hecks 2.8.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 (886) hide show
  1. checksums.yaml +4 -4
  2. data/exe/hecks +50 -7
  3. data/lib/hecks/adapters/driven/claude_code.rb +4 -104
  4. data/lib/hecks/adapters/driven/d1.rb +44 -237
  5. data/lib/hecks/adapters/driven/folder.rb +17 -76
  6. data/lib/hecks/adapters/driven/google_authentication.rb +15 -49
  7. data/lib/hecks/adapters/driven/governance_authorization.rb +23 -70
  8. data/lib/hecks/adapters/driven/heki/journal.rb +8 -41
  9. data/lib/hecks/adapters/driven/heki/saga_store.rb +12 -54
  10. data/lib/hecks/adapters/driven/heki/snapshot.rb +4 -12
  11. data/lib/hecks/adapters/driven/heki.rb +13 -42
  12. data/lib/hecks/adapters/driven/identity_registry.rb +3 -14
  13. data/lib/hecks/adapters/driven/in_memory_ordering.rb +9 -26
  14. data/lib/hecks/adapters/driven/in_process_key_vault.rb +2 -14
  15. data/lib/hecks/adapters/driven/lambda/client.rb +10 -51
  16. data/lib/hecks/adapters/driven/lambda.rb +10 -84
  17. data/lib/hecks/adapters/driven/local_storage.rb +5 -40
  18. data/lib/hecks/adapters/driven/memory.rb +32 -100
  19. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +5 -21
  20. data/lib/hecks/adapters/driven/postgres/codec.rb +6 -28
  21. data/lib/hecks/adapters/driven/postgres/outbox.rb +3 -12
  22. data/lib/hecks/adapters/driven/postgres/reconnect.rb +10 -32
  23. data/lib/hecks/adapters/driven/postgres/schema_builder.rb +34 -108
  24. data/lib/hecks/adapters/driven/postgres/shared_connection.rb +180 -0
  25. data/lib/hecks/adapters/driven/postgres.rb +149 -136
  26. data/lib/hecks/adapters/driven/postgres_era.adapter +4 -15
  27. data/lib/hecks/adapters/driven/prism.rb +48 -38
  28. data/lib/hecks/adapters/driven/sql_query_builder.rb +21 -121
  29. data/lib/hecks/adapters/driven/sqlite/codec.rb +8 -40
  30. data/lib/hecks/adapters/driven/sqlite/projection.rb +26 -82
  31. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +40 -84
  32. data/lib/hecks/adapters/driven/sqlite.rb +128 -65
  33. data/lib/hecks/adapters/driven/tenant_provisioner.rb +76 -62
  34. data/lib/hecks/adapters/driven.rb +5 -36
  35. data/lib/hecks/adapters/driving/github_webhook.rb +8 -76
  36. data/lib/hecks/behaviors/dsl.rb +7 -25
  37. data/lib/hecks/behaviors/expectations.rb +32 -142
  38. data/lib/hecks/behaviors/ir.rb +7 -20
  39. data/lib/hecks/behaviors/rspec.rb +6 -17
  40. data/lib/hecks/behaviors/runner.rb +10 -34
  41. data/lib/hecks/behaviors.rb +4 -8
  42. data/lib/hecks/bench/cli.rb +62 -0
  43. data/lib/hecks/bench/environment.rb +71 -0
  44. data/lib/hecks/bench/postgres_probe.rb +30 -0
  45. data/lib/hecks/bench/report.rb +76 -0
  46. data/lib/hecks/bench/ruby_runner.rb +93 -0
  47. data/lib/hecks/bench/run.rb +55 -0
  48. data/lib/hecks/bench/rust_runner.rb +101 -0
  49. data/lib/hecks/bench/stats.rb +46 -0
  50. data/lib/hecks/bench/suite.rb +98 -0
  51. data/lib/hecks/bench/workload.rb +89 -0
  52. data/lib/hecks/bench.rb +17 -0
  53. data/lib/hecks/bluebook/aggregate.rb +9 -75
  54. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +9 -38
  55. data/lib/hecks/bluebook/assembly/build.rb +4 -15
  56. data/lib/hecks/bluebook/assembly/contract.rb +15 -136
  57. data/lib/hecks/bluebook/assembly/contracts.rb +56 -174
  58. data/lib/hecks/bluebook/assembly/marks.rb +31 -223
  59. data/lib/hecks/bluebook/assembly/specializer.rb +6 -52
  60. data/lib/hecks/bluebook/assembly.rb +6 -45
  61. data/lib/hecks/bluebook/attribute.rb +12 -61
  62. data/lib/hecks/bluebook/behaviour/aggregate.rb +39 -39
  63. data/lib/hecks/bluebook/behaviour/attribute.rb +3 -14
  64. data/lib/hecks/bluebook/behaviour/chapter.rb +14 -42
  65. data/lib/hecks/bluebook/behaviour/command.rb +14 -66
  66. data/lib/hecks/bluebook/behaviour/domain_port.rb +11 -20
  67. data/lib/hecks/bluebook/behaviour/entity.rb +7 -27
  68. data/lib/hecks/bluebook/behaviour/hexagon.rb +23 -41
  69. data/lib/hecks/bluebook/behaviour/lifecycle.rb +15 -40
  70. data/lib/hecks/bluebook/behaviour/policy.rb +23 -52
  71. data/lib/hecks/bluebook/behaviour/process_manager.rb +30 -57
  72. data/lib/hecks/bluebook/behaviour/read_model.rb +25 -31
  73. data/lib/hecks/bluebook/behaviour/traits.rb +27 -64
  74. data/lib/hecks/bluebook/behaviour/value_object.rb +5 -24
  75. data/lib/hecks/bluebook/capabilities.rb +17 -49
  76. data/lib/hecks/bluebook/chapter.rb +16 -50
  77. data/lib/hecks/bluebook/command.rb +23 -81
  78. data/lib/hecks/bluebook/domain_port.rb +49 -67
  79. data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +50 -229
  80. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +50 -377
  81. data/lib/hecks/bluebook/dsl/attribute_collector.rb +33 -204
  82. data/lib/hecks/bluebook/dsl/binding_proxy.rb +16 -69
  83. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +96 -708
  84. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +63 -169
  85. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +3 -1
  86. data/lib/hecks/bluebook/dsl/command_builder.rb +74 -546
  87. data/lib/hecks/bluebook/dsl/const_shim.rb +8 -41
  88. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +42 -89
  89. data/lib/hecks/bluebook/dsl/entity_builder.rb +44 -330
  90. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +20 -269
  91. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +148 -197
  92. data/lib/hecks/bluebook/dsl/identity_declaration.rb +13 -88
  93. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +6 -20
  94. data/lib/hecks/bluebook/dsl/policy_builder.rb +16 -88
  95. data/lib/hecks/bluebook/dsl/port_builder.rb +2 -6
  96. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +22 -96
  97. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +31 -184
  98. data/lib/hecks/bluebook/dsl/query_builder.rb +38 -43
  99. data/lib/hecks/bluebook/dsl/read_model_builder.rb +75 -201
  100. data/lib/hecks/bluebook/dsl/rule_reference.rb +22 -163
  101. data/lib/hecks/bluebook/dsl/translation_builder.rb +28 -114
  102. data/lib/hecks/bluebook/dsl/value_object_builder.rb +10 -124
  103. data/lib/hecks/bluebook/dsl/word_gate.rb +16 -162
  104. data/lib/hecks/bluebook/dsl/world_builder.rb +46 -111
  105. data/lib/hecks/bluebook/entity.rb +13 -71
  106. data/lib/hecks/bluebook/expression/ast_json.rb +24 -190
  107. data/lib/hecks/bluebook/expression/ast_reader.rb +12 -54
  108. data/lib/hecks/bluebook/expression/canonical_form.rb +11 -88
  109. data/lib/hecks/bluebook/expression/evaluator.rb +47 -295
  110. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +30 -147
  111. data/lib/hecks/bluebook/expression/resolver.rb +39 -661
  112. data/lib/hecks/bluebook/hexagon.rb +18 -33
  113. data/lib/hecks/bluebook/lifecycle.rb +5 -16
  114. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -7
  115. data/lib/hecks/bluebook/meta_validator/judge.rb +111 -361
  116. data/lib/hecks/bluebook/meta_validator/plan.rb +33 -162
  117. data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -7
  118. data/lib/hecks/bluebook/meta_validator/readings.rb +56 -342
  119. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +25 -176
  120. data/lib/hecks/bluebook/meta_validator/shapes.rb +53 -267
  121. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +47 -306
  122. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +7 -43
  123. data/lib/hecks/bluebook/meta_validator/verdict_cache.rb +246 -0
  124. data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -18
  125. data/lib/hecks/bluebook/meta_validator.rb +87 -352
  126. data/lib/hecks/bluebook/model_check/client_profile.rb +6 -21
  127. data/lib/hecks/bluebook/model_check.rb +122 -596
  128. data/lib/hecks/bluebook/pattern_subset.rb +49 -69
  129. data/lib/hecks/bluebook/process_manager.rb +13 -83
  130. data/lib/hecks/bluebook/project_loader.rb +3 -39
  131. data/lib/hecks/bluebook/project_register.rb +12 -60
  132. data/lib/hecks/bluebook/query.rb +27 -51
  133. data/lib/hecks/bluebook/read_model.rb +57 -81
  134. data/lib/hecks/bluebook/reference.rb +7 -41
  135. data/lib/hecks/bluebook/smoke_test.rb +9 -99
  136. data/lib/hecks/bluebook/synthesizer.rb +13 -62
  137. data/lib/hecks/bluebook/translation.rb +26 -62
  138. data/lib/hecks/bluebook/value_object.rb +11 -36
  139. data/lib/hecks/bluebook.rb +5 -22
  140. data/lib/hecks/cache_dir.rb +4 -23
  141. data/lib/hecks/canonical_json.rb +30 -0
  142. data/lib/hecks/chapters.rb +102 -0
  143. data/lib/hecks/cli/behaviors.rb +61 -0
  144. data/lib/hecks/cli/canonicalise.rb +25 -0
  145. data/lib/hecks/cli/check_engine_agreement.rb +32 -0
  146. data/lib/hecks/cli/check_era.rb +88 -0
  147. data/lib/hecks/cli/console.rb +66 -0
  148. data/lib/hecks/cli/deploy_template_diff.rb +40 -0
  149. data/lib/hecks/cli/doc_coverage.rb +32 -0
  150. data/lib/hecks/cli/document.rb +5 -23
  151. data/lib/hecks/cli/expression_projection.rb +41 -0
  152. data/lib/hecks/cli/follow.rb +88 -0
  153. data/lib/hecks/cli/history.rb +44 -0
  154. data/lib/hecks/cli/ir.rb +4 -6
  155. data/lib/hecks/cli/mcp.rb +5 -6
  156. data/lib/hecks/cli/model_check.rb +24 -88
  157. data/lib/hecks/cli/pattern_cases.rb +47 -0
  158. data/lib/hecks/cli/present.rb +39 -0
  159. data/lib/hecks/cli/project_cli.rb +223 -64
  160. data/lib/hecks/cli/project_diagrams.rb +4 -10
  161. data/lib/hecks/cli/project_glossary.rb +44 -0
  162. data/lib/hecks/cli/reference.rb +46 -0
  163. data/lib/hecks/cli/refresh_projections.rb +44 -0
  164. data/lib/hecks/cli/refresh_rspec_runtime_baseline.rb +150 -0
  165. data/lib/hecks/cli/release.rb +70 -0
  166. data/lib/hecks/cli/release_gem.rb +59 -0
  167. data/lib/hecks/cli/rspec_io_parallel_files.rb +137 -0
  168. data/lib/hecks/cli/rspec_shard_files.rb +66 -0
  169. data/lib/hecks/cli/run.rb +15 -61
  170. data/lib/hecks/cli/seed_semantics_corpus.rb +71 -0
  171. data/lib/hecks/cli/serve_query_ir_mcp.rb +30 -0
  172. data/lib/hecks/cli/shape.rb +70 -0
  173. data/lib/hecks/cli/smoke_http.rb +230 -0
  174. data/lib/hecks/cli/smoke_test.rb +7 -19
  175. data/lib/hecks/cli/spec_example.rb +27 -0
  176. data/lib/hecks/cli/statements.rb +32 -0
  177. data/lib/hecks/cli/stores.rb +4 -6
  178. data/lib/hecks/cli/stress_concurrency_specs.rb +177 -0
  179. data/lib/hecks/cli.rb +216 -73
  180. data/lib/hecks/codemod.rb +324 -0
  181. data/lib/hecks/construct.rb +8 -34
  182. data/lib/hecks/corpus.rb +423 -0
  183. data/lib/hecks/deploy/bluebook/deploy.bluebook +617 -158
  184. data/lib/hecks/deploy/bluebook/deploy.hecksagon +41 -11
  185. data/lib/hecks/deploy/oidc.json +82 -2
  186. data/lib/hecks/doc/reference.rb +351 -0
  187. data/lib/hecks/doors/cli_door.rb +196 -0
  188. data/lib/hecks/doors/cli_runner.rb +297 -0
  189. data/lib/hecks/{facade → doors}/command_request.rb +14 -34
  190. data/lib/hecks/doors/handle.rb +206 -0
  191. data/lib/hecks/doors/json_door.rb +132 -0
  192. data/lib/hecks/doors/launcher_options.rb +129 -0
  193. data/lib/hecks/{cli → doors}/mcp_door.rb +25 -120
  194. data/lib/hecks/doors/mcp_door_scope.rb +97 -0
  195. data/lib/hecks/doors/ruby_door/aggregate_door.rb +162 -0
  196. data/lib/hecks/doors/ruby_door/chapter.rb +72 -0
  197. data/lib/hecks/doors/ruby_door.rb +77 -0
  198. data/lib/hecks/doors.rb +61 -0
  199. data/lib/hecks/embryonaut_bluebook/lock.rb +3 -35
  200. data/lib/hecks/embryonaut_bluebook/shape.rb +1 -17
  201. data/lib/hecks/embryonaut_bluebook/vendor.rb +8 -53
  202. data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +4 -19
  203. data/lib/hecks/embryonaut_bluebook.rb +5 -72
  204. data/lib/hecks/engine_agreement.rb +156 -0
  205. data/lib/hecks/facade.rb +23 -51
  206. data/lib/hecks/forms/app.rb +21 -76
  207. data/lib/hecks/forms/banking_presentation.rb +50 -0
  208. data/lib/hecks/forms/command_form_renderer.rb +10 -29
  209. data/lib/hecks/forms/field_renderer.rb +17 -156
  210. data/lib/hecks/forms/field_shape.rb +31 -222
  211. data/lib/hecks/forms/html.rb +12 -47
  212. data/lib/hecks/forms/index_renderer.rb +1 -4
  213. data/lib/hecks/forms/page.rb +3 -9
  214. data/lib/hecks/forms/params.rb +14 -60
  215. data/lib/hecks/forms/port_argument.rb +2 -19
  216. data/lib/hecks/forms/query_form_renderer.rb +4 -79
  217. data/lib/hecks/forms/record_renderer.rb +8 -75
  218. data/lib/hecks/forms/record_table.rb +7 -50
  219. data/lib/hecks/forms/reference_options.rb +3 -30
  220. data/lib/hecks/forms/value_object_shape.rb +8 -35
  221. data/lib/hecks/forms.rb +5 -33
  222. data/lib/hecks/fqn.rb +5 -12
  223. data/lib/hecks/framework/bluebook/compliance.bluebook +16 -65
  224. data/lib/hecks/framework/bluebook/console_settings.bluebook +47 -134
  225. data/lib/hecks/framework/bluebook/framework.hecksagon +5 -14
  226. data/lib/hecks/framework/bluebook/governance.bluebook +13 -34
  227. data/lib/hecks/framework/bluebook/identity.bluebook +11 -26
  228. data/lib/hecks/framework/bluebook/privacy.bluebook +8 -33
  229. data/lib/hecks/framework.rb +11 -80
  230. data/lib/hecks/freezer.rb +5 -39
  231. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +393 -0
  232. data/lib/hecks/fuzzing/combination_miner.rb +86 -0
  233. data/lib/hecks/fuzzing/concurrent_dispatch.rb +214 -0
  234. data/lib/hecks/fuzzing/coverage_campaign.rb +143 -0
  235. data/lib/hecks/fuzzing/differential.rb +156 -0
  236. data/lib/hecks/fuzzing/domain_generator.rb +615 -0
  237. data/lib/hecks/fuzzing/era_boundary.rb +71 -0
  238. data/lib/hecks/fuzzing/form_census.rb +136 -0
  239. data/lib/hecks/fuzzing/generated_domain_check.rb +93 -0
  240. data/lib/hecks/fuzzing/invalid_value_generator.rb +64 -0
  241. data/lib/hecks/fuzzing/isolated_boot.rb +301 -0
  242. data/lib/hecks/fuzzing/nondeterministic.rb +51 -0
  243. data/lib/hecks/fuzzing/outside_world.rb +45 -0
  244. data/lib/hecks/fuzzing/persistence_parity.rb +102 -0
  245. data/lib/hecks/fuzzing/properties/corrections.rb +88 -0
  246. data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +314 -0
  247. data/lib/hecks/fuzzing/properties/guards.rb +190 -0
  248. data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +300 -0
  249. data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +93 -0
  250. data/lib/hecks/fuzzing/properties/outbox.rb +89 -0
  251. data/lib/hecks/fuzzing/properties/querying.rb +175 -0
  252. data/lib/hecks/fuzzing/properties.rb +162 -0
  253. data/lib/hecks/fuzzing/qa_settings.rb +123 -0
  254. data/lib/hecks/fuzzing/replay.rb +505 -0
  255. data/lib/hecks/fuzzing/rotation_priority.rb +48 -0
  256. data/lib/hecks/fuzzing/rust_gap_manifest.rb +108 -0
  257. data/lib/hecks/fuzzing/self_consistency.rb +339 -0
  258. data/lib/hecks/fuzzing/sequence_generator/adversary.rb +385 -0
  259. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +132 -0
  260. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +95 -0
  261. data/lib/hecks/fuzzing/sequence_generator/picker.rb +77 -0
  262. data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +109 -0
  263. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +237 -0
  264. data/lib/hecks/fuzzing/sequence_generator.rb +189 -0
  265. data/lib/hecks/fuzzing/shrinker.rb +166 -0
  266. data/lib/hecks/fuzzing/structural_skips.rb +33 -0
  267. data/lib/hecks/fuzzing/sweep_depth.rb +43 -0
  268. data/lib/hecks/fuzzing/target_capabilities.rb +163 -0
  269. data/lib/hecks/fuzzing/value_generator.rb +216 -0
  270. data/lib/hecks/fuzzing.rb +23 -0
  271. data/lib/hecks/grammar/evolve.rb +336 -0
  272. data/lib/hecks/grammar/expression.bluebook +15 -40
  273. data/lib/hecks/grammar/translation.bluebook +3 -6
  274. data/lib/hecks/grammar.rb +16 -41
  275. data/lib/hecks/hecks/adapters/codebase/codemods.rb +45 -0
  276. data/lib/hecks/hecks/adapters/codebase/conformance.rb +71 -0
  277. data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +202 -0
  278. data/lib/hecks/hecks/adapters/codebase/gem_registry.rb +80 -0
  279. data/lib/hecks/hecks/adapters/codebase/kernel_tables.rb +54 -0
  280. data/lib/hecks/hecks/adapters/codebase/language.rb +240 -0
  281. data/lib/hecks/hecks/adapters/codebase/npm_registry.rb +102 -0
  282. data/lib/hecks/hecks/adapters/codebase/publishing.rb +142 -0
  283. data/lib/hecks/hecks/adapters/codebase/regeneration.rb +67 -0
  284. data/lib/hecks/hecks/adapters/codebase/release_facts.rb +90 -0
  285. data/lib/hecks/hecks/adapters/codebase/ruby_child.rb +83 -0
  286. data/lib/hecks/hecks/adapters/codebase/secret_vault.rb +36 -0
  287. data/lib/hecks/hecks/adapters/codebase/source_tree.adapter +7 -0
  288. data/lib/hecks/hecks/adapters/codebase/source_tree.rb +189 -0
  289. data/lib/hecks/hecks/adapters/codebase/sqlite_fixture.rb +71 -0
  290. data/lib/hecks/hecks/adapters/codebase/style.rb +171 -0
  291. data/lib/hecks/hecks/adapters/codebase/test_runner.rb +55 -0
  292. data/lib/hecks/hecks/adapters/codebase/test_suite.rb +165 -0
  293. data/lib/hecks/hecks/adapters/codebase/tree.rb +111 -0
  294. data/lib/hecks/hecks/adapters/console_capture.rb +79 -0
  295. data/lib/hecks/hecks/adapters/deploy_toolchain.adapter +7 -0
  296. data/lib/hecks/hecks/adapters/deploy_toolchain.rb +108 -0
  297. data/lib/hecks/hecks/adapters/git.adapter +7 -0
  298. data/lib/hecks/hecks/adapters/git.rb +102 -0
  299. data/lib/hecks/hecks/adapters/host_http.adapter +7 -0
  300. data/lib/hecks/hecks/adapters/host_http.rb +65 -0
  301. data/lib/hecks/hecks/adapters/in_process_boot.adapter +7 -0
  302. data/lib/hecks/hecks/adapters/in_process_boot.rb +197 -0
  303. data/lib/hecks/hecks/adapters/in_process_operations.rb +202 -0
  304. data/lib/hecks/hecks/adapters/journal_store/changes.rb +143 -0
  305. data/lib/hecks/hecks/adapters/journal_store/compaction.rb +145 -0
  306. data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +132 -0
  307. data/lib/hecks/hecks/adapters/journal_store/examination.rb +135 -0
  308. data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +163 -0
  309. data/lib/hecks/hecks/adapters/journal_store/readings.rb +187 -0
  310. data/lib/hecks/hecks/adapters/journal_store.adapter +7 -0
  311. data/lib/hecks/hecks/adapters/journal_store.rb +64 -0
  312. data/lib/hecks/hecks/adapters/local_files.adapter +7 -0
  313. data/lib/hecks/hecks/adapters/local_files.rb +46 -0
  314. data/lib/hecks/hecks/adapters/pg_admin.adapter +7 -0
  315. data/lib/hecks/hecks/adapters/pg_admin.rb +245 -0
  316. data/lib/hecks/hecks/adapters/process_pool.adapter +7 -0
  317. data/lib/hecks/hecks/adapters/process_pool.rb +119 -0
  318. data/lib/hecks/hecks/adapters/rust_toolchain.adapter +7 -0
  319. data/lib/hecks/hecks/adapters/rust_toolchain.rb +179 -0
  320. data/lib/hecks/hecks/adapters/rust_workspace.rb +150 -0
  321. data/lib/hecks/hecks/adapters/shell.adapter +7 -0
  322. data/lib/hecks/hecks/adapters/shell.rb +49 -0
  323. data/lib/hecks/hecks/adapters/terminal.adapter +7 -0
  324. data/lib/hecks/hecks/adapters/terminal.rb +74 -0
  325. data/lib/hecks/hecks/codebase.behaviors +172 -0
  326. data/lib/hecks/hecks/codebase.bluebook +2453 -0
  327. data/lib/hecks/hecks/context_map.hecksagon +13 -0
  328. data/lib/hecks/hecks/custodian.behaviors +179 -0
  329. data/lib/hecks/hecks/custodian.bluebook +1847 -0
  330. data/lib/hecks/hecks/deploy.behaviors +74 -0
  331. data/lib/hecks/hecks/deploy.world +12 -0
  332. data/lib/hecks/hecks/environments/memory.world +10 -0
  333. data/lib/hecks/hecks/governance.world +7 -0
  334. data/lib/hecks/hecks/hecks.behaviors +62 -0
  335. data/lib/hecks/hecks/hecks.bluebook +124 -0
  336. data/lib/hecks/hecks/hecks.hecksagon +390 -0
  337. data/lib/hecks/hecks/hecks.world +42 -0
  338. data/lib/hecks/ir.rb +14 -83
  339. data/lib/hecks/kernel_capabilities.rb +194 -0
  340. data/lib/hecks/language/adapter.bluebook +2 -7
  341. data/lib/hecks/language/bluebook/aggregate.bluebook +56 -221
  342. data/lib/hecks/language/bluebook/attaches/paging.bluebook +6 -15
  343. data/lib/hecks/language/bluebook/bluebook.bluebook +26 -83
  344. data/lib/hecks/language/bluebook/bluebook.hecksagon +3 -15
  345. data/lib/hecks/language/bluebook/command.bluebook +27 -144
  346. data/lib/hecks/language/bluebook/entity.bluebook +24 -97
  347. data/lib/hecks/language/bluebook/policy.bluebook +16 -67
  348. data/lib/hecks/language/bluebook/process_manager.bluebook +28 -151
  349. data/lib/hecks/language/bluebook/projection.bluebook +126 -60
  350. data/lib/hecks/language/bluebook/query.bluebook +19 -43
  351. data/lib/hecks/language/bluebook/shape.bluebook +23 -73
  352. data/lib/hecks/language/bluebook/syntax.bluebook +51 -262
  353. data/lib/hecks/language/bluebook/vocabulary.bluebook +83 -198
  354. data/lib/hecks/language/hecksagon/adapter_binding.bluebook +3 -10
  355. data/lib/hecks/language/hecksagon/domain_port.bluebook +14 -19
  356. data/lib/hecks/language/hecksagon/hecksagon.bluebook +26 -25
  357. data/lib/hecks/language/hecksagon/port_operation.bluebook +3 -14
  358. data/lib/hecks/language/oidc.json +35 -0
  359. data/lib/hecks/language/port.bluebook +4 -17
  360. data/lib/hecks/language/translation/translation.bluebook +3 -9
  361. data/lib/hecks/language/translation/translation_aggregate.bluebook +5 -24
  362. data/lib/hecks/language/world/wiring.bluebook +1 -3
  363. data/lib/hecks/language/world/world.bluebook +5 -7
  364. data/lib/hecks/literal.rb +8 -50
  365. data/lib/hecks/mcp_stdio_guard.rb +4 -41
  366. data/lib/hecks/naming.rb +29 -137
  367. data/lib/hecks/persistence_legacy_fixture/regenerate.rb +161 -0
  368. data/lib/hecks/persistence_legacy_fixture.rb +113 -0
  369. data/lib/hecks/ports/access_control.rb +7 -23
  370. data/lib/hecks/ports/agent/answers.rb +5 -23
  371. data/lib/hecks/ports/agent.rb +47 -172
  372. data/lib/hecks/ports/authentication.rb +12 -39
  373. data/lib/hecks/ports/authorization.rb +16 -43
  374. data/lib/hecks/ports/clock.rb +5 -45
  375. data/lib/hecks/ports/extraction.rb +7 -12
  376. data/lib/hecks/ports/identity_assignment.rb +8 -29
  377. data/lib/hecks/ports/identity_generation.rb +6 -29
  378. data/lib/hecks/ports/identity_resolution.rb +2 -10
  379. data/lib/hecks/ports/key_vault.rb +9 -45
  380. data/lib/hecks/ports/persistence/append_only.rb +61 -64
  381. data/lib/hecks/ports/persistence/binding_policy.rb +4 -14
  382. data/lib/hecks/ports/persistence/codec_boundary.rb +20 -80
  383. data/lib/hecks/ports/persistence/null_saga_store.rb +4 -20
  384. data/lib/hecks/ports/persistence/plugin.rb +13 -42
  385. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +44 -144
  386. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +15 -115
  387. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +20 -85
  388. data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +6 -25
  389. data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +18 -24
  390. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +55 -181
  391. data/lib/hecks/ports/persistence/plugins/era/postgres_era/events.rb +77 -0
  392. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +12 -122
  393. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +28 -128
  394. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +73 -474
  395. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +31 -124
  396. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +45 -219
  397. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +13 -108
  398. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +19 -76
  399. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +9 -49
  400. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +6 -123
  401. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +23 -55
  402. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +14 -72
  403. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +7 -16
  404. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +43 -127
  405. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +13 -45
  406. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +131 -555
  407. data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +13 -63
  408. data/lib/hecks/ports/persistence/plugins/era/translation/approval_file.rb +227 -0
  409. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +2 -17
  410. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +3 -14
  411. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +13 -58
  412. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -17
  413. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +9 -26
  414. data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +50 -47
  415. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +18 -124
  416. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +34 -123
  417. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +5 -12
  418. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +3 -9
  419. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -14
  420. data/lib/hecks/ports/persistence/plugins/era/translation.rb +1 -0
  421. data/lib/hecks/ports/persistence/plugins/era.rb +4 -23
  422. data/lib/hecks/ports/persistence/postgres_dump/connection.rb +7 -23
  423. data/lib/hecks/ports/persistence/postgres_dump.rb +4 -35
  424. data/lib/hecks/ports/persistence/remote_runtime.rb +2 -24
  425. data/lib/hecks/ports/persistence/repository_factory.rb +8 -27
  426. data/lib/hecks/ports/persistence/state_codec.rb +47 -108
  427. data/lib/hecks/ports/persistence.rb +7 -14
  428. data/lib/hecks/ports/projection.rb +42 -84
  429. data/lib/hecks/ports/query/in_memory.rb +10 -58
  430. data/lib/hecks/ports/query/ordering.rb +11 -32
  431. data/lib/hecks/ports/query.rb +14 -37
  432. data/lib/hecks/ports.rb +2 -8
  433. data/lib/hecks/projection_files.rb +285 -0
  434. data/lib/hecks/projections/bootstrap_table.rb +12 -44
  435. data/lib/hecks/projections/deploy/fargate/assembly.rb +2 -15
  436. data/lib/hecks/projections/deploy/fargate/cdn.rb +1 -48
  437. data/lib/hecks/projections/deploy/fargate/cdn_default.rb +2 -11
  438. data/lib/hecks/projections/deploy/fargate/check.rb +5 -14
  439. data/lib/hecks/projections/deploy/fargate/containers.rb +3 -78
  440. data/lib/hecks/projections/deploy/fargate/extras.rb +3 -44
  441. data/lib/hecks/projections/deploy/fargate/monitoring.rb +0 -44
  442. data/lib/hecks/projections/deploy/fargate/settings.rb +2 -54
  443. data/lib/hecks/projections/deploy/fargate/yaml.rb +13 -58
  444. data/lib/hecks/projections/deploy/fargate.rb +40 -207
  445. data/lib/hecks/projections/deploy/lambda.rb +191 -708
  446. data/lib/hecks/projections/deploy/preview/access_yaml.rb +1 -33
  447. data/lib/hecks/projections/deploy/preview/containers.rb +6 -111
  448. data/lib/hecks/projections/deploy/preview/preview.sh.erb +1 -1
  449. data/lib/hecks/projections/deploy/preview/routing_yaml.rb +4 -56
  450. data/lib/hecks/projections/deploy/preview/script.rb +2 -14
  451. data/lib/hecks/projections/deploy/preview/settings.rb +3 -33
  452. data/lib/hecks/projections/deploy/preview/task_yaml.rb +2 -38
  453. data/lib/hecks/projections/deploy/preview/template.rb +3 -59
  454. data/lib/hecks/projections/deploy/preview.rb +2 -67
  455. data/lib/hecks/projections/deploy/scripts/deploy-service.sh.tmpl +1 -1
  456. data/lib/hecks/projections/deploy/scripts/expected-era.header +1 -1
  457. data/lib/hecks/projections/deploy/scripts/hosting.mk.tmpl +3 -3
  458. data/lib/hecks/projections/deploy/scripts/settings.rb +3 -25
  459. data/lib/hecks/projections/deploy/scripts/smoke-after-deploy.sh.tmpl +1 -1
  460. data/lib/hecks/projections/deploy/scripts.rb +4 -57
  461. data/lib/hecks/projections/deploy/shared.rb +48 -147
  462. data/lib/hecks/projections/deploy/smoke.rb +4 -61
  463. data/lib/hecks/projections/deploy/template_diff/comparer.rb +3 -25
  464. data/lib/hecks/projections/deploy/template_diff/loader.rb +2 -11
  465. data/lib/hecks/projections/deploy/template_diff.rb +5 -57
  466. data/lib/hecks/projections/diagrams.rb +22 -584
  467. data/lib/hecks/projections/glossary/html.rb +14 -130
  468. data/lib/hecks/projections/glossary/markdown.rb +8 -69
  469. data/lib/hecks/projections/glossary/mermaid.rb +9 -66
  470. data/lib/hecks/projections/glossary/sensitivity.rb +5 -34
  471. data/lib/hecks/projections/glossary/sentences.rb +14 -159
  472. data/lib/hecks/projections/glossary.rb +30 -222
  473. data/lib/hecks/projections/ir.rb +3 -10
  474. data/lib/hecks/projections/model/deviations.rb +16 -43
  475. data/lib/hecks/projections/model.rb +12 -51
  476. data/lib/hecks/projections/oidc.rb +12 -56
  477. data/lib/hecks/projections/parser_table.rb +13 -32
  478. data/lib/hecks/projections/reference.rb +4 -18
  479. data/lib/hecks/projections/rust_vocabulary.rb +13 -251
  480. data/lib/hecks/projections/shape.rb +3 -29
  481. data/lib/hecks/projections/statements.rb +7 -86
  482. data/lib/hecks/projections/vocabulary.rb +6 -22
  483. data/lib/hecks/projections.rb +2 -16
  484. data/lib/hecks/projector/cli_projector.rb +154 -400
  485. data/lib/hecks/projector/docs_projector.rb +10 -201
  486. data/lib/hecks/projector/exporter.rb +42 -134
  487. data/lib/hecks/projector/ir_projector.rb +2 -9
  488. data/lib/hecks/projector/narrate_projector.rb +15 -189
  489. data/lib/hecks/projector/target.rb +13 -76
  490. data/lib/hecks/projector.rb +30 -121
  491. data/lib/hecks/quality_control/adapters/agent.adapter +7 -0
  492. data/lib/hecks/quality_control/adapters/agent.rb +58 -0
  493. data/lib/hecks/quality_control/adapters/angle_tools.adapter +7 -0
  494. data/lib/hecks/quality_control/adapters/angle_tools.rb +15 -0
  495. data/lib/hecks/quality_control/adapters/clearance_recorder.rb +36 -0
  496. data/lib/hecks/quality_control/adapters/clearance_tools.adapter +7 -0
  497. data/lib/hecks/quality_control/adapters/clearance_tools.rb +17 -0
  498. data/lib/hecks/quality_control/adapters/git_pr.adapter +7 -0
  499. data/lib/hecks/quality_control/adapters/git_pr.rb +226 -0
  500. data/lib/hecks/quality_control/adapters/github_checks.adapter +9 -0
  501. data/lib/hecks/quality_control/adapters/github_checks.rb +83 -0
  502. data/lib/hecks/quality_control/adapters/github_ci_webhook.rb +56 -0
  503. data/lib/hecks/quality_control/adapters/github_issues.adapter +7 -0
  504. data/lib/hecks/quality_control/adapters/github_issues.rb +49 -0
  505. data/lib/hecks/quality_control/adapters/qa_tool.rb +59 -0
  506. data/lib/hecks/quality_control/adapters/sweep_tools.adapter +7 -0
  507. data/lib/hecks/quality_control/adapters/sweep_tools.rb +51 -0
  508. data/lib/hecks/quality_control/adapters/target_tools.adapter +7 -0
  509. data/lib/hecks/quality_control/adapters/target_tools.rb +43 -0
  510. data/lib/hecks/quality_control/cli/child.rb +45 -0
  511. data/lib/hecks/quality_control/cli/qa_concurrency_racer.rb +45 -0
  512. data/lib/hecks/quality_control/cli/qa_discover_external_domains.rb +248 -0
  513. data/lib/hecks/quality_control/cli/qa_domain_novelty.rb +163 -0
  514. data/lib/hecks/quality_control/cli/qa_generated_domains.rb +450 -0
  515. data/lib/hecks/quality_control/cli/qa_log_bug.rb +195 -0
  516. data/lib/hecks/quality_control/cli/qa_mine_combinations.rb +220 -0
  517. data/lib/hecks/quality_control/cli/qa_open_pr.rb +305 -0
  518. data/lib/hecks/quality_control/cli/qa_postgres_migrate.rb +154 -0
  519. data/lib/hecks/quality_control/cli/qa_postgres_role.rb +159 -0
  520. data/lib/hecks/quality_control/cli/qa_pr_check.rb +232 -0
  521. data/lib/hecks/quality_control/cli/qa_seed_angles.rb +142 -0
  522. data/lib/hecks/quality_control/cli/qa_seed_targets.rb +69 -0
  523. data/lib/hecks/quality_control/cli/qa_sweep/all_mode.rb +280 -0
  524. data/lib/hecks/quality_control/cli/qa_sweep/checks.rb +329 -0
  525. data/lib/hecks/quality_control/cli/qa_sweep/dials.rb +92 -0
  526. data/lib/hecks/quality_control/cli/qa_sweep/finding_report.rb +117 -0
  527. data/lib/hecks/quality_control/cli/qa_sweep/parsing.rb +175 -0
  528. data/lib/hecks/quality_control/cli/qa_sweep/release_mode.rb +60 -0
  529. data/lib/hecks/quality_control/cli/qa_sweep.rb +611 -0
  530. data/lib/hecks/quality_control/cli/qa_tick.rb +274 -0
  531. data/lib/hecks/quality_control/quality_control.bluebook +2224 -0
  532. data/lib/hecks/quality_control/quality_control.hecksagon +13 -0
  533. data/lib/hecks/quality_control/quality_control.ports.hecksagon +54 -0
  534. data/lib/hecks/query_ir.rb +346 -0
  535. data/lib/hecks/query_ir_mcp.rb +198 -0
  536. data/lib/hecks/query_specification/common/comparators.rb +5 -26
  537. data/lib/hecks/query_specification/common/comparison.rb +35 -143
  538. data/lib/hecks/query_specification/common/dsl.rb +8 -24
  539. data/lib/hecks/query_specification/common/null_policy.rb +20 -70
  540. data/lib/hecks/query_specification/common/options.rb +2 -6
  541. data/lib/hecks/query_specification/common/where_clause.rb +2 -10
  542. data/lib/hecks/query_specification/field_path.rb +37 -77
  543. data/lib/hecks/query_specification/hop_path.rb +12 -76
  544. data/lib/hecks/release/gem_pin.rb +2 -26
  545. data/lib/hecks/release/runner/ci_publisher.rb +5 -8
  546. data/lib/hecks/release/runner/clean_tree.rb +42 -0
  547. data/lib/hecks/release/runner/commands.rb +2 -4
  548. data/lib/hecks/release/runner/console.rb +6 -0
  549. data/lib/hecks/release/runner/gem_publisher.rb +15 -9
  550. data/lib/hecks/release/runner/npm_publisher.rb +9 -53
  551. data/lib/hecks/release/runner/preflight.rb +29 -20
  552. data/lib/hecks/release/runner/published.rb +8 -26
  553. data/lib/hecks/release/runner/tagger.rb +31 -23
  554. data/lib/hecks/release/runner.rb +60 -38
  555. data/lib/hecks/rendering.rb +4 -26
  556. data/lib/hecks/router/namespace_installer.rb +15 -39
  557. data/lib/hecks/router.rb +4 -8
  558. data/lib/hecks/runtime/adapter_lookup.rb +124 -0
  559. data/lib/hecks/runtime/aggregate_lock.rb +8 -33
  560. data/lib/hecks/runtime/boot_gates.rb +3 -18
  561. data/lib/hecks/runtime/caller.rb +19 -59
  562. data/lib/hecks/runtime/capability_graph.rb +5 -21
  563. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +16 -78
  564. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +27 -160
  565. data/lib/hecks/runtime/command_interpreter.rb +124 -306
  566. data/lib/hecks/runtime/command_rules/admissibility.rb +95 -366
  567. data/lib/hecks/runtime/command_rules/arithmetic.rb +66 -196
  568. data/lib/hecks/runtime/command_rules/authorization.rb +13 -45
  569. data/lib/hecks/runtime/command_rules/emission.rb +8 -21
  570. data/lib/hecks/runtime/command_rules/references.rb +23 -202
  571. data/lib/hecks/runtime/dependency_planning.rb +50 -104
  572. data/lib/hecks/runtime/dispatcher.rb +134 -243
  573. data/lib/hecks/runtime/entity_element.rb +40 -462
  574. data/lib/hecks/runtime/entity_interpreter.rb +64 -219
  575. data/lib/hecks/runtime/errors.rb +32 -115
  576. data/lib/hecks/runtime/event.rb +3 -25
  577. data/lib/hecks/runtime/identity.rb +18 -154
  578. data/lib/hecks/runtime/instance.rb +18 -150
  579. data/lib/hecks/runtime/interpreting.rb +14 -70
  580. data/lib/hecks/runtime/invocation.rb +28 -164
  581. data/lib/hecks/runtime/loader.rb +109 -194
  582. data/lib/hecks/runtime/outbox.rb +39 -262
  583. data/lib/hecks/runtime/policy_interpreter.rb +43 -202
  584. data/lib/hecks/runtime/port_operation_interpreter.rb +28 -97
  585. data/lib/hecks/runtime/query_interpreter.rb +122 -187
  586. data/lib/hecks/runtime/reaction_invocation.rb +36 -138
  587. data/lib/hecks/runtime/reaction_outcome.rb +89 -0
  588. data/lib/hecks/runtime/read_model_interpreter.rb +117 -208
  589. data/lib/hecks/runtime/rebuild_sweep.rb +8 -54
  590. data/lib/hecks/runtime/reference_hop.rb +8 -81
  591. data/lib/hecks/runtime/refusal_wording.rb +28 -87
  592. data/lib/hecks/runtime/registry/saga_persistence.rb +10 -102
  593. data/lib/hecks/runtime/registry/verification.rb +213 -227
  594. data/lib/hecks/runtime/registry/world_defaults.rb +4 -53
  595. data/lib/hecks/runtime/registry.rb +156 -247
  596. data/lib/hecks/runtime/remote_dispatcher.rb +68 -154
  597. data/lib/hecks/runtime/routing.rb +4 -15
  598. data/lib/hecks/runtime/saga_interpreter/correlation.rb +14 -61
  599. data/lib/hecks/runtime/saga_interpreter.rb +79 -263
  600. data/lib/hecks/runtime/saga_pending_dispatch.rb +2 -43
  601. data/lib/hecks/runtime/tenant_check.rb +6 -68
  602. data/lib/hecks/runtime/tenant_scope.rb +3 -28
  603. data/lib/hecks/runtime/value/admission.rb +16 -67
  604. data/lib/hecks/runtime/value/coercion.rb +162 -760
  605. data/lib/hecks/runtime/value/entity_list_coercion.rb +26 -219
  606. data/lib/hecks/runtime/value/field_checks.rb +172 -0
  607. data/lib/hecks/runtime/value.rb +15 -84
  608. data/lib/hecks/runtime.rb +35 -69
  609. data/lib/hecks/rust_build/conformance.rb +158 -0
  610. data/lib/hecks/rust_build/conformance_fuzz.rb +71 -0
  611. data/lib/hecks/rust_build/coverage.rb +218 -0
  612. data/lib/hecks/rust_build/native_build.rb +124 -0
  613. data/lib/hecks/rust_build/project_rust/root_mod.rb +120 -0
  614. data/lib/hecks/rust_build/project_rust.rb +332 -0
  615. data/lib/hecks/rust_build/wasm.rb +105 -0
  616. data/lib/hecks/rust_build/wasm_browser.rb +113 -0
  617. data/lib/hecks/rust_build.rb +144 -0
  618. data/lib/hecks/storehouse.rb +155 -582
  619. data/lib/hecks/tenancy/bluebook/tenancy.bluebook +10 -34
  620. data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +6 -23
  621. data/lib/hecks/three_zero/forms.yml +127 -0
  622. data/lib/hecks/three_zero.rb +12 -0
  623. data/lib/hecks/tools/argument_gate_matrix.rb +316 -0
  624. data/lib/hecks/tools/comment_style.rb +1070 -0
  625. data/lib/hecks/tools/corpus_report.rb +87 -0
  626. data/lib/hecks/tools/deploy_recipe.rb +255 -0
  627. data/lib/hecks/tools/deploy_recipe_lint.rb +282 -0
  628. data/lib/hecks/tools/drop_implicit_append_fields.rb +95 -0
  629. data/lib/hecks/tools/era_projection_backfill.rb +94 -0
  630. data/lib/hecks/tools/era_reattest.rb +146 -0
  631. data/lib/hecks/tools/evolve_run.rb +189 -0
  632. data/lib/hecks/tools/fuzz_sweep.rb +373 -0
  633. data/lib/hecks/tools/heki_compaction.rb +100 -0
  634. data/lib/hecks/tools/hoist_local_givens.rb +246 -0
  635. data/lib/hecks/tools/journal_compaction.rb +89 -0
  636. data/lib/hecks/tools/oidc_manifests.rb +70 -0
  637. data/lib/hecks/tools/query_ir_run.rb +81 -0
  638. data/lib/hecks/tools/regeneration_run.rb +166 -0
  639. data/lib/hecks/tools/rust_comment_style.rb +642 -0
  640. data/lib/hecks/tools/sequence_script.rb +62 -0
  641. data/lib/hecks/tools/tail_merge.rb +117 -0
  642. data/lib/hecks/tools/tenant_provisioning.rb +142 -0
  643. data/lib/hecks/tools/translation_audit.rb +208 -0
  644. data/lib/hecks/tools/translation_scaffold.rb +131 -0
  645. data/lib/hecks/tools.rb +86 -0
  646. data/lib/hecks/vendoring/git_environment.rb +2 -8
  647. data/lib/hecks/vendoring/git_source.rb +4 -10
  648. data/lib/hecks/vendoring.rb +7 -46
  649. data/lib/hecks/version.rb +3 -14
  650. data/lib/hecks.rb +52 -90
  651. data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +8 -46
  652. data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +11 -80
  653. data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +10 -99
  654. data/qa/settings.yml +66 -0
  655. data/rust/.cargo/config.toml +6 -0
  656. data/rust/.gitignore +2 -0
  657. data/rust/Cargo.lock +54 -0
  658. data/rust/Cargo.toml +61 -0
  659. data/rust/build/.cargo/config.toml +3 -0
  660. data/rust/build/.gitignore +1 -0
  661. data/rust/build/Cargo.lock +7 -0
  662. data/rust/build/Cargo.toml +19 -0
  663. data/rust/build/src/build_artifact.rs +47 -0
  664. data/rust/build/src/cargo_sync.rs +248 -0
  665. data/rust/build/src/json.rs +421 -0
  666. data/rust/build/src/lineage_pass.rs +285 -0
  667. data/rust/build/src/main.rs +51 -0
  668. data/rust/build/src/optional_pass.rs +150 -0
  669. data/rust/build/src/pipeline.rs +264 -0
  670. data/rust/build/src/reserved_names.rs +76 -0
  671. data/rust/build/src/resolve.rs +124 -0
  672. data/rust/build/src/root.rs +25 -0
  673. data/rust/build/src/sidecars.rs +73 -0
  674. data/rust/build/src/subprocess.rs +51 -0
  675. data/rust/build/src/tmp.rs +31 -0
  676. data/rust/codegen/.cargo/config.toml +3 -0
  677. data/rust/codegen/.gitignore +1 -0
  678. data/rust/codegen/Cargo.lock +7 -0
  679. data/rust/codegen/Cargo.toml +20 -0
  680. data/rust/codegen/src/attr.rs +32 -0
  681. data/rust/codegen/src/bridging.rs +481 -0
  682. data/rust/codegen/src/commands.rs +1226 -0
  683. data/rust/codegen/src/constraints.rs +109 -0
  684. data/rust/codegen/src/dependency_planning.rs +209 -0
  685. data/rust/codegen/src/domain_generator.rs +1288 -0
  686. data/rust/codegen/src/exemplar.rs +230 -0
  687. data/rust/codegen/src/expr_emitter.rs +87 -0
  688. data/rust/codegen/src/fielded.rs +192 -0
  689. data/rust/codegen/src/hecks_naming.rs +33 -0
  690. data/rust/codegen/src/json.rs +335 -0
  691. data/rust/codegen/src/json_codec.rs +697 -0
  692. data/rust/codegen/src/literal.rs +207 -0
  693. data/rust/codegen/src/main.rs +290 -0
  694. data/rust/codegen/src/manifest.rs +227 -0
  695. data/rust/codegen/src/mutations.rs +784 -0
  696. data/rust/codegen/src/naming.rs +286 -0
  697. data/rust/codegen/src/ports.rs +208 -0
  698. data/rust/codegen/src/prelude.rs +116 -0
  699. data/rust/codegen/src/queries.rs +786 -0
  700. data/rust/codegen/src/reactions.rs +532 -0
  701. data/rust/codegen/src/read_models.rs +697 -0
  702. data/rust/codegen/src/reference_specs.rs +40 -0
  703. data/rust/codegen/src/registry.rs +966 -0
  704. data/rust/codegen/src/reserved_names.rs +76 -0
  705. data/rust/codegen/src/shared.rs +93 -0
  706. data/rust/codegen/src/skip_reason.rs +25 -0
  707. data/rust/codegen/src/types.rs +362 -0
  708. data/rust/host/.cargo/config.toml +3 -0
  709. data/rust/host/.gitignore +1 -0
  710. data/rust/host/Cargo.lock +4297 -0
  711. data/rust/host/Cargo.toml +61 -0
  712. data/rust/host/HECKS_RELEASE +1 -0
  713. data/rust/host/rds-ca-bundle.pem +2736 -0
  714. data/rust/host/src/api.rs +1596 -0
  715. data/rust/host/src/approval.rs +652 -0
  716. data/rust/host/src/auth.rs +1287 -0
  717. data/rust/host/src/bin/expr_harness.rs +46 -0
  718. data/rust/host/src/bin/lineage_harness.rs +119 -0
  719. data/rust/host/src/bin/mint_harness.rs +135 -0
  720. data/rust/host/src/checkout.rs +265 -0
  721. data/rust/host/src/dispatch.rs +1443 -0
  722. data/rust/host/src/expr_json.rs +1117 -0
  723. data/rust/host/src/field_hints.rs +52 -0
  724. data/rust/host/src/ir.rs +733 -0
  725. data/rust/host/src/journal.rs +874 -0
  726. data/rust/host/src/lambda_client.rs +378 -0
  727. data/rust/host/src/log.rs +147 -0
  728. data/rust/host/src/main.rs +474 -0
  729. data/rust/host/src/mint.rs +1865 -0
  730. data/rust/host/src/payments/keystore.rs +330 -0
  731. data/rust/host/src/payments/tests.rs +1400 -0
  732. data/rust/host/src/payments.rs +767 -0
  733. data/rust/host/src/presentation.rs +698 -0
  734. data/rust/host/src/presentation_write.rs +1431 -0
  735. data/rust/host/src/query_step.rs +149 -0
  736. data/rust/host/src/rate_limit.rs +904 -0
  737. data/rust/host/src/reference_transform.rs +241 -0
  738. data/rust/host/src/reference_validate.rs +338 -0
  739. data/rust/host/src/resend.rs +296 -0
  740. data/rust/host/src/secrets.rs +106 -0
  741. data/rust/host/src/server.rs +663 -0
  742. data/rust/host/src/storage_shape.rs +175 -0
  743. data/rust/host/src/test_pg.rs +40 -0
  744. data/rust/host/src/ui_schema.rs +1351 -0
  745. data/rust/host/src/wasm_runner.rs +191 -0
  746. data/rust/host/src/web/newsletter/cooldown.rs +126 -0
  747. data/rust/host/src/web/newsletter/tests.rs +104 -0
  748. data/rust/host/src/web/newsletter.rs +310 -0
  749. data/rust/host/src/web/newsletter_send.rs +357 -0
  750. data/rust/host/src/web/registrations.rs +1505 -0
  751. data/rust/host/src/web.rs +2937 -0
  752. data/rust/lsp/.gitignore +1 -0
  753. data/rust/lsp/Cargo.lock +7 -0
  754. data/rust/lsp/Cargo.toml +16 -0
  755. data/rust/lsp/README.md +133 -0
  756. data/rust/lsp/src/diagnostics.rs +165 -0
  757. data/rust/lsp/src/json.rs +385 -0
  758. data/rust/lsp/src/main.rs +399 -0
  759. data/rust/lsp/src/outline.rs +177 -0
  760. data/rust/lsp/src/rpc.rs +67 -0
  761. data/rust/parser/.cargo/config.toml +5 -0
  762. data/rust/parser/.gitignore +1 -0
  763. data/rust/parser/Cargo.lock +7 -0
  764. data/rust/parser/Cargo.toml +21 -0
  765. data/rust/parser/src/build/closed_sets.rs +27 -0
  766. data/rust/parser/src/build/identity.rs +276 -0
  767. data/rust/parser/src/build/mod.rs +12 -0
  768. data/rust/parser/src/build/naming.rs +141 -0
  769. data/rust/parser/src/build/pattern_subset.rs +161 -0
  770. data/rust/parser/src/build/query_derive.rs +72 -0
  771. data/rust/parser/src/build/query_inference.rs +269 -0
  772. data/rust/parser/src/build/query_options.rs +100 -0
  773. data/rust/parser/src/build/read_model.rs +94 -0
  774. data/rust/parser/src/build/references.rs +32 -0
  775. data/rust/parser/src/canonical.rs +114 -0
  776. data/rust/parser/src/diag.rs +55 -0
  777. data/rust/parser/src/emit.rs +953 -0
  778. data/rust/parser/src/expr/ast_json.rs +147 -0
  779. data/rust/parser/src/expr/evaluator.rs +81 -0
  780. data/rust/parser/src/expr/mod.rs +84 -0
  781. data/rust/parser/src/expr/resolver.rs +497 -0
  782. data/rust/parser/src/ir.rs +387 -0
  783. data/rust/parser/src/keywords.rs +585 -0
  784. data/rust/parser/src/lex.rs +662 -0
  785. data/rust/parser/src/main.rs +252 -0
  786. data/rust/parser/src/parse/aggregate.rs +612 -0
  787. data/rust/parser/src/parse/chapter.rs +517 -0
  788. data/rust/parser/src/parse/command.rs +637 -0
  789. data/rust/parser/src/parse/domain_port.rs +127 -0
  790. data/rust/parser/src/parse/entity.rs +527 -0
  791. data/rust/parser/src/parse/file.rs +67 -0
  792. data/rust/parser/src/parse/hecksagon.rs +231 -0
  793. data/rust/parser/src/parse/lifecycle.rs +162 -0
  794. data/rust/parser/src/parse/mod.rs +1262 -0
  795. data/rust/parser/src/parse/policy.rs +87 -0
  796. data/rust/parser/src/parse/process_manager.rs +305 -0
  797. data/rust/parser/src/parse/query.rs +100 -0
  798. data/rust/parser/src/parse/read_model.rs +214 -0
  799. data/rust/parser/src/parse/value_object.rs +250 -0
  800. data/rust/parser/src/ruby_value.rs +422 -0
  801. data/rust/project/bridging.rb +257 -0
  802. data/rust/project/commands.rb +877 -0
  803. data/rust/project/constraints.rb +86 -0
  804. data/rust/project/dependency_planning.rb +178 -0
  805. data/rust/project/domain_generator.rb +980 -0
  806. data/rust/project/exemplar.rb +148 -0
  807. data/rust/project/expr_emitter.rb +72 -0
  808. data/rust/project/fielded.rb +141 -0
  809. data/rust/project/json_codec.rb +641 -0
  810. data/rust/project/mutations.rb +721 -0
  811. data/rust/project/naming.rb +205 -0
  812. data/rust/project/ports.rb +65 -0
  813. data/rust/project/queries.rb +493 -0
  814. data/rust/project/reactions.rb +317 -0
  815. data/rust/project/read_models.rb +690 -0
  816. data/rust/project/reference_specs.rb +27 -0
  817. data/rust/project/registry.rb +396 -0
  818. data/rust/project/skip_reason.rb +29 -0
  819. data/rust/project/types.rb +225 -0
  820. data/rust/project/write_if_changed.rb +83 -0
  821. data/rust/project.rb +30 -0
  822. data/rust/project_rust_pipeline.rb +383 -0
  823. data/rust/src/exemplar/commands.rs +279 -0
  824. data/rust/src/exemplar/constraints.rs +18 -0
  825. data/rust/src/exemplar/fielded.rs +280 -0
  826. data/rust/src/exemplar/json.rs +277 -0
  827. data/rust/src/exemplar/mod.rs +17 -0
  828. data/rust/src/exemplar/mutations.rs +80 -0
  829. data/rust/src/exemplar/queries.rs +33 -0
  830. data/rust/src/exemplar/reactions.rs +88 -0
  831. data/rust/src/exemplar/read_models.rs +48 -0
  832. data/rust/src/exemplar/registry.rs +166 -0
  833. data/rust/src/exemplar/types.rs +44 -0
  834. data/rust/src/kernel/attribute_shapes/composite.rs +88 -0
  835. data/rust/src/kernel/attribute_shapes/list.rs +18 -0
  836. data/rust/src/kernel/attribute_shapes/mod.rs +44 -0
  837. data/rust/src/kernel/attribute_shapes/optional.rs +9 -0
  838. data/rust/src/kernel/attribute_shapes/scalar.rs +39 -0
  839. data/rust/src/kernel/cli.rs +585 -0
  840. data/rust/src/kernel/dispatch.rs +1090 -0
  841. data/rust/src/kernel/expr.rs +458 -0
  842. data/rust/src/kernel/expression_operators/arithmetic.rs +128 -0
  843. data/rust/src/kernel/expression_operators/comparison.rs +48 -0
  844. data/rust/src/kernel/expression_operators/enumeration.rs +232 -0
  845. data/rust/src/kernel/expression_operators/logical.rs +13 -0
  846. data/rust/src/kernel/expression_operators/membership.rs +18 -0
  847. data/rust/src/kernel/expression_operators/mod.rs +68 -0
  848. data/rust/src/kernel/expression_operators/pattern_match.rs +73 -0
  849. data/rust/src/kernel/expression_operators/positional.rs +126 -0
  850. data/rust/src/kernel/expression_operators/presence.rs +101 -0
  851. data/rust/src/kernel/expression_operators/sign_test.rs +16 -0
  852. data/rust/src/kernel/expression_operators/sized.rs +35 -0
  853. data/rust/src/kernel/expression_operators/text.rs +79 -0
  854. data/rust/src/kernel/expression_operators/to_string.rs +18 -0
  855. data/rust/src/kernel/json.rs +779 -0
  856. data/rust/src/kernel/mod.rs +133 -0
  857. data/rust/src/kernel/named_query.rs +219 -0
  858. data/rust/src/kernel/orchestrate.rs +1810 -0
  859. data/rust/src/kernel/pattern.rs +307 -0
  860. data/rust/src/kernel/query_comparators.rs +206 -0
  861. data/rust/src/kernel/query_ordering.rs +103 -0
  862. data/rust/src/kernel/read_model.rs +914 -0
  863. data/rust/src/kernel/reference_lookup.rs +149 -0
  864. data/rust/src/kernel/repository.rs +468 -0
  865. data/rust/src/kernel/routing.rs +612 -0
  866. data/rust/src/kernel/vocab/aggregate_dispatch_order.rs +118 -0
  867. data/rust/src/kernel/vocab/entity_dispatch_order.rs +114 -0
  868. data/rust/src/kernel/vocab/field_hint.rs +70 -0
  869. data/rust/src/kernel/vocab/mod.rs +20 -0
  870. data/rust/src/kernel/vocab/query_comparator.rs +65 -0
  871. data/rust/src/kernel/vocab/refusal_template.rs +1592 -0
  872. data/rust/src/lib.rs +8 -0
  873. data/rust/src/main.rs +16 -0
  874. data/rust/web/.gitignore +1 -0
  875. data/rust/web/Cargo.lock +119 -0
  876. data/rust/web/Cargo.toml +18 -0
  877. data/rust/web/src/lib.rs +8 -0
  878. metadata +478 -12
  879. data/lib/hecks/facade/cli_door.rb +0 -178
  880. data/lib/hecks/facade/cli_runner.rb +0 -271
  881. data/lib/hecks/facade/handle.rb +0 -293
  882. data/lib/hecks/facade/json_door.rb +0 -247
  883. data/lib/hecks/facade/surface/aggregate_door.rb +0 -222
  884. data/lib/hecks/facade/surface/chapter.rb +0 -116
  885. data/lib/hecks/facade/surface.rb +0 -61
  886. data/lib/hecks/mcp_door_scope.rb +0 -176
