hecks 2.8.0 → 2.9.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 (404) hide show
  1. checksums.yaml +4 -4
  2. data/exe/hecks +4 -6
  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 +17 -98
  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 +4 -30
  23. data/lib/hecks/adapters/driven/postgres/schema_builder.rb +34 -108
  24. data/lib/hecks/adapters/driven/postgres.rb +145 -134
  25. data/lib/hecks/adapters/driven/postgres_era.adapter +4 -15
  26. data/lib/hecks/adapters/driven/prism.rb +7 -30
  27. data/lib/hecks/adapters/driven/sql_query_builder.rb +21 -121
  28. data/lib/hecks/adapters/driven/sqlite/codec.rb +8 -40
  29. data/lib/hecks/adapters/driven/sqlite/projection.rb +26 -82
  30. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +40 -84
  31. data/lib/hecks/adapters/driven/sqlite.rb +128 -65
  32. data/lib/hecks/adapters/driven/tenant_provisioner.rb +5 -48
  33. data/lib/hecks/adapters/driven.rb +5 -36
  34. data/lib/hecks/adapters/driving/github_webhook.rb +8 -76
  35. data/lib/hecks/behaviors/dsl.rb +7 -25
  36. data/lib/hecks/behaviors/expectations.rb +31 -141
  37. data/lib/hecks/behaviors/ir.rb +7 -20
  38. data/lib/hecks/behaviors/rspec.rb +6 -17
  39. data/lib/hecks/behaviors/runner.rb +10 -34
  40. data/lib/hecks/behaviors.rb +4 -8
  41. data/lib/hecks/bluebook/aggregate.rb +9 -75
  42. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +9 -38
  43. data/lib/hecks/bluebook/assembly/build.rb +4 -15
  44. data/lib/hecks/bluebook/assembly/contract.rb +15 -136
  45. data/lib/hecks/bluebook/assembly/contracts.rb +54 -174
  46. data/lib/hecks/bluebook/assembly/marks.rb +31 -223
  47. data/lib/hecks/bluebook/assembly/specializer.rb +6 -52
  48. data/lib/hecks/bluebook/assembly.rb +6 -45
  49. data/lib/hecks/bluebook/attribute.rb +12 -61
  50. data/lib/hecks/bluebook/behaviour/aggregate.rb +10 -39
  51. data/lib/hecks/bluebook/behaviour/attribute.rb +3 -14
  52. data/lib/hecks/bluebook/behaviour/chapter.rb +14 -42
  53. data/lib/hecks/bluebook/behaviour/command.rb +14 -66
  54. data/lib/hecks/bluebook/behaviour/domain_port.rb +4 -20
  55. data/lib/hecks/bluebook/behaviour/entity.rb +7 -27
  56. data/lib/hecks/bluebook/behaviour/hexagon.rb +23 -41
  57. data/lib/hecks/bluebook/behaviour/lifecycle.rb +15 -40
  58. data/lib/hecks/bluebook/behaviour/policy.rb +23 -52
  59. data/lib/hecks/bluebook/behaviour/process_manager.rb +30 -57
  60. data/lib/hecks/bluebook/behaviour/read_model.rb +25 -31
  61. data/lib/hecks/bluebook/behaviour/traits.rb +27 -64
  62. data/lib/hecks/bluebook/behaviour/value_object.rb +5 -24
  63. data/lib/hecks/bluebook/capabilities.rb +17 -49
  64. data/lib/hecks/bluebook/chapter.rb +10 -48
  65. data/lib/hecks/bluebook/command.rb +23 -81
  66. data/lib/hecks/bluebook/domain_port.rb +14 -63
  67. data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +50 -229
  68. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +50 -377
  69. data/lib/hecks/bluebook/dsl/attribute_collector.rb +33 -204
  70. data/lib/hecks/bluebook/dsl/binding_proxy.rb +16 -69
  71. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +86 -708
  72. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +56 -170
  73. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +1 -0
  74. data/lib/hecks/bluebook/dsl/command_builder.rb +74 -546
  75. data/lib/hecks/bluebook/dsl/const_shim.rb +8 -41
  76. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +12 -87
  77. data/lib/hecks/bluebook/dsl/entity_builder.rb +44 -330
  78. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +20 -269
  79. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +26 -194
  80. data/lib/hecks/bluebook/dsl/identity_declaration.rb +13 -88
  81. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +6 -20
  82. data/lib/hecks/bluebook/dsl/policy_builder.rb +16 -88
  83. data/lib/hecks/bluebook/dsl/port_builder.rb +2 -6
  84. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +22 -96
  85. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +31 -184
  86. data/lib/hecks/bluebook/dsl/query_builder.rb +11 -42
  87. data/lib/hecks/bluebook/dsl/read_model_builder.rb +75 -201
  88. data/lib/hecks/bluebook/dsl/rule_reference.rb +22 -163
  89. data/lib/hecks/bluebook/dsl/translation_builder.rb +28 -114
  90. data/lib/hecks/bluebook/dsl/value_object_builder.rb +10 -124
  91. data/lib/hecks/bluebook/dsl/word_gate.rb +16 -162
  92. data/lib/hecks/bluebook/dsl/world_builder.rb +19 -111
  93. data/lib/hecks/bluebook/entity.rb +13 -71
  94. data/lib/hecks/bluebook/expression/ast_json.rb +24 -190
  95. data/lib/hecks/bluebook/expression/ast_reader.rb +12 -54
  96. data/lib/hecks/bluebook/expression/canonical_form.rb +11 -88
  97. data/lib/hecks/bluebook/expression/evaluator.rb +47 -295
  98. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +30 -147
  99. data/lib/hecks/bluebook/expression/resolver.rb +37 -660
  100. data/lib/hecks/bluebook/hexagon.rb +5 -28
  101. data/lib/hecks/bluebook/lifecycle.rb +5 -16
  102. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -7
  103. data/lib/hecks/bluebook/meta_validator/judge.rb +111 -361
  104. data/lib/hecks/bluebook/meta_validator/plan.rb +33 -162
  105. data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -7
  106. data/lib/hecks/bluebook/meta_validator/readings.rb +56 -342
  107. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +24 -176
  108. data/lib/hecks/bluebook/meta_validator/shapes.rb +53 -267
  109. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +43 -305
  110. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +7 -43
  111. data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -18
  112. data/lib/hecks/bluebook/meta_validator.rb +79 -349
  113. data/lib/hecks/bluebook/model_check/client_profile.rb +6 -21
  114. data/lib/hecks/bluebook/model_check.rb +100 -597
  115. data/lib/hecks/bluebook/pattern_subset.rb +11 -69
  116. data/lib/hecks/bluebook/process_manager.rb +13 -83
  117. data/lib/hecks/bluebook/project_loader.rb +3 -39
  118. data/lib/hecks/bluebook/project_register.rb +12 -60
  119. data/lib/hecks/bluebook/query.rb +9 -48
  120. data/lib/hecks/bluebook/read_model.rb +57 -81
  121. data/lib/hecks/bluebook/reference.rb +7 -41
  122. data/lib/hecks/bluebook/smoke_test.rb +8 -98
  123. data/lib/hecks/bluebook/synthesizer.rb +13 -62
  124. data/lib/hecks/bluebook/translation.rb +26 -62
  125. data/lib/hecks/bluebook/value_object.rb +11 -36
  126. data/lib/hecks/bluebook.rb +5 -22
  127. data/lib/hecks/cache_dir.rb +4 -23
  128. data/lib/hecks/cli/document.rb +3 -21
  129. data/lib/hecks/cli/ir.rb +3 -5
  130. data/lib/hecks/cli/mcp.rb +2 -3
  131. data/lib/hecks/cli/mcp_door.rb +19 -114
  132. data/lib/hecks/cli/model_check.rb +18 -85
  133. data/lib/hecks/cli/project_cli.rb +7 -40
  134. data/lib/hecks/cli/project_diagrams.rb +0 -7
  135. data/lib/hecks/cli/run.rb +12 -58
  136. data/lib/hecks/cli/smoke_test.rb +2 -16
  137. data/lib/hecks/cli/stores.rb +1 -2
  138. data/lib/hecks/cli.rb +18 -24
  139. data/lib/hecks/construct.rb +8 -34
  140. data/lib/hecks/deploy/bluebook/deploy.bluebook +33 -142
  141. data/lib/hecks/deploy/bluebook/deploy.hecksagon +2 -9
  142. data/lib/hecks/embryonaut_bluebook/lock.rb +3 -35
  143. data/lib/hecks/embryonaut_bluebook/shape.rb +1 -17
  144. data/lib/hecks/embryonaut_bluebook/vendor.rb +8 -53
  145. data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +4 -19
  146. data/lib/hecks/embryonaut_bluebook.rb +4 -71
  147. data/lib/hecks/facade/cli_door.rb +24 -106
  148. data/lib/hecks/facade/cli_runner.rb +28 -172
  149. data/lib/hecks/facade/command_request.rb +13 -33
  150. data/lib/hecks/facade/handle.rb +34 -121
  151. data/lib/hecks/facade/json_door.rb +31 -146
  152. data/lib/hecks/facade/surface/aggregate_door.rb +39 -104
  153. data/lib/hecks/facade/surface/chapter.rb +10 -54
  154. data/lib/hecks/facade/surface.rb +8 -23
  155. data/lib/hecks/facade.rb +10 -25
  156. data/lib/hecks/forms/app.rb +15 -70
  157. data/lib/hecks/forms/command_form_renderer.rb +10 -29
  158. data/lib/hecks/forms/field_renderer.rb +17 -156
  159. data/lib/hecks/forms/field_shape.rb +30 -222
  160. data/lib/hecks/forms/html.rb +12 -47
  161. data/lib/hecks/forms/index_renderer.rb +1 -4
  162. data/lib/hecks/forms/page.rb +3 -9
  163. data/lib/hecks/forms/params.rb +14 -60
  164. data/lib/hecks/forms/port_argument.rb +2 -19
  165. data/lib/hecks/forms/query_form_renderer.rb +4 -79
  166. data/lib/hecks/forms/record_renderer.rb +8 -75
  167. data/lib/hecks/forms/record_table.rb +7 -50
  168. data/lib/hecks/forms/reference_options.rb +3 -30
  169. data/lib/hecks/forms/value_object_shape.rb +8 -35
  170. data/lib/hecks/forms.rb +5 -33
  171. data/lib/hecks/fqn.rb +5 -12
  172. data/lib/hecks/framework/bluebook/compliance.bluebook +16 -65
  173. data/lib/hecks/framework/bluebook/console_settings.bluebook +47 -134
  174. data/lib/hecks/framework/bluebook/framework.hecksagon +5 -14
  175. data/lib/hecks/framework/bluebook/governance.bluebook +13 -34
  176. data/lib/hecks/framework/bluebook/identity.bluebook +11 -26
  177. data/lib/hecks/framework/bluebook/privacy.bluebook +8 -33
  178. data/lib/hecks/framework.rb +11 -80
  179. data/lib/hecks/freezer.rb +5 -39
  180. data/lib/hecks/grammar/expression.bluebook +15 -40
  181. data/lib/hecks/grammar/translation.bluebook +3 -6
  182. data/lib/hecks/grammar.rb +16 -41
  183. data/lib/hecks/ir.rb +14 -83
  184. data/lib/hecks/language/adapter.bluebook +2 -7
  185. data/lib/hecks/language/bluebook/aggregate.bluebook +56 -221
  186. data/lib/hecks/language/bluebook/attaches/paging.bluebook +6 -15
  187. data/lib/hecks/language/bluebook/bluebook.bluebook +15 -83
  188. data/lib/hecks/language/bluebook/bluebook.hecksagon +3 -15
  189. data/lib/hecks/language/bluebook/command.bluebook +27 -144
  190. data/lib/hecks/language/bluebook/entity.bluebook +24 -97
  191. data/lib/hecks/language/bluebook/policy.bluebook +16 -67
  192. data/lib/hecks/language/bluebook/process_manager.bluebook +28 -151
  193. data/lib/hecks/language/bluebook/projection.bluebook +126 -60
  194. data/lib/hecks/language/bluebook/query.bluebook +12 -43
  195. data/lib/hecks/language/bluebook/shape.bluebook +23 -73
  196. data/lib/hecks/language/bluebook/syntax.bluebook +51 -262
  197. data/lib/hecks/language/bluebook/vocabulary.bluebook +82 -197
  198. data/lib/hecks/language/hecksagon/adapter_binding.bluebook +3 -10
  199. data/lib/hecks/language/hecksagon/domain_port.bluebook +4 -19
  200. data/lib/hecks/language/hecksagon/hecksagon.bluebook +6 -25
  201. data/lib/hecks/language/hecksagon/port_operation.bluebook +3 -14
  202. data/lib/hecks/language/oidc.json +35 -0
  203. data/lib/hecks/language/port.bluebook +4 -17
  204. data/lib/hecks/language/translation/translation.bluebook +3 -9
  205. data/lib/hecks/language/translation/translation_aggregate.bluebook +5 -24
  206. data/lib/hecks/language/world/wiring.bluebook +1 -3
  207. data/lib/hecks/language/world/world.bluebook +5 -7
  208. data/lib/hecks/literal.rb +8 -50
  209. data/lib/hecks/mcp_door_scope.rb +9 -90
  210. data/lib/hecks/mcp_stdio_guard.rb +4 -41
  211. data/lib/hecks/naming.rb +29 -137
  212. data/lib/hecks/ports/access_control.rb +7 -23
  213. data/lib/hecks/ports/agent/answers.rb +5 -23
  214. data/lib/hecks/ports/agent.rb +47 -172
  215. data/lib/hecks/ports/authentication.rb +12 -39
  216. data/lib/hecks/ports/authorization.rb +16 -43
  217. data/lib/hecks/ports/clock.rb +5 -45
  218. data/lib/hecks/ports/extraction.rb +7 -12
  219. data/lib/hecks/ports/identity_assignment.rb +8 -29
  220. data/lib/hecks/ports/identity_generation.rb +6 -29
  221. data/lib/hecks/ports/identity_resolution.rb +2 -10
  222. data/lib/hecks/ports/key_vault.rb +9 -45
  223. data/lib/hecks/ports/persistence/append_only.rb +61 -64
  224. data/lib/hecks/ports/persistence/binding_policy.rb +4 -14
  225. data/lib/hecks/ports/persistence/codec_boundary.rb +20 -80
  226. data/lib/hecks/ports/persistence/null_saga_store.rb +4 -20
  227. data/lib/hecks/ports/persistence/plugin.rb +13 -42
  228. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +38 -141
  229. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +15 -115
  230. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +16 -84
  231. data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +6 -25
  232. data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +3 -22
  233. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +55 -181
  234. data/lib/hecks/ports/persistence/plugins/era/postgres_era/events.rb +77 -0
  235. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +12 -122
  236. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +28 -128
  237. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +73 -474
  238. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +31 -124
  239. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +45 -219
  240. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +13 -108
  241. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +18 -75
  242. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +9 -49
  243. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +6 -123
  244. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +23 -55
  245. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +14 -72
  246. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +7 -16
  247. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +14 -115
  248. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +13 -45
  249. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +127 -554
  250. data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +13 -63
  251. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +2 -17
  252. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +3 -14
  253. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +13 -58
  254. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -17
  255. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +9 -26
  256. data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +9 -25
  257. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +18 -124
  258. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +34 -123
  259. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +5 -12
  260. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +3 -9
  261. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -14
  262. data/lib/hecks/ports/persistence/plugins/era.rb +4 -23
  263. data/lib/hecks/ports/persistence/postgres_dump/connection.rb +7 -23
  264. data/lib/hecks/ports/persistence/postgres_dump.rb +4 -35
  265. data/lib/hecks/ports/persistence/remote_runtime.rb +2 -24
  266. data/lib/hecks/ports/persistence/repository_factory.rb +8 -27
  267. data/lib/hecks/ports/persistence/state_codec.rb +23 -103
  268. data/lib/hecks/ports/persistence.rb +7 -14
  269. data/lib/hecks/ports/projection.rb +42 -84
  270. data/lib/hecks/ports/query/in_memory.rb +10 -58
  271. data/lib/hecks/ports/query/ordering.rb +11 -32
  272. data/lib/hecks/ports/query.rb +14 -37
  273. data/lib/hecks/ports.rb +2 -8
  274. data/lib/hecks/projections/bootstrap_table.rb +11 -43
  275. data/lib/hecks/projections/deploy/fargate/assembly.rb +2 -15
  276. data/lib/hecks/projections/deploy/fargate/cdn.rb +1 -48
  277. data/lib/hecks/projections/deploy/fargate/cdn_default.rb +2 -11
  278. data/lib/hecks/projections/deploy/fargate/check.rb +5 -14
  279. data/lib/hecks/projections/deploy/fargate/containers.rb +3 -78
  280. data/lib/hecks/projections/deploy/fargate/extras.rb +3 -44
  281. data/lib/hecks/projections/deploy/fargate/monitoring.rb +0 -44
  282. data/lib/hecks/projections/deploy/fargate/settings.rb +2 -54
  283. data/lib/hecks/projections/deploy/fargate/yaml.rb +13 -58
  284. data/lib/hecks/projections/deploy/fargate.rb +35 -202
  285. data/lib/hecks/projections/deploy/lambda.rb +150 -678
  286. data/lib/hecks/projections/deploy/preview/access_yaml.rb +1 -33
  287. data/lib/hecks/projections/deploy/preview/containers.rb +6 -111
  288. data/lib/hecks/projections/deploy/preview/routing_yaml.rb +4 -56
  289. data/lib/hecks/projections/deploy/preview/script.rb +2 -14
  290. data/lib/hecks/projections/deploy/preview/settings.rb +3 -33
  291. data/lib/hecks/projections/deploy/preview/task_yaml.rb +2 -38
  292. data/lib/hecks/projections/deploy/preview/template.rb +2 -58
  293. data/lib/hecks/projections/deploy/preview.rb +2 -67
  294. data/lib/hecks/projections/deploy/scripts/settings.rb +3 -25
  295. data/lib/hecks/projections/deploy/scripts.rb +4 -57
  296. data/lib/hecks/projections/deploy/shared.rb +47 -146
  297. data/lib/hecks/projections/deploy/smoke.rb +4 -61
  298. data/lib/hecks/projections/deploy/template_diff/comparer.rb +3 -25
  299. data/lib/hecks/projections/deploy/template_diff/loader.rb +2 -11
  300. data/lib/hecks/projections/deploy/template_diff.rb +5 -57
  301. data/lib/hecks/projections/diagrams.rb +20 -582
  302. data/lib/hecks/projections/glossary/html.rb +14 -130
  303. data/lib/hecks/projections/glossary/markdown.rb +8 -69
  304. data/lib/hecks/projections/glossary/mermaid.rb +9 -66
  305. data/lib/hecks/projections/glossary/sensitivity.rb +5 -34
  306. data/lib/hecks/projections/glossary/sentences.rb +14 -159
  307. data/lib/hecks/projections/glossary.rb +30 -222
  308. data/lib/hecks/projections/ir.rb +3 -10
  309. data/lib/hecks/projections/model/deviations.rb +15 -42
  310. data/lib/hecks/projections/model.rb +12 -51
  311. data/lib/hecks/projections/oidc.rb +12 -56
  312. data/lib/hecks/projections/parser_table.rb +9 -28
  313. data/lib/hecks/projections/reference.rb +2 -15
  314. data/lib/hecks/projections/rust_vocabulary.rb +12 -250
  315. data/lib/hecks/projections/shape.rb +3 -29
  316. data/lib/hecks/projections/statements.rb +7 -86
  317. data/lib/hecks/projections/vocabulary.rb +6 -22
  318. data/lib/hecks/projections.rb +2 -16
  319. data/lib/hecks/projector/cli_projector.rb +60 -375
  320. data/lib/hecks/projector/docs_projector.rb +10 -201
  321. data/lib/hecks/projector/exporter.rb +42 -134
  322. data/lib/hecks/projector/ir_projector.rb +2 -9
  323. data/lib/hecks/projector/narrate_projector.rb +15 -189
  324. data/lib/hecks/projector/target.rb +13 -76
  325. data/lib/hecks/projector.rb +30 -121
  326. data/lib/hecks/query_specification/common/comparators.rb +5 -26
  327. data/lib/hecks/query_specification/common/comparison.rb +35 -143
  328. data/lib/hecks/query_specification/common/dsl.rb +8 -24
  329. data/lib/hecks/query_specification/common/null_policy.rb +20 -70
  330. data/lib/hecks/query_specification/common/options.rb +2 -6
  331. data/lib/hecks/query_specification/common/where_clause.rb +2 -10
  332. data/lib/hecks/query_specification/field_path.rb +37 -77
  333. data/lib/hecks/query_specification/hop_path.rb +12 -76
  334. data/lib/hecks/release/gem_pin.rb +2 -26
  335. data/lib/hecks/release/runner/ci_publisher.rb +3 -6
  336. data/lib/hecks/release/runner/commands.rb +2 -4
  337. data/lib/hecks/release/runner/gem_publisher.rb +2 -3
  338. data/lib/hecks/release/runner/npm_publisher.rb +6 -20
  339. data/lib/hecks/release/runner/preflight.rb +4 -19
  340. data/lib/hecks/release/runner/tagger.rb +2 -9
  341. data/lib/hecks/release/runner.rb +3 -32
  342. data/lib/hecks/rendering.rb +4 -26
  343. data/lib/hecks/router/namespace_installer.rb +12 -36
  344. data/lib/hecks/router.rb +4 -8
  345. data/lib/hecks/runtime/aggregate_lock.rb +8 -33
  346. data/lib/hecks/runtime/boot_gates.rb +3 -18
  347. data/lib/hecks/runtime/caller.rb +19 -59
  348. data/lib/hecks/runtime/capability_graph.rb +5 -21
  349. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +16 -78
  350. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +23 -160
  351. data/lib/hecks/runtime/command_interpreter.rb +124 -306
  352. data/lib/hecks/runtime/command_rules/admissibility.rb +95 -366
  353. data/lib/hecks/runtime/command_rules/arithmetic.rb +66 -196
  354. data/lib/hecks/runtime/command_rules/authorization.rb +13 -45
  355. data/lib/hecks/runtime/command_rules/emission.rb +8 -21
  356. data/lib/hecks/runtime/command_rules/references.rb +23 -202
  357. data/lib/hecks/runtime/dependency_planning.rb +30 -102
  358. data/lib/hecks/runtime/dispatcher.rb +82 -241
  359. data/lib/hecks/runtime/entity_element.rb +40 -462
  360. data/lib/hecks/runtime/entity_interpreter.rb +64 -219
  361. data/lib/hecks/runtime/errors.rb +32 -115
  362. data/lib/hecks/runtime/event.rb +3 -25
  363. data/lib/hecks/runtime/identity.rb +18 -154
  364. data/lib/hecks/runtime/instance.rb +18 -150
  365. data/lib/hecks/runtime/interpreting.rb +11 -70
  366. data/lib/hecks/runtime/invocation.rb +28 -164
  367. data/lib/hecks/runtime/loader.rb +48 -186
  368. data/lib/hecks/runtime/outbox.rb +38 -261
  369. data/lib/hecks/runtime/policy_interpreter.rb +38 -200
  370. data/lib/hecks/runtime/port_operation_interpreter.rb +26 -87
  371. data/lib/hecks/runtime/query_interpreter.rb +45 -187
  372. data/lib/hecks/runtime/reaction_invocation.rb +36 -138
  373. data/lib/hecks/runtime/read_model_interpreter.rb +117 -208
  374. data/lib/hecks/runtime/rebuild_sweep.rb +8 -54
  375. data/lib/hecks/runtime/reference_hop.rb +8 -81
  376. data/lib/hecks/runtime/refusal_wording.rb +8 -89
  377. data/lib/hecks/runtime/registry/saga_persistence.rb +10 -102
  378. data/lib/hecks/runtime/registry/verification.rb +52 -225
  379. data/lib/hecks/runtime/registry/world_defaults.rb +4 -53
  380. data/lib/hecks/runtime/registry.rb +99 -244
  381. data/lib/hecks/runtime/remote_dispatcher.rb +37 -152
  382. data/lib/hecks/runtime/routing.rb +4 -15
  383. data/lib/hecks/runtime/saga_interpreter/correlation.rb +14 -61
  384. data/lib/hecks/runtime/saga_interpreter.rb +79 -263
  385. data/lib/hecks/runtime/saga_pending_dispatch.rb +2 -43
  386. data/lib/hecks/runtime/tenant_check.rb +6 -68
  387. data/lib/hecks/runtime/tenant_scope.rb +3 -28
  388. data/lib/hecks/runtime/value/admission.rb +16 -67
  389. data/lib/hecks/runtime/value/coercion.rb +155 -641
  390. data/lib/hecks/runtime/value/entity_list_coercion.rb +26 -219
  391. data/lib/hecks/runtime/value.rb +12 -84
  392. data/lib/hecks/runtime.rb +17 -65
  393. data/lib/hecks/storehouse.rb +141 -568
  394. data/lib/hecks/tenancy/bluebook/tenancy.bluebook +8 -32
  395. data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +6 -23
  396. data/lib/hecks/vendoring/git_environment.rb +2 -8
  397. data/lib/hecks/vendoring/git_source.rb +4 -10
  398. data/lib/hecks/vendoring.rb +7 -46
  399. data/lib/hecks/version.rb +3 -14
  400. data/lib/hecks.rb +26 -81
  401. data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +8 -46
  402. data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +11 -80
  403. data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +10 -99
  404. metadata +3 -2