@@ -4,106 +4,53 @@ require_relative "../naming"
4
4
  require_relative "value_object_shape"
5
5
 
6
6
  module Hecks
7
- # The forms surface's own namespace — the `expose` DSL, the IR->HTML
8
- # renderers, and the Rack app bridging them; see `forms.rb`'s own header,
9
- # its primary opening, for the fuller design this implements.
7
+ # The forms surface: the `expose` DSL, the IR->HTML renderers and the Rack app (see forms.rb).
10
8
  module Forms
11
- # One resolved field, ready for a renderer to turn into markup. A leaf
12
- # scalar carries `kind`/`options`/etc; a `:group` or `:list` carries
13
- # `children` instead and nothing else on itself.
14
- #
15
- # `path` is the dotted field path this attribute is reached at —
16
- # `"email.address"`, `"amount.cents"` — the same convention the language
17
- # already uses for a query's own cross-object `where` clauses
18
- # (`where(:"customer.status" => ...)`), not a fresh one invented here. A
19
- # command receives its arguments as nested hashes
20
- # (`email: {address: "..."}`), so `Params.extract` (params.rb) walks
21
- # this same dotted spelling back apart on submit — one convention, two
22
- # directions.
9
+ # One resolved field, ready for a renderer. A leaf carries `kind`/`options`; a `:group`
10
+ # or `:list` carries `children`. `path` is the dotted path (`"amount.cents"`) that
11
+ # `Params.extract` walks back apart on submit.
23
12
  Field = Struct.new(
24
13
  :path, :label, :kind, :html_type, :options, :children, :default, :optional,
25
14
  :pattern, :step, :help, :target_aggregate, keyword_init: true
26
15
  ) do
27
- # Tells whether this field holds a value itself rather than carrying `children`.
28
- #
29
- # @return [Boolean] false for a `:group` or `:list`, true for every other kind,
30
- # `:money` included
31
16
  def leaf? = kind != :group && kind != :list
32
17
 
33
- # Tells whether a submission may leave this field blank.
34
- #
35
- # @return [Boolean, nil] the `optional` member as given; nil when the field was built
36
- # without one, which reads as required
37
18
  def optional? = optional
38
19
 
39
- # Tells whether a submission must fill this field in.
40
- #
41
- # @return [Boolean] true unless `optional` was set truthy
42
20
  def required? = !optional
43
21
  end
44
22
 
45
- # Turns a wire-spelled field or path segment into the plain-English text
46
- # `FieldShape` embeds as a `Field`'s label or a group's legend.
23
+ # Turns a wire-spelled field or path segment into a label or legend.
47
24
  module Humanize
48
- # Humanizes the last segment of a field name or dotted path into sentence-case words.
49
- #
50
- # "given" -> "Given", "daily_limit" -> "Daily limit", "end_to_end" ->
51
- # "End to end" — the label a plain reader wants, not the wire spelling.
52
- #
53
- # @param text [String, Symbol, nil] a field name or dotted path, such as
54
- # `"amount.cents"`; only the part after the last `"."` is used
55
- # @return [String] the humanized words, or `""` when `text` is nil or empty
25
+ # "daily_limit" -> "Daily limit"; only the last segment of a dotted path is used.
56
26
  def self.label(text)