@@ -5,48 +5,25 @@ module Hecks
5
5
  module Bluebook
6
6
  Invariant = Struct.new(:description, :canonical, :predicate, :ast, keyword_init: true)
7
7
 
8
- # A value object — a declaration holder, never instantiated.
9
- #
10
- # `ValueObjectBuilder` returns an anonymous subclass whose singleton
11
- # carries the declaration : attributes, invariants, members. Nothing ever
12
- # calls `.new` on one — coercion builds `Runtime::Value` wrappers, and
13
- # invariants run as canonical text through the Evaluator. The runtime
14
- # reaches a shape through `aggregate.value_object(name)`, the IR's own
15
- # finder ; there is no constant nesting and no second index.
16
- #
17
- # `to_h` does not move. It is a byte-for-byte contract pinned by the
18
- # golden fixtures, so it keeps spelling the short declared name, which
19
- # is what `hecks_name` carries. Declarations in the graph, strings in the
20
- # export.
8
+ # A value object: a declaration holder, never instantiated.
9
+ # `ValueObjectBuilder` returns a subclass carrying attributes, invariants and members;
10
+ # reach one through `aggregate.value_object(name)`.
11
+ # `to_h` spells the short declared name (`hecks_name`), a contract pinned by golden fixtures.
21
12
  class ValueObject