57
- # Split on "." first, alone, to take only the last path segment —
58
- # "daily_limit" is one segment (the underscore is a word break
59
- # inside it, not a path hop) and must keep both its words; only a
60
- # genuinely dotted path ("amount.cents") drops everything before
61
- # the last ".".
27
+ # Split on "." alone: an underscore is a word break within a segment, not a path hop.
62
28
  segment = text.to_s.split(".").last.to_s
63
29
  return segment if segment.empty?
64
30
 
65
- # The word split itself is `Naming.words` — the one humanizer,
66
- # shared with the glossary projection.
67
31
  Naming.words(segment)
68
32
  end
69
33
 
70
- # Humanizes every segment of a dotted path and joins them with " → ".
71
- #
72
- # The full dotted path, each segment humanized and joined with
73
- # " → " for a fieldset legend spanning more than one hop
74
- # ("Amount → Cents") — a group's own legend, not a leaf's label.
75
- #
76
- # @param path [String, Symbol, nil] a dotted field path, such as `"amount.cents"`
77
- # @return [String] the humanized trail, or `""` when `path` is nil or empty
34
+ # "amount.cents" -> "Amount → Cents", for a fieldset legend spanning several hops.
78
35
  def self.breadcrumb(path)
79
36
  path.to_s.split(".").map { |part| label(part) }.join(" → ")
80
37
  end
81
38
  end
82
39
 
83
- # Attribute -> Field. The one mapping every renderer in this
84
- # directory reads instead of re-deriving its own — see
85
- # docs/command-form-and-query-form-bluebook.md's survey of the gap this closes (the
86
- # prior generic-console attempt fell back to `type="text"` for anything
87
- # that wasn't a number or an enum; a `pattern` naming an email shape, or a
88
- # closed set another aggregate declares, went unread).
40
+ # Attribute -> Field: the one mapping every form renderer reads instead of re-deriving.
89
41
  module FieldShape
90
42
  PRIMITIVES = Bluebook::Attribute::PRIMITIVES
91
43
 
92
- # Resolves one declared attribute into the field a form renders for it, choosing the
93
- # input kind from the attribute's type, pattern, `admits:` set and value-object shape.
44
+ # Resolves one declared attribute into the field a form renders for it.
94
45
  #
95
- # `aggregate:` is the Aggregate that owns this attribute (a
96
- # command's, a query's, or — recursively — a value object's) —
97
- # needed to resolve `reference_to`, `admits:`, and a same-chapter
98
- # value object by name. `path:` defaults to the attribute's own name;
99
- # a caller resolving a nested value object's attribute passes the
100
- # dotted path so far.
46
+ # `aggregate` owns the attribute and is needed to resolve `reference_to`, `admits:`
47
+ # and same-chapter value objects; `path` is the dotted path reached so far.
101
48
  #