22
13
  extend Construct
23
- # Extended, not included — this construct is a class, so its
24
- # emission is a class method. See Hecks::IR's own note on
25
- # the two shapes.
14
+ # Extended, not included: this construct is a class, so emission is a class method.
26
15
  extend Hecks::IR
27
16
  extend Behaviour::ValueObject
28
17
 
29
18
  emits_ir(
30
19
  name: :hecks_name,
31
20
  attributes: many(:attributes),
32
- # `ast:` — a JSON-serializable rendering of the same predicate
33
- # `canonical` already spells as text, alongside it rather than
34
- # replacing it (`canonical` stays the human-facing/doctest-facing
35
- # form; parsing it back would just re-derive what `ast` already
36
- # states directly). Ground truth and the full reasoning:
37
- # `Expression::AstJson`'s own header — built for `rust/host`'s
38
- # own mint-time invariant check (`reference_validate.rs`), which
39
- # has no kernel crate to parse `canonical` with.
21
+ # `ast` sits beside `canonical` because rust/host's mint-time invariant check
22
+ # has no kernel crate to parse `canonical` with (see `Expression::AstJson`).
40
23
  invariants: -> { invariants.map { |rule| Expression::AstJson.rule_row(rule) } },
41
24
  closed_set: :closed_set?,
42
- # The field name is stringified, never the value. A `member` row can
43
- # hold any of the scalar types an attribute declares — `Integer 84`
44
- # (`StatementFrequency#retention_months`, statements.bluebook), not
45
- # only `String` — and stringifying it on the way out would erase
46
- # that: `84` and `"84"` (a member some other row might legitimately
47
- # spell as text) would become indistinguishable once they reached
48
- # `to_h`. The declared name still moves (`field.to_s`) — that half
49
- # was never a Ruby object with a type to lose.
25
+ # Only the field name is stringified: a member value can be an Integer, and
26
+ # stringifying it would make `84` and `"84"` indistinguishable in `to_h`.
50
27
  members: -> { members.map { |member| member.map { |field, value| [field.to_s, value] } } }
51
28
  )