102
- # @param attribute [Bluebook::Attribute] the attribute to build a field for
103
- # @param aggregate [Bluebook::Aggregate] the aggregate that owns the attribute
104
- # @param path [String] dotted field path the attribute is reached at
105
- # @return [Forms::Field] the resolved field; a single-attribute value object resolves
106
- # to its inner leaf, so the returned path may be longer than `path`
49
+ # @param attribute [Bluebook::Attribute]
50
+ # @param aggregate [Bluebook::Aggregate]
51
+ # @param path [String]
52
+ # @return [Forms::Field] a single-attribute value object resolves to its inner leaf,
53
+ # so the returned path may be longer than `path`
107
54
  # @raise [Bluebook::DSL::Malformed] if a `reference_to` attribute cannot say which
108
55
  # aggregate declares it
109
56
  def self.resolve(attribute, aggregate:, path: attribute.name.to_s)
@@ -119,19 +66,8 @@ module Hecks
119
66
  primitive_field(attribute, common)
120
67
  end
121
68
 
122
- # Builds the `:list` field for a `list_of` attribute, carrying as its one child the field
123
- # a single element would resolve to.
124
- #
125
- # @param attribute [Bluebook::Attribute] the list attribute
126
- # @param aggregate [Bluebook::Aggregate] the aggregate that owns the attribute
127
- # @param path [String] dotted field path the list is reached at
128
- # @return [Forms::Field] a `:list` field whose `children` holds exactly one element field
129
- # @raise [Bluebook::DSL::Malformed] if the element is a `reference_to` that cannot say
130
- # which aggregate declares it
131
69
  def self.list_field(attribute, aggregate, path)