52
29
 
@@ -57,10 +34,8 @@ module Hecks
57
34
  # the bluebook declares and the thing Ruby holds are one object.
58
35
  #
59
36
  # @param name [String, Symbol] the value object's declared type name
60
- # @param attributes [Array<Bluebook::Attribute>] the value object's declared
61
- # fields
62
- # @param invariants [Array<Bluebook::Invariant>] the rules checked against every
63
- # instance of this value object
37
+ # @param attributes [Array<Bluebook::Attribute>] the value object's declared fields
38
+ # @param invariants [Array<Bluebook::Invariant>] the rules checked against every instance
64
39
  # @param members [Array<Hash{Symbol => Object}>] the declared `one_of` members, one
65
40
  # row of field values per member
66
41
  # @param closed_set [Boolean] whether a `one_of` was declared, even with no
@@ -1,36 +1,19 @@
1
- # Hecks::Bluebook
2
- #
3
- # Everything a .bluebook file becomes on its way to running: the expression
4
- # language (expression/), the model itself (the chapter class plus
5
- # everything it declares), the assembly that turns
6
- # declarations back into that graph (assembly.rb + assembly/), the authoring
7
- # DSL (dsl/), and the meta-validator that judges a chapter against the
8
- # language's own grammar (meta_validator.rb + meta_validator/).
9
- #
10
- # The require order below matters: expression and IR load first (pure
11
- # declarations), assembly's collaborators load before its face, and the DSL
12
- # loads before the meta-validator that its builders call at build time.
1
+ # Everything a .bluebook file becomes on its way to running: expression language, model,
2
+ # assembly, authoring DSL and meta-validator.
13
3
 
14
4
  module Hecks
15
- # Declared as a class, not a module — `Hecks::Bluebook` is a
16
- # chapter (bluebook/chapter.rb carries its body). Everything a chapter
17
- # declares nests under it, as do the ways to build one (`DSL`) and to
18
- # judge one (`MetaValidator`). Reopening this anywhere must say `class`.
5
+ # `Hecks::Bluebook` is a class defined in bluebook/chapter.rb; reopen it with `class`.
19
6
  module Bluebook
20
7
  end
21
8
  end
22
9
 
23
- # What the chapter's own files lean on at class-body level (`extend
24
- # Construct`, the assembly's QuerySpecification marks) — required here
25
- # because those files' contents are frozen and cannot say so themselves.
10
+ # Required here because the chapter's frozen files lean on these at class-body level.
11
+ # Load order: expression and IR first, assembly's collaborators before its face, DSL last.
26
12
  require_relative "construct"
27
13
  require_relative "literal"
28
14
  require_relative "query_specification"
29
15
 
30
16
  require_relative "bluebook/expression"
31
- # **The model itself** — the chapter class's own body first, then everything
32
- # a chapter declares. Order matters only for reading: each is a bag of
33
- # declarations with no load-time cross-references.
34
17
  require_relative "bluebook/chapter"
35
18
  require_relative "bluebook/reference"
36
19
  require_relative "bluebook/attribute"
@@ -3,30 +3,11 @@ require "fileutils"
3
3
  require "tmpdir"
4
4
 
5
5
  module Hecks
6
- # The one place the runtime's own scratch files live, outside the gem.
6
+ # The one place the runtime's own scratch files live, outside the gem: an
7
+ # installed gem is read-only, and a checkout's `tmp/` isn't this library's to assume.
7
8
  #
8
- # The syntax-boot cache and the Storehouse audit log are written on a
9
- # normal run, so they cannot sit under the gem's own directory: an
10
- # installed gem is read-only, and a checkout's `tmp/` is not a place a
11
- # library gets to assume. Both ask this module for a subdirectory instead.
12
- #
13
- # ## Where the root is
14
- #
15
- # The first of these that can be made a private directory wins:
16
- #
17
- # 1. `$XDG_CACHE_HOME/hecks`, when `XDG_CACHE_HOME` is set to an absolute path
18
- # 2. `~/.cache/hecks`
19
- # 3. `<system temp dir>/hecks-<uid>`
20
- #
21
- # ## Private, or not used
22
- #
23
- # The syntax-boot cache is read back with `Marshal.load`, so a directory
24
- # another account can write to is a way to run code as this one. A
25
- # candidate is accepted only if it is owned by the current user and
26
- # writable by nobody else; the shared temp directory in particular is
27
- # where a predictable name can be planted by someone else. When no candidate
28
- # qualifies, a fresh per-process directory stands in: the cache still
29
- # works within the process and is never shared with a stranger.
9
+ # A candidate root is used only if it is private to the current user, since the
10
+ # syntax-boot cache it holds is read back with `Marshal.load`.
30
11
  module CacheDir
31
12
  module_function
32
13
 
@@ -5,23 +5,7 @@ module Hecks
5
5
  # The command behind `bin/docs`, `bin/narrate`, `hecks docs` and `hecks narrate`:
6
6
  # one domain's document, projected from its own bluebook, to stdout.
7
7
  #
8
- # `:docs` answers the usage document a console's `<Domain>.docs` prints; `:narrate`
9
- # answers the same chapter read back in English, for the subject-matter expert
10
- # (`Projector::NarrateProjector`). Nothing is written for the caller: redirect it,
11
- # so the caller decides where a generated file lands and git decides whether it
12
- # drifted.
13
- #
14
- # ## Every failure is a sentence
15
- #
16
- # A misspelled aggregate refuses by name rather than printing nothing and exiting
17
- # 0. A caller cannot tell an empty document from an empty domain, so this refuses
18
- # instead and names what is actually there.
19
- #
20
- # ## Standing in a domain is enough
21
- #
22
- # `Adapters::Folder#domain_root` walks up for the nearest `.hecksagon`, which makes
23
- # the first argument ambiguous. The rule: a directory is a domain, anything else
24
- # is an aggregate name, and the two-argument form says which is which.
8
+ # Nothing is written for the caller: redirect it, so git decides whether it drifted.
25
9
  module Document
26
10
  # Build output and other trees under a root that hold no domain a caller means.
27
11
  # Matched against the path relative to the root, because a substring test
@@ -66,10 +50,8 @@ module Hecks
66
50
 
67
51
  # Lists every directory under `root` that `Hecks.boot` would accept.
68
52
  #
69
- # Found by their wiring, not their chapters: a `.hecksagon` is what says "this
70
- # is a domain, and here is how its aggregates are stored", while most
71
- # `.bluebook` files (era translations, the language's own grammar,
72
- # `spec/fixtures`) are not domains anybody boots.
53
+ # Found by their wiring, not their chapters: a `.hecksagon` says this is a
54
+ # domain, while most `.bluebook` files (era translations, grammar, fixtures) are not.
73
55
  #
74
56
  # @param root [String] the directory to search under
75
57
  # @return [Array<String>] domain directory paths relative to `root`,