132
- # The scalar shape one element of this list would take, so a
133
- # renderer can say what belongs on each line without a second
134
- # mapping table. `list:` is the only thing that differs.
70
+ # The scalar one element would take; `list:` is the only thing that differs.
135
71
  scalar = Bluebook::Attribute.new(
136
72
  name: attribute.name, type: attribute.type, list: false,
137
73
  default: nil, optional: true, pattern: attribute.pattern, admits: attribute.admits
@@ -140,17 +76,6 @@ module Hecks
140
76
  children: [resolve(scalar, aggregate: aggregate, path: path)])
141
77
  end
142
78
 
143
- # Builds the `:reference` field for a `reference_to` attribute, remembering the target
144
- # aggregate so a renderer can offer its records.
145
- #
146
- # @param attribute [Bluebook::Attribute] an attribute whose type is a
147
- # `Bluebook::Reference`
148
- # @param common [Hash{Symbol => Object}] the `Field` members every kind shares, keyed
149
- # `:path`, `:label`, `:default`, `:optional`, `:pattern`
150
- # @return [Forms::Field] a `:reference` field; its `target_aggregate` is nil when the
151
- # target belongs to a domain that is not loaded
152
- # @raise [Bluebook::DSL::Malformed] if the reference cannot say which aggregate
153
- # declares it
154
79
  def self.reference_field(attribute, common)
155
80
  target = attribute.type.resolve
156
81
  Field.new(**common, kind: :reference, html_type: "text", target_aggregate: target,
@@ -161,24 +86,8 @@ module Hecks
161
86
  end)
162
87
  end
163
88
 
164
- # Builds the radio or select field for an attribute whose `admits:` names a closed set,
165
- # offering exactly that set's members.
166
- #
167
- # `admits:` names a closed set declared elsewhere (`"Account::
168
- # LedgerDirection"`) that the value must belong to — see
169
- # Runtime::Value::Admission#admitted_members, which this mirrors
170
- # exactly (same split, same chapter walk, same discriminant rule) so
171
- # a rendered `<select>` never offers a member the runtime would then
172
- # refuse.
173
- #
174
- # @param attribute [Bluebook::Attribute] an attribute declaring `admits:`
175
- # @param aggregate [Bluebook::Aggregate] the aggregate that owns the attribute; its
176
- # chapter is searched for the named set
177
- # @param common [Hash{Symbol => Object}] the `Field` members every kind shares, keyed
178
- # `:path`, `:label`, `:default`, `:optional`, `:pattern`
179
- # @return [Forms::Field] a `:radio` or `:select` field, its path extended by one hop
180
- # when the attribute's own type is a single-attribute value object; a plain
181
- # primitive field when the named set is not declared
89
+ # Mirrors Runtime::Value::Admission#admitted_members (same split, chapter walk and
90
+ # discriminant rule) so a `<select>` never offers a member the runtime would refuse.
182
91
  def self.admitted_field(attribute, aggregate, common)
183
92
  set_aggregate_name, set_name = attribute.admits.to_s.split("::", 2)
184
93
  chapter = aggregate.hecks_owner
@@ -187,15 +96,8 @@ module Hecks
187
96
  return primitive_field(attribute, common) unless set
188
97
 
189
98
  options = select_or_radio(common, closed_set_options(set))
190
- # The attribute's own type still has to be built the shape coercion
191
- # expects (`Value::Coercion#fields_for` refuses anything that
192
- # isn't a Hash or a Value for a value-object-typed attribute) — a
193
- # plain String attribute stays a bare scalar, but a value object
194
- # like `MovementDirection { value }` still needs the ".value" hop
195
- # even though the set it's checked against (`admits:`) is declared
196
- # somewhere else entirely. Same unwrap `value_object_field` does,
197
- # kept separate because an admitted set changes the options, not
198
- # which field the hop lands on.
99
+ # A value-object-typed attribute still needs the ".value" hop that
100
+ # `Value::Coercion#fields_for` expects, even though `admits:` names a set elsewhere.
199
101
  own_shape = own_value_object(attribute, aggregate)
200
102
  inner = own_shape && ValueObjectShape.sole_attribute(own_shape)
201
103
  return options unless inner
@@ -204,28 +106,10 @@ module Hecks
204
106
  options
205
107
  end
206
108
 
207
- # Finds the value object an attribute's type names, looking on the owning aggregate
208
- # first and then on every other aggregate of the same chapter.
209
- #
210
- # @param attribute [Bluebook::Attribute] the attribute whose type names a value object
211
- # @param aggregate [Bluebook::Aggregate] the aggregate that owns the attribute
212
- # @return [Bluebook::ValueObject, nil] the declared shape, or nil when no aggregate in
213
- # the chapter declares a value object of that name
214
109
  def self.own_value_object(attribute, aggregate)
215
110
  aggregate.value_object(attribute.type) || cross_aggregate_value_object(aggregate, attribute.type)
216
111
  end
217
112
 
218
- # Builds the field for an attribute typed as a value object: a closed-set choice, a
219
- # money pair, the unwrapped inner leaf of a single-attribute shape, or a group.
220
- #
221
- # @param attribute [Bluebook::Attribute] an attribute whose type is not a primitive
222
- # @param aggregate [Bluebook::Aggregate] the aggregate that owns the attribute
223
- # @param common [Hash{Symbol => Object}] the `Field` members every kind shares, keyed
224
- # `:path`, `:label`, `:default`, `:optional`, `:pattern`
225
- # @return [Forms::Field] the resolved field; a plain primitive field when the named
226
- # value object is not declared anywhere in the chapter
227
- # @raise [Bluebook::DSL::Malformed] if a nested `reference_to` attribute cannot say
228
- # which aggregate declares it
229
113
  def self.value_object_field(attribute, aggregate, common)
230
114
  shape = own_value_object(attribute, aggregate)
231
115
  return primitive_field(attribute, common) unless shape
@@ -233,13 +117,8 @@ module Hecks
233
117
  return closed_set_field(shape, common) if shape.closed_set?
234
118
  return money_field(shape, common) if ValueObjectShape.money?(shape)
235
119
 
236
- # A single-attribute value object (EmailAddress{address}, CustomerNumber{value})
237
- # is a name for a scalar, not a genuine group — unwrap it so the form
238
- # asks for one thing ("Email address") instead of a one-item fieldset,
239
- # and so the inner attribute's own pattern (the real email regex,
240
- # declared on `address`, not on the outer `email` attribute) drives
241
- # the input type. [[feedback_name_the_scalar_field]] says the same
242
- # thing about Ruby call sites; a form asks the identical question.
120
+ # A single-attribute value object names a scalar, not a group: unwrap it so the form
121
+ # asks for one thing and the inner attribute's own pattern drives the input type.
243
122
  if (inner = ValueObjectShape.sole_attribute(shape))
244
123
  return resolve(inner, aggregate: aggregate, path: "#{common[:path]}.#{inner.name}")
245
124
  .tap { |field| field.optional = common[:optional] || field.optional }
@@ -248,14 +127,6 @@ module Hecks
248
127
  group_field(shape, aggregate, common)
249
128
  end
250
129
 
251
- # Searches every aggregate of the owning chapter for a value object by name, so a shape
252
- # declared on a sibling aggregate still resolves.
253
- #
254
- # @param aggregate [Bluebook::Aggregate] any aggregate of the chapter to search
255
- # @param type_name [String] name of the value object, as `Bluebook::Attribute#type`
256
- # spells it
257
- # @return [Bluebook::ValueObject, nil] the first match in aggregate declaration order, or
258
- # nil when none declares it or the aggregate has no owning chapter
259
130
  def self.cross_aggregate_value_object(aggregate, type_name)
260
131
  aggregate.hecks_owner&.aggregates&.each do |sibling|
261
132
  found = sibling.value_object(type_name)
@@ -264,31 +135,11 @@ module Hecks
264
135
  nil
265
136
  end
266
137
 
267
- # Builds the `:group` field for a multi-attribute value object, resolving each of its
268
- # attributes one path hop below the group.
269
- #
270
- # @param shape [Bluebook::ValueObject] the value object whose attributes become children
271
- # @param aggregate [Bluebook::Aggregate] the aggregate the nested attributes resolve
272
- # against
273
- # @param common [Hash{Symbol => Object}] the `Field` members every kind shares; only
274
- # `:path`, `:label` and `:optional` are read
275
- # @return [Forms::Field] a `:group` field with one child per attribute of `shape`
276
- # @raise [Bluebook::DSL::Malformed] if a nested `reference_to` attribute cannot say
277
- # which aggregate declares it
278
138
  def self.group_field(shape, aggregate, common)
279
139
  children = shape.attributes.map { |inner| resolve(inner, aggregate: aggregate, path: "#{common[:path]}.#{inner.name}") }
280
140
  Field.new(path: common[:path], label: common[:label], kind: :group, optional: common[:optional], children: children)
281
141
  end
282
142
 
283
- # Builds the `:money` field for a `cents`/`currency` value object: a required-or-not
284
- # whole-cents number input beside an always-optional currency code.
285
- #
286
- # @param shape [Bluebook::ValueObject] the money-shaped value object, read for the
287
- # declared defaults of `cents` and `currency`
288
- # @param common [Hash{Symbol => Object}] the `Field` members every kind shares; only
289
- # `:path`, `:label` and `:optional` are read
290
- # @return [Forms::Field] a `:money` field whose children are the `cents` and `currency`
291
- # leaves, the currency defaulting to `"USD"` when the shape declares none
292
143
  def self.money_field(shape, common)
293
144
  cents = Field.new(path: "#{common[:path]}.cents", label: "Amount (cents)", kind: :number,
294
145
  html_type: "number", step: "1", optional: common[:optional],
@@ -300,57 +151,25 @@ module Hecks
300
151
  children: [cents, currency])
301
152
  end
302
153
 
303
- # Lists a closed set's members by their discriminant — the value object's first
304
- # attribute — as the strings a form offers.
305
- #
306
- # @param value_object [Bluebook::ValueObject] a closed-set (`one_of`) value object
307
- # @return [Array<String>] one discriminant value per declared member, in declaration
308
- # order; `[]` when the shape declares no members
154
+ # A member's discriminant is the value object's first attribute.
309
155
  def self.closed_set_options(value_object)
310
156
  discriminant = value_object.attributes.first.name
311
157
  value_object.members.map { |member| member[discriminant].to_s }
312
158
  end
313
159
 
314
- # Builds the radio or select field for an attribute typed as a closed set, its path
315
- # extended by the set's discriminant attribute.
316
- #
317
- # A `one_of` shape (`AccountKind{name}`, `LedgerDirection{value}`) is
318
- # always single-attribute in this language — the discriminant is the
319
- # whole value object — so the field's own path always gains that one
320
- # hop; nothing to branch on the way `admitted_field` has to (a set
321
- # named by `admits:` may sit on a multi-field value object it doesn't
322
- # itself define the members of).
323
- #
324
- # @param shape [Bluebook::ValueObject] the closed-set value object
325
- # @param common [Hash{Symbol => Object}] the `Field` members every kind shares, keyed
326
- # `:path`, `:label`, `:default`, `:optional`, `:pattern`
327
- # @return [Forms::Field] a `:radio` or `:select` field offering the set's members
160
+ # A `one_of` shape is always single-attribute, so the path always gains the
161
+ # discriminant hop; `admitted_field` must branch because its set may be multi-field.
328
162
  def self.closed_set_field(shape, common)
329
163
  discriminant = shape.attributes.first.name
330
164
  select_or_radio(common.merge(path: "#{common[:path]}.#{discriminant}"), closed_set_options(shape))
331
165
  end
332
166
 