data/lib/hecks/cli/ir.rb CHANGED
@@ -6,17 +6,15 @@ require_relative "../ports/persistence/plugins/era"
6
6
  module Hecks
7
7
  module CLI
8
8
  # The command behind `bin/ir` and `hecks ir`: a booted domain's IR as JSON, the
9
- # same `to_h` the golden specs pin and `StorageShape` hashes into an era, for
10
- # reading rather than asserting on.
9
+ # same `to_h` the golden specs pin and `StorageShape` hashes into an era.
11
10
  module Ir
12
11
  module_function
13
12
 
14
13
  # Prints the IR `argv` asks for.
15
14
  #
16
- # `--meta` prints the language's own IR, the chapters under
17
- # `lib/hecks/language/bluebook/` merged into one. It is reached through
15
+ # `--meta` prints the language's own IR, reached through
18
16
  # `Bluebook::MetaValidator.grammar_registry`, the real boot sequence, so it
19
- # cannot drift from what `MetaValidator` itself loads.
17
+ # can't drift from what `MetaValidator` loads.
20
18
  #
21
19
  # @param argv [Array<String>] a domain path and `--translations`, or `--meta`
22
20
  # @param program [String] the name the usage message calls this command by
data/lib/hecks/cli/mcp.rb CHANGED
@@ -5,9 +5,8 @@ module Hecks
5
5
  # The command behind `bin/hecks_mcp_door` and `hecks mcp`: the MCP door onto the
6
6
  # storehouse bus, over stdio only.
7
7
  #
8
- # This file loads nothing but `McpStdioGuard`, so the transport check runs before
9
- # the framework does. The door itself is `McpDoor`, required only once the check
10
- # passes.
8
+ # This file loads nothing but `McpStdioGuard`, so the transport check runs
9
+ # before the framework does.
11
10
  module Mcp
12
11
  # The server name the guard's refusals and warnings carry.
13
12
  SERVER = "hecks-mcp-door".freeze
@@ -4,56 +4,17 @@ require_relative "mcp"
4
4
 
5
5
  module Hecks
6
6
  module CLI
7
- # The MCP door onto the storehouse bus: one MCP server for every booted domain,
8
- # not one per command, hand-rolled JSON-RPC over stdio (newline-delimited JSON,
9
- # flushed after every write, no gem dependency).
7
+ # The MCP door onto the storehouse bus: hand-rolled JSON-RPC over stdio, one
8
+ # server per booted domain. All logic and the JSON shape answered with live in
9
+ # `Storehouse`; this is plumbing only. A `role:`/`actor_id:` a caller sends is
10
+ # asserted, not verified, unless Governance is attached.
10
11
  #
11
- # ## Plumbing only
12
- #
13
- # All the logic and the JSON shape it answers with live in `Storehouse`, the bus
14
- # itself, transport-blind. A door of another shape (a plain CLI, an HTTP door)
15
- # would sit beside this one, calling `Storehouse` the same way and sharing its
16
- # audit log and caller-identity handling.
17
- #
18
- # ## Identity is asserted, not verified
19
- #
20
- # `dispatch` and `query` take `role:` and `actor_id:`, bound for the call through
21
- # `Hecks.as_caller`, so a role-gated command is checked against them rather than
22
- # merely documented by `describe`; `dispatch` refuses a role-declaring command
23
- # called without one. Nothing here verifies the claim beyond the string (or, with
24
- # Governance attached, a `Governance::RoleAssignment` lookup). The readers take
25
- # no role, and `query` gates on none.
26
- #
27
- # ## Stdio only, enforced
28
- #
29
- # The door has no authentication. `Mcp.call` runs
30
- # `McpStdioGuard.enforce_stdio!` before this file loads, and `serve` prints the
31
- # warning to stderr, never stdout, which carries the protocol. `domain:` is
32
- # confined to `Storehouse::BOOT_ROOT` (`confine!`), but a domain within that
33
- # root still boots real Ruby, so this is a code execution surface for anyone who
34
- # can write to stdin. A network transport needs authentication first; see
35
- # `docs/decisions/0062-mcp-servers-need-real-authentication-before-any-network-transport.md`.
36
- #
37
- # ## Reader mode
38
- #
39
- # Whoever spawns the door can narrow it with `HECKS_DOOR_TOOLS=readers` and
40
- # `HECKS_DOOR_DOMAINS=<dir>[:<dir>...]` (`Hecks::McpDoorScope`, ADR 0072 decision 2).
41
- # A reader door serves only `McpDoorScope::READER_TOOLS` (`query`, `events`,
42
- # `state`, `catalog`, `describe`, `validate`, `domains`, `history`, `follow`), lists
43
- # only those in `tools/list`, and refuses `dispatch` (so `dry_run` and `steps` too),
44
- # `behaviors` and any other name with an answer that names the mode. Its `domain:`
45
- # must resolve to one of the named directories, checked before anything boots, so no
46
- # other domain's Ruby is loaded. The door keeps no domain loaded between calls, so
47
- # the named list is the whole allowed set. This limits what one spawned agent can
48
- # reach; it identifies no one and is not authentication. The names sit outside
49
- # `HECKS_MCP_*` because the stdio guard refuses every name in that prefix but the
50
- # transport, and that refusal belongs to ADR 0062. With neither variable set, the
51
- # door serves every tool as described above.
52
- #
53
- # ## One boot per call
54
- #
55
- # `Hecks.boot(domain, install_facade: false)` is cheap, and it lets one server
56
- # answer calls against two domains back to back with no shared, staling state.
12
+ # There is no authentication: `domain:` boots real Ruby confined to
13
+ # `Storehouse::BOOT_ROOT`, so this is a code execution surface for anyone who
14
+ # can write to stdin (ADR 0062). Spawning with `HECKS_DOOR_TOOLS=readers` and
15
+ # `HECKS_DOOR_DOMAINS=<dir>[:<dir>...]` narrows a door to read-only tools and
16
+ # named domains (`McpDoorScope`); this limits what one agent can reach and is
17
+ # not itself authentication.
57
18
  module McpDoor
58
19
  PROTOCOL_VERSION = "2024-11-05".freeze
59
20
 
@@ -271,27 +232,17 @@ module Hecks
271
232
 
272
233
  module_function
273
234
 
274
- # The scope this door was spawned with: every tool and any domain, or a reader
275
- # door narrowed by `HECKS_DOOR_TOOLS`/`HECKS_DOOR_DOMAINS`. Read once, on first use,
276
- # so a bad setting refuses to start the door before anything is written to stdout.
277
- #
278
- # @return [McpDoorScope]
235
+ # Read once, so a bad setting refuses to start the door before anything is
236
+ # written to stdout.
279
237
  def scope
280
238
  @scope ||= McpDoorScope.start!(server: Mcp::SERVER)
281
239
  end
282
240
 
283
- # The notes the stdio warning carries: the standing ones, then what this door's
284
- # scope says about `domain:`.
285
- #
286
- # @return [Array<String>]
241
+ # The standing notes, then what this door's scope says about `domain:`.
287
242
  def warning_notes
288
243
  NOTES[0, 2] + (scope.restricted? ? scope.notes : [NOTES[2]])
289
244
  end
290
245
 
291
- # Prints the stdio warning to stderr, then answers one JSON-RPC request per
292
- # line of `$stdin` until it closes.
293
- #
294
- # @return [void]
295
246
  def serve
296
247
  McpStdioGuard.warn!(server: Mcp::SERVER, notes: warning_notes)
297
248
  $stdout.sync = true
@@ -315,29 +266,14 @@ module Hecks
315
266
  end
316
267
  end
317
268
 
318
- # Boots one domain for a single call, confined to `Storehouse::BOOT_ROOT`.
319
- #
320
- # @param domain [String] the domain directory, e.g. `"examples/banking"`
321
- # @return [Runtime::Dispatcher, Runtime::RemoteDispatcher] the booted domain
322
- # @raise [Runtime::TypeMismatch] if `domain` resolves outside `Storehouse::BOOT_ROOT`, or,
323
- # on a reader door, outside `HECKS_DOOR_DOMAINS`
324
- # @raise [Runtime::WiringError] if the domain fails to boot
269
+ # `domain:` is confined to `Storehouse::BOOT_ROOT`, and further to a reader
270
+ # door's `HECKS_DOOR_DOMAINS`, before anything boots.
325
271
  def boot(domain)
326
272
  Hecks.boot(Storehouse.confine!(scope.admit_domain!(domain), "domain"), install_facade: false)
327
273
  end
328
274
 
329
- # Runs one registered MCP tool by delegating to the matching `Storehouse` call.
330
- #
331
- # A closed-set dispatch table, one `when` per tool, so the size is the tool
332
- # count and the shared `rescue` catches every branch's escape once.
333
- #
334
- # @param name [String] the tool name, one of `TOOLS`'s own `:name` values
335
- # @param args [Hash{String => Object}] the tool's JSON arguments, shaped per that
336
- # tool's `inputSchema`
337
- # @return [Hash{Symbol => Object}] the delegated `Storehouse` result on a known
338
- # tool name; `{ok: false, error: String}` for an unknown tool name or any
339
- # `StandardError` this door did not anticipate (a domain refusal is already
340
- # `{ok: false, ...}` from inside `Storehouse` itself)
275
+ # One `when` per tool, so the shared `rescue` catches every branch's escape
276
+ # once; a domain refusal is already `{ok: false, ...}` from `Storehouse`.
341
277
  def call_tool(name, args) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
342
278
  case name
343
279
  when "dispatch"
@@ -378,60 +314,29 @@ module Hecks
378
314
  { ok: false, error: "no such tool: #{name.inspect} — known: #{TOOLS.map { |t| t[:name] }.join(', ')}" }
379
315
  end
380
316
  rescue StandardError => e
381
- # **A defect, not a refusal** — every domain refusal is already answered as
382
- # `{ok: false, error: "..."}` inside `Storehouse`. Reaching here means a bad
383
- # domain path or an argument shape `Facade::JsonDoor` could not symbolize,
384
- # still answered as structured content rather than an MCP-level `isError`,
385
- # so a calling agent reads one shape for every outcome.
317
+ # A defect, not a refusal: reaching here means a bad domain path or an
318
+ # argument shape `Facade::JsonDoor` could not symbolize.
386
319
  { ok: false, error: "#{e.class}: #{e.message}" }
387
320
  end
388
321
 
389
- # Runs one MCP tool call if this door's mode serves it, and refuses it otherwise.
390
- #
391
- # @param name [String] the tool name from the `tools/call` request
392
- # @param args [Hash{String => Object}] the tool's JSON arguments
393
- # @return [Hash{Symbol => Object}] the `call_tool` result, or `scope.refusal(name)`
394
- # when a reader door does not serve `name`
395
322
  def answer_tool(name, args)
396
323
  return scope.refusal(name) unless scope.permits_tool?(name)
397
324
 
398
325
  call_tool(name, args)
399
326
  end
400
327
 
401
- # Wraps a `call_tool` payload in the MCP `tools/call` result shape.
402
- #
403
- # @param payload [Hash{Symbol => Object}] a `call_tool` result
404
- # @return [Hash{Symbol => Object}] `{content: [{type: "text", text: ...}], isError: Boolean}`,
405
- # pretty-printing `payload` as the text and setting `isError` from `payload[:ok]`
406
328
  def tool_result(payload)
407
329
  { content: [{ type: "text", text: JSON.pretty_generate(payload) }], isError: payload[:ok] == false }
408
330
  end
409
331
 
410
- # Writes one JSON-RPC success response line to stdout.
411
- #
412
- # @param id [String, Integer, nil] the request's own `id`, echoed back
413
- # @param result [Object] the JSON-serializable result payload
414
- # @return [void]
415
332
  def send_response(id, result)
416
333
  puts JSON.generate({ jsonrpc: "2.0", id: id, result: result })
417
334
  end
418
335
 
419
- # Writes one JSON-RPC error response line to stdout.
420
- #
421
- # @param id [String, Integer, nil] the request's own `id`, echoed back; nil when
422
- # the request itself could not be parsed
423
- # @param code [Integer] the JSON-RPC error code
424
- # @param message [String] the error message
425
- # @return [void]
426
336
  def send_error(id, code, message)
427
337
  puts JSON.generate({ jsonrpc: "2.0", id: id, error: { code: code, message: message } })
428
338
  end
429
339
 
430
- # Dispatches one parsed JSON-RPC request to its method and writes the response.
431
- #
432
- # @param request [Hash{String => Object}] one parsed JSON-RPC request, with
433
- # `"id"`, `"method"`, and optional `"params"`
434
- # @return [void]
435
340
  def handle(request)
436
341
  id = request["id"]
437
342
  method = request["method"]
@@ -5,26 +5,13 @@ module Hecks
5
5
  module CLI
6
6
  # The command behind `bin/model_check` and `hecks model_check`: static analysis
7
7
  # over the IR, printed per domain, exiting non-zero when any error-severity
8
- # finding is left.
8
+ # finding is left — unreachable lifecycle states, dead transitions, unreached
9
+ # saga states, dispatches to a nonexistent command, handlers for an event
10
+ # nothing emits. The runtime checks none of these; a dead transition never
11
+ # fires, in silence.
9
12
  #
10
- # It finds unreachable lifecycle states, transitions nothing can fire, saga
11
- # states no handler chain reaches, a compensation whose `from_state` is
12
- # unreachable, dispatches to a command that does not exist, and handlers
13
- # listening for an event nothing emits. The runtime checks none of these: a dead
14
- # transition never fires, in silence.
15
- #
16
- # ## Named domains, or the whole corpus
17
- #
18
- # Given domain paths, it boots each and runs one cross-domain check across all
19
- # of them. Given none, it sweeps the repository's corpus (`Corpus.model_check_members`)
20
- # and the language's own chapters; that needs `root:`, the repository, so an
21
- # installed gem without one asks for a domain path instead.
22
- #
23
- # ## Options
24
- #
25
- # `--strict` makes a `rust_reserved_name` finding an error for every target, not
26
- # only for those with a Cargo feature under `root`'s `rust/Cargo.toml`.
27
- # `--profile client` adds `Bluebook::ModelCheck::ClientProfile`'s error findings.
13
+ # Given domain paths it checks just those, cross-domain; given none it sweeps
14
+ # the repository's corpus and the language's own chapters, which needs `root:`.
28
15
  module ModelCheck
29
16
  # The directory the framework's own `.port` and `.adapter` files live under.