333
- # Builds a choice field over fixed options, as radio buttons for four or fewer and a
334
- # `<select>` beyond that.
335
- #
336
- # @param common [Hash{Symbol => Object}] the `Field` members every kind shares, keyed
337
- # `:path`, `:label`, `:default`, `:optional`, `:pattern`
338
- # @param options [Array<String>] the values offered; each is its own label
339
- # @return [Forms::Field] a `:radio` or `:select` field whose `options` are
340
- # `[value, label]` pairs
167
+ # Radio buttons for four or fewer options, a `<select>` beyond that.
341
168
  def self.select_or_radio(common, options)
342
169
  kind = options.size <= 4 ? :radio : :select
343
170
  Field.new(**common, kind: kind, html_type: "text", options: options.map { |value| [value, value] })
344
171
  end
345
172
 
346
- # Builds the leaf field for a primitive-typed attribute: a number input for `Integer`
347
- # and `Float`, a checkbox for a boolean, and a text-family input for anything else.
348
- #
349
- # @param attribute [Bluebook::Attribute] the attribute whose type picks the input
350
- # @param common [Hash{Symbol => Object}] the `Field` members every kind shares, keyed
351
- # `:path`, `:label`, `:default`, `:optional`, `:pattern`
352
- # @return [Forms::Field] a `:number`, `:boolean`, `:text` or `:textarea` leaf; an
353
- # `Integer` carries `step` `"1"`, a `Float` `"any"`
354
173
  def self.primitive_field(attribute, common)
355
174
  case attribute.type.to_s
356
175
  when "Integer" then Field.new(**common, kind: :number, html_type: "number", step: "1")
@@ -362,10 +181,9 @@ module Hecks
362
181
  end
363
182
  end
364
183
 
365
- # Vocabulary::FieldHint (language/bluebook/vocabulary.bluebook), read
366
- # off the generated table: `pattern` is the regex source, matched
367
- # case-insensitively. bin/project_field_hints writes the Rust host's
368
- # copy from the same rows.
184
+ # Vocabulary::FieldHint rows (language/bluebook/vocabulary.bluebook), matched
185
+ # case-insensitively. hecks project_field_hints writes the Rust host's copy from the same
186
+ # rows.
369
187
  HINTS = Hecks::Vocabulary.rows("FieldHint")
370
188
  .to_h { |row| [row["name"], Regexp.new(row["pattern"], Regexp::IGNORECASE)] }
371
189
  .freeze
@@ -374,15 +192,6 @@ module Hecks
374
192
  TEL_HINT = HINTS.fetch("tel")
375
193
  TEXTAREA_HINT = HINTS.fetch("textarea")
376
194
 
377
- # Builds a text-family leaf, picking `email`, `url`, `tel` or plain `text` from the
378
- # attribute's pattern and the `FieldHint` name patterns, and a textarea for a
379
- # long-text name.
380
- #
381
- # @param attribute [Bluebook::Attribute] the attribute whose name and pattern are read
382
- # @param common [Hash{Symbol => Object}] the `Field` members every kind shares, keyed
383
- # `:path`, `:label`, `:default`, `:optional`, `:pattern`
384
- # @return [Forms::Field] a `:text` leaf, or `:textarea` when the input type is plain
385
- # `"text"` and the name matches `TEXTAREA_HINT`
386
195
  def self.text_field(attribute, common)
387
196
  name = attribute.name.to_s
388
197
  pattern = attribute.pattern.to_s
@@ -2,20 +2,13 @@ require "uri"
2
2
 
3
3
  module Hecks
4
4
  module Forms
5
- # Hand-rolled, on purpose — the repo has no ERB anywhere and no template
6
- # engine dependency (see docs/command-form-and-query-form-bluebook.md's survey). Every
7
- # other generator in this codebase (bin/reference's markdown, the IR's own
8
- # `to_h`) builds output as plain Ruby strings; this does the same for HTML,
9
- # with exactly one job: nothing that reaches `Escape.html` ever becomes a
10
- # tag. A feature developer's own domain data — a customer's name, an
11
- # account number a support rep typed into a form and got wrong — flows
12
- # through here on every render, so escaping is not optional decoration.
5
+ # HTML, URL-query and URL-path escaping for values that come from domain data.
6
+ # Nothing that reaches `Escape.html` becomes a tag.
13
7
  module Escape
14
8
  # Escapes a value for HTML text content, replacing `&`, `<`, `>`, `"` and `'` with
15
9
  # entities so nothing in it becomes a tag.
16
10
  #
17
- # Order matters — `&` first, or every escape this method itself just
18
- # wrote (`&amp;`, `&lt;`, ...) gets re-escaped a second time.
11
+ # `&` is replaced first so the entities written here are not escaped again.
19
12
  #
20
13
  # @param value [Object, nil] the value to show, rendered with `to_s`; nil renders as `""`
21
14
  # @return [String] the escaped text
@@ -30,10 +23,8 @@ module Hecks
30
23
 
31
24
  # Escapes a value for use inside a quoted HTML attribute.
32
25
  #
33
- # Safe inside a double-quoted HTML attribute specifically — `html`
34
- # already covers this (it escapes `"`), kept as a named alias so a
35
- # call site reads "this value fills an attribute" rather than repeating
36
- # the same escaping and leaving the reader to check they match.
26
+ # Safe inside a double-quoted attribute; an alias of `html` so call sites say what
27
+ # the value fills.
37
28
  #
38
29
  # @param value [Object, nil] the attribute value, rendered with `to_s`; nil renders
39
30
  # as `""`
@@ -42,24 +33,9 @@ module Hecks
42
33
 
43
34
  # Percent-encodes a value for use as a query-string value.
44
35
  #
45
- # L12 (docs/audits/2026-08-10-main-bug-audit.md) — safe as a
46
- # query-string value. `html`/`attr` guard against the value becoming
47
- # markup, but say nothing about it staying inside the URL syntax
48
- # position it was placed in: an aggregate's identity is free-form
49
- # unless its value object declares a `pattern:` (see S3 in the same
50
- # audit), so `&`, `+`, `?`, `#`, and `/` are all otherwise legal id
51
- # characters, and each would corrupt an href/Location built by naive
52
- # interpolation (a stray `&` smuggles a second query parameter, `#`
53
- # truncates the path at a fragment, `/` splits the path into an
54
- # extra segment, ...). Percent-encodes via
55
- # `application/x-www-form-urlencoded` (`+` for space) — correct only
56
- # for a query-string value (query_form_renderer.rb's `quick_links`,
57
- # record_renderer.rb's `?to=`). For a URL path segment use `path`
58
- # below instead — `+` is a literal plus there, not an escaped space,
59
- # so this method would corrupt any id containing a space. Callers
60
- # still wrap the assembled href/Location in `attr` (or `html`) as
61
- # usual — this only covers the id's own component, not the
62
- # surrounding markup.
36
+ # Aggregate ids are free-form, so `&`, `#` and `/` must not reach a URL raw. Correct
37
+ # for a query-string value only; use `path` for a path segment. Callers still wrap
38
+ # the assembled href in `attr`.
63
39
  #
64
40
  # @param value [Object, nil] the value to encode, rendered with `to_s`
65
41
  # @return [String] the `application/x-www-form-urlencoded` form, a space rendered as `+`
@@ -67,13 +43,7 @@ module Hecks
67
43
 
68
44
  # Percent-encodes a value for use as one URL path segment.
69
45
  #
70
- # Same guard as `url`, for a URL path segment instead of a
71
- # query-string value. `encode_www_form_component` renders space as
72
- # `+`, which is only meaningful inside a query string — in a path
73
- # segment `+` is a literal plus, so an id like "John Smith" would
74
- # round-trip to "John+Smith" and 404 against the real id "John
75
- # Smith". Reuse the same percent-encoding and just correct that one
76
- # character back to `%20`.
46
+ # Like `url`, but a space becomes `%20`: `+` is a literal plus in a path segment.
77
47
  #
78
48
  # @param value [Object, nil] the segment to encode, rendered with `to_s`
79
49
  # @return [String] the percent-encoded segment, a space rendered as `%20` and `/` as
@@ -81,11 +51,8 @@ module Hecks
81
51
  def self.path(value) = URI.encode_www_form_component(value.to_s).gsub("+", "%20")
82
52
  end
83
53
 
84
- # A tiny attribute-hash -> string helper, shared by every renderer in
85
- # this directory so `<input ...>` doesn't get hand-assembled five
86
- # different ways with five different escaping bugs waiting in each.
87
- # `true` renders as a bare boolean attribute (`required`, not
88
- # `required="true"`); `nil`/`false` are dropped entirely.
54
+ # Attribute-hash to string helper shared by the form renderers.
55
+ # `true` renders a bare boolean attribute; `nil` and `false` are dropped.
89
56
  module Tag
90
57
  # Renders a Hash of attributes as the text that sits inside an opening tag, escaping
91
58
  # every value and spelling an underscored name with hyphens.
@@ -118,9 +85,7 @@ module Hecks
118
85
  # Renders a void element such as `<input>`. A self-closing tag reads the same as an
119
86
  # opening one; HTML5 needs no slash.
120
87
  #
121
- # `self.open(...)`, not bare `open(...)` — this `Tag.open` (an HTML tag
122
- # renderer, right above) shadows Kernel#open safely either way, but the
123
- # explicit receiver also settles Security/Open's static ambiguity.
88
+ # The explicit `self.open` receiver keeps Security/Open from flagging Kernel#open.
124
89
  #
125
90
  # @param name [String] the element name, such as `"input"`
126
91
  # @param pairs [Hash{Symbol => Object}] attributes, rendered as `attrs` renders them
@@ -2,10 +2,7 @@ require_relative "html"
2
2
 
3
3
  module Hecks
4
4
  module Forms
5
- # The home page: every exposed chapter, every aggregate on it — the
6
- # entry point into what would otherwise be a URL you'd have to already
7
- # know. `chapters` is `{domain_name => Bluebook::Chapter}`, in `expose`
8
- # order (see `Forms::Config` in forms.rb).
5
+ # The home page: every exposed chapter and the aggregates on it.
9
6
  module IndexRenderer
10
7
  # Renders the home page body: one section per exposed chapter, each linking to its
11
8
  # aggregates.
@@ -2,12 +2,8 @@ require_relative "html"
2
2
 
3
3
  module Hecks
4
4
  module Forms
5
- # The one HTML shell every page in this app renders inside — nav,
6
- # typography, form/table/badge styles, all inline (no CDN, no build
7
- # step: this ships inside the `hecks` gem, and a project that
8
- # embeds it gets one dependency-free response per request). Themed via
9
- # `prefers-color-scheme` alone; nothing here reads a cookie or a query
10
- # param for it, so it is never wrong for the browser rendering it.
5
+ # The HTML shell every page renders inside, with styles and script inline.
6
+ # Themed by `prefers-color-scheme` alone.
11
7
  module Page
12
8
  # Wraps one page's own body HTML in the shared shell: doctype, head, nav, footer,
13
9
  # inline styles and script.
@@ -146,9 +142,7 @@ module Hecks
146
142
  .actions { display: flex; flex-wrap: wrap; gap: .5rem; margin: .6rem 0 1.4rem; }
147
143
  CSS
148
144
 
149
- # Decorative only — every form here already works with JS disabled
150
- # (plain `<form method=post>`/`method=get`), matching this repo's own
151
- # "no ERB, nothing scripted" bar for the domain layer itself.
145
+ # Decorative only; every form works with JS disabled.
152
146
  SCRIPT = <<~JS.freeze
153
147
  document.addEventListener("click", (event) => {
154
148
  const button = event.target.closest("[data-copy]");