30
17
  HECKS_DIR = File.expand_path("..", __dir__)
@@ -64,10 +51,6 @@ module Hecks
64
51
  exit(ok ? 0 : 1)
65
52
  end
66
53
 
67
- # Reads `--profile client` or `--profile=client` and removes it from `argv`.
68
- #
69
- # @param argv [Array<String>] the arguments, changed in place
70
- # @return [Symbol, nil] the requested profile, or nil when none was asked for
71
54
  def take_profile(argv)
72
55
  inline = argv.find { |arg| arg.start_with?("--profile=") }
73
56
  index = argv.index("--profile")
@@ -79,13 +62,8 @@ module Hecks
79
62
  name.to_sym
80
63
  end
81
64
 
82
- # Boots each named domain and examines them against one shared set of known
83
- # domains and emitted events, so a cross-domain reaction between two of them
84
- # is checked.
85
- #
86
- # @param domain_args [Array<String>] domain directory paths
87
- # @param options [Options] the run's configuration
88
- # @return [Boolean] true when every domain passes
65
+ # Examines every named domain against one shared set of known domains and
66
+ # emitted events, so a cross-domain reaction between two of them is checked.
89
67
  def check_domains(domain_args, options)
90
68
  booted = domain_args.map do |domain_arg|
91
69
  [File.basename(domain_arg.chomp("/")), boot(bluebook_dir(domain_arg.chomp("/")) || domain_arg)]
@@ -93,15 +71,8 @@ module Hecks
93
71
  examine_all(booted, options)
94
72
  end
95
73
 
96
- # Boots every corpus member once, then examines each against the set of names
97
- # every member declares, then examines the language itself.
98
- #
99
74
  # Two passes over the same boots, because a single boot's own registry cannot
100
75
  # answer whether a target domain exists anywhere in the corpus.
101
- #
102
- # @param root [String] the repository root
103
- # @param options [Options] the run's configuration
104
- # @return [Boolean] true when every member and the language pass
105
76
  def check_corpus(root, options)
106
77
  require_relative "../corpus"
107
78
  targets = Corpus.model_check_members(root: root).map { |member| [member.stem, Corpus.source_of(member)] }
@@ -110,17 +81,8 @@ module Hecks
110
81
  examine_language(options) && ok
111
82
  end
112
83
 
113
- # Boots one source into a fresh registry, with its sibling hecksagons so a
114
- # policy bound from there is visible too.
115
- #
116
- # `root:` is the source's parent: a directory source is already the domain's
117
- # own `bluebook/` folder, and without a root a member declaring
118
- # `uses_embryonaut_bluebook` refuses with "needs a registry with a root to
119
- # vendor from".
120
- #
121
- # @param source [String] a directory to boot (every bluebook within), or a
122
- # single `.bluebook` file path
123
- # @return [Runtime::Registry] the registry populated with the booted bluebooks
84
+ # `root:` is the source's parent, so a member declaring
85
+ # `uses_embryonaut_bluebook` can vendor from it.
124
86
  def boot(source)
125
87
  root = File.directory?(source) ? File.dirname(source) : nil
126
88
  registry = Runtime::Registry.new(root: root)
@@ -142,10 +104,8 @@ module Hecks
142
104
  end
143
105
 
144
106
  # A port attaches to its aggregate from the hecksagon, not the bluebook, so a
145
- # deaf-policy check that never loads it would see a policy reacting to an
146
- # event nothing appears to emit. A directory loads every `*.hecksagon` in it,
147
- # as a real boot does. Recording a bind builds IR only, so no adapter needs to
148
- # resolve here.
107
+ # deaf-policy check that skipped it would miss a policy reacting to an event
108
+ # nothing emits. Recording a bind builds IR only; no adapter resolves here.
149
109
  hecksagons = if File.directory?(source)
150
110
  Dir.glob(File.join(source, "*.hecksagon"))
151
111
  else
@@ -167,17 +127,6 @@ module Hecks
167
127
  end
168
128
  end
169
129
 
170
- # Runs `Bluebook::ModelCheck` over one booted domain's chapters, prints its
171
- # findings against the allowlist, and reports whether it passes.
172
- #
173
- # @param name [String] the domain's display name, for the header and the
174
- # `ALLOWED_FINDINGS` lookup
175
- # @param registry [Runtime::Registry] a booted registry holding the domain's chapters
176
- # @param options [Options] the run's configuration
177
- # @param known_domains [Set<String>] every bluebook and hecksagon name booted this run
178
- # @param global_emitted_events [Set<String>] every event any booted chapter emits
179
- # @return [Boolean] false if an allowlist entry is stale; otherwise true when no
180
- # error-severity finding is left
181
130
  def domain_passes?(name, registry, options, known_domains:, global_emitted_events:)
182
131
  puts "── #{name}"
183
132
 
@@ -203,12 +152,9 @@ module Hecks
203
152
  passes?(findings, " clean — #{chapters.size} chapter(s), no dead states, no unreachable protocol steps")
204
153
  end
205
154
 
206
- # Examines the language's own `Bluebook` and `World` chapters through
207
- # `MetaValidator.grammar_registry`, the judged graph its conformance specs use,
208
- # because any one grammar file booted alone is a fraction of the language.
209
- #
210
- # @param options [Options] the run's configuration
211
- # @return [Boolean] true when neither chapter has an error-severity finding
155
+ # Checked through `MetaValidator.grammar_registry`, the judged graph its
156
+ # conformance specs use, because any one grammar file booted alone is a
157
+ # fraction of the language.
212
158
  def examine_language(options)
213
159
  ok = true
214
160
  ["Bluebook", "World"].each do |name|
@@ -235,16 +181,8 @@ module Hecks
235
181
  errors.empty?
236
182
  end
237
183
 
238
- # Says whether the domain has a Cargo feature, which makes a
239
- # `rust_reserved_name` finding an error for it.
240
- #
241
- # The check reads `rust/Cargo.toml` through the repository-only fuzzing
242
- # tooling, so it is loaded only when there is a `rust/` to read.
243
- #
244
- # @param name [String] the domain's display name
245
- # @param rust_dir [String, nil] the repository's `rust/` directory; nil without a
246
- # checkout
247
- # @return [Boolean] true when `rust_dir` declares a feature named after the domain
184
+ # The repository-only fuzzing tooling is loaded lazily, only when there is a
185
+ # `rust/` to read.
248
186
  def rust_target?(name, rust_dir)
249
187
  return false unless rust_dir
250
188
 
@@ -252,12 +190,7 @@ module Hecks
252
190
  Fuzzing::TargetCapabilities.rust_feature?(name, rust_dir)
253
191
  end
254
192
 
255
- # The directory holding a domain's bluebooks: `<domain>/bluebook/` or the
256
- # domain directory itself, the same rule `Corpus.bluebook_dir` applies.
257
- #
258
- # @param domain_path [String] a domain directory path
259
- # @return [String, nil] the directory of the first `.bluebook` found, or nil when
260
- # neither place holds one
193
+ # The same rule `Corpus.bluebook_dir` applies.
261
194
  def bluebook_dir(domain_path)
262
195
  [File.join(domain_path, "bluebook"), domain_path].each do |dir|
263
196
  files = Dir[File.join(dir, "*.bluebook")]