hecks 0.2.0 → 0.3.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 (408) hide show
  1. checksums.yaml +5 -5
  2. data/lib/hecks/adapters/driven/claude_code.adapter +3 -0
  3. data/lib/hecks/adapters/driven/claude_code.rb +127 -0
  4. data/lib/hecks/adapters/driven/d1.adapter +12 -0
  5. data/lib/hecks/adapters/driven/d1.rb +403 -0
  6. data/lib/hecks/adapters/driven/folder.adapter +3 -0
  7. data/lib/hecks/adapters/driven/folder.rb +199 -0
  8. data/lib/hecks/adapters/driven/google_authentication.adapter +3 -0
  9. data/lib/hecks/adapters/driven/google_authentication.rb +100 -0
  10. data/lib/hecks/adapters/driven/governance_authorization.adapter +3 -0
  11. data/lib/hecks/adapters/driven/governance_authorization.rb +62 -0
  12. data/lib/hecks/adapters/driven/heki/journal.rb +51 -0
  13. data/lib/hecks/adapters/driven/heki/saga_store.rb +0 -0
  14. data/lib/hecks/adapters/driven/heki/snapshot.rb +38 -0
  15. data/lib/hecks/adapters/driven/heki.adapter +4 -0
  16. data/lib/hecks/adapters/driven/heki.rb +148 -0
  17. data/lib/hecks/adapters/driven/identity_registry.adapter +3 -0
  18. data/lib/hecks/adapters/driven/identity_registry.rb +26 -0
  19. data/lib/hecks/adapters/driven/in_memory_ordering.rb +51 -0
  20. data/lib/hecks/adapters/driven/lambda/client.rb +63 -0
  21. data/lib/hecks/adapters/driven/lambda.adapter +4 -0
  22. data/lib/hecks/adapters/driven/lambda.rb +131 -0
  23. data/lib/hecks/adapters/driven/memory.adapter +3 -0
  24. data/lib/hecks/adapters/driven/memory.rb +103 -0
  25. data/lib/hecks/adapters/driven/mock_stripe_adapter.adapter +3 -0
  26. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +28 -0
  27. data/lib/hecks/adapters/driven/postgres/codec.rb +80 -0
  28. data/lib/hecks/adapters/driven/postgres/schema_builder.rb +168 -0
  29. data/lib/hecks/adapters/driven/postgres.adapter +5 -0
  30. data/lib/hecks/adapters/driven/postgres.rb +391 -0
  31. data/lib/hecks/adapters/driven/postgres_era/lineage/era_store.rb +171 -0
  32. data/lib/hecks/adapters/driven/postgres_era/lineage/field_cache.rb +190 -0
  33. data/lib/hecks/adapters/driven/postgres_era/lineage/head_compiler.rb +429 -0
  34. data/lib/hecks/adapters/driven/postgres_era/lineage/mint_transaction.rb +166 -0
  35. data/lib/hecks/adapters/driven/postgres_era/lineage/provisioning.rb +286 -0
  36. data/lib/hecks/adapters/driven/postgres_era/lineage/resumable_backfill.rb +168 -0
  37. data/lib/hecks/adapters/driven/postgres_era/lineage/tail_merge.rb +163 -0
  38. data/lib/hecks/adapters/driven/postgres_era/lineage/transform_installer.rb +114 -0
  39. data/lib/hecks/adapters/driven/postgres_era/lineage.rb +137 -0
  40. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/coverage_check.rb +89 -0
  41. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/era_resolver.rb +82 -0
  42. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/merge_coordinator.rb +43 -0
  43. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/minter.rb +132 -0
  44. data/lib/hecks/adapters/driven/postgres_era/lineage_manager.rb +74 -0
  45. data/lib/hecks/adapters/driven/postgres_era.adapter +6 -0
  46. data/lib/hecks/adapters/driven/postgres_era.rb +671 -0
  47. data/lib/hecks/adapters/driven/prism.adapter +3 -0
  48. data/lib/hecks/adapters/driven/prism.rb +80 -0
  49. data/lib/hecks/adapters/driven/secure_random_identity.adapter +3 -0
  50. data/lib/hecks/adapters/driven/secure_random_identity.rb +14 -0
  51. data/lib/hecks/adapters/driven/sql_query_builder.rb +221 -0
  52. data/lib/hecks/adapters/driven/sqlite/codec.rb +63 -0
  53. data/lib/hecks/adapters/driven/sqlite/projection.rb +105 -0
  54. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +180 -0
  55. data/lib/hecks/adapters/driven/sqlite.adapter +9 -0
  56. data/lib/hecks/adapters/driven/sqlite.rb +285 -0
  57. data/lib/hecks/adapters/driven/system_clock.adapter +3 -0
  58. data/lib/hecks/adapters/driven/system_clock.rb +14 -0
  59. data/lib/hecks/adapters/driven.rb +36 -0
  60. data/lib/hecks/adapters.rb +6 -0
  61. data/lib/hecks/behaviors/dsl.rb +96 -0
  62. data/lib/hecks/behaviors/expectations.rb +280 -0
  63. data/lib/hecks/behaviors/ir.rb +31 -0
  64. data/lib/hecks/behaviors/rspec.rb +42 -0
  65. data/lib/hecks/behaviors/runner.rb +96 -0
  66. data/lib/hecks/behaviors.rb +25 -0
  67. data/lib/hecks/bluebook/aggregate.rb +108 -0
  68. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +134 -0
  69. data/lib/hecks/bluebook/assembly/build.rb +48 -0
  70. data/lib/hecks/bluebook/assembly/contract.rb +112 -0
  71. data/lib/hecks/bluebook/assembly/contracts.rb +409 -0
  72. data/lib/hecks/bluebook/assembly/marks.rb +227 -0
  73. data/lib/hecks/bluebook/assembly/specializer.rb +70 -0
  74. data/lib/hecks/bluebook/assembly.rb +78 -0
  75. data/lib/hecks/bluebook/attribute.rb +96 -0
  76. data/lib/hecks/bluebook/behaviour/aggregate.rb +83 -0
  77. data/lib/hecks/bluebook/behaviour/attribute.rb +27 -0
  78. data/lib/hecks/bluebook/behaviour/chapter.rb +72 -0
  79. data/lib/hecks/bluebook/behaviour/command.rb +116 -0
  80. data/lib/hecks/bluebook/behaviour/domain_port.rb +25 -0
  81. data/lib/hecks/bluebook/behaviour/entity.rb +59 -0
  82. data/lib/hecks/bluebook/behaviour/hexagon.rb +50 -0
  83. data/lib/hecks/bluebook/behaviour/lifecycle.rb +51 -0
  84. data/lib/hecks/bluebook/behaviour/policy.rb +52 -0
  85. data/lib/hecks/bluebook/behaviour/process_manager.rb +38 -0
  86. data/lib/hecks/bluebook/behaviour/query.rb +10 -0
  87. data/lib/hecks/bluebook/behaviour/read_model.rb +29 -0
  88. data/lib/hecks/bluebook/behaviour/traits.rb +81 -0
  89. data/lib/hecks/bluebook/behaviour/value_object.rb +33 -0
  90. data/lib/hecks/bluebook/chapter.rb +68 -0
  91. data/lib/hecks/bluebook/command.rb +124 -0
  92. data/lib/hecks/bluebook/domain_port.rb +102 -0
  93. data/lib/hecks/bluebook/dsl/adapter_builder.rb +34 -0
  94. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +906 -0
  95. data/lib/hecks/bluebook/dsl/attribute_collector.rb +327 -0
  96. data/lib/hecks/bluebook/dsl/binding_proxy.rb +71 -0
  97. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +1018 -0
  98. data/lib/hecks/bluebook/dsl/command_builder.rb +626 -0
  99. data/lib/hecks/bluebook/dsl/const_shim.rb +81 -0
  100. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +79 -0
  101. data/lib/hecks/bluebook/dsl/entity_builder.rb +305 -0
  102. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +366 -0
  103. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +163 -0
  104. data/lib/hecks/bluebook/dsl/identity_declaration.rb +191 -0
  105. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +44 -0
  106. data/lib/hecks/bluebook/dsl/malformed.rb +7 -0
  107. data/lib/hecks/bluebook/dsl/policy_builder.rb +120 -0
  108. data/lib/hecks/bluebook/dsl/port_builder.rb +30 -0
  109. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +142 -0
  110. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +207 -0
  111. data/lib/hecks/bluebook/dsl/query_builder.rb +113 -0
  112. data/lib/hecks/bluebook/dsl/read_model_builder.rb +233 -0
  113. data/lib/hecks/bluebook/dsl/rule_reference.rb +172 -0
  114. data/lib/hecks/bluebook/dsl/translation_builder.rb +243 -0
  115. data/lib/hecks/bluebook/dsl/value_object_builder.rb +178 -0
  116. data/lib/hecks/bluebook/dsl/word_gate.rb +221 -0
  117. data/lib/hecks/bluebook/dsl/world_builder.rb +77 -0
  118. data/lib/hecks/bluebook/dsl.rb +45 -0
  119. data/lib/hecks/bluebook/entity.rb +103 -0
  120. data/lib/hecks/bluebook/expression/canonical_form.rb +55 -0
  121. data/lib/hecks/bluebook/expression/evaluator.rb +261 -0
  122. data/lib/hecks/bluebook/expression/projection.json +170 -0
  123. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +233 -0
  124. data/lib/hecks/bluebook/expression/resolver.rb +630 -0
  125. data/lib/hecks/bluebook/expression.rb +13 -0
  126. data/lib/hecks/bluebook/hexagon.rb +60 -0
  127. data/lib/hecks/bluebook/lifecycle.rb +42 -0
  128. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +54 -0
  129. data/lib/hecks/bluebook/meta_validator/judge.rb +559 -0
  130. data/lib/hecks/bluebook/meta_validator/plan.rb +332 -0
  131. data/lib/hecks/bluebook/meta_validator/port_judge.rb +47 -0
  132. data/lib/hecks/bluebook/meta_validator/readings.rb +350 -0
  133. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +312 -0
  134. data/lib/hecks/bluebook/meta_validator/shapes.rb +246 -0
  135. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +255 -0
  136. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +138 -0
  137. data/lib/hecks/bluebook/meta_validator/world_judge.rb +78 -0
  138. data/lib/hecks/bluebook/meta_validator.rb +452 -0
  139. data/lib/hecks/bluebook/model_check.rb +318 -0
  140. data/lib/hecks/bluebook/pattern_subset.rb +120 -0
  141. data/lib/hecks/bluebook/policy.rb +41 -0
  142. data/lib/hecks/bluebook/process_manager.rb +86 -0
  143. data/lib/hecks/bluebook/project_discovery.rb +30 -0
  144. data/lib/hecks/bluebook/project_loader.rb +40 -0
  145. data/lib/hecks/bluebook/project_register.rb +82 -0
  146. data/lib/hecks/bluebook/query.rb +61 -0
  147. data/lib/hecks/bluebook/read_model.rb +109 -0
  148. data/lib/hecks/bluebook/reference.rb +74 -0
  149. data/lib/hecks/bluebook/smoke_test.rb +166 -0
  150. data/lib/hecks/bluebook/synthesizer.rb +95 -0
  151. data/lib/hecks/bluebook/translation.rb +92 -0
  152. data/lib/hecks/bluebook/value_object.rb +58 -0
  153. data/lib/hecks/bluebook.rb +74 -0
  154. data/lib/hecks/codemod.rb +342 -0
  155. data/lib/hecks/construct.rb +71 -0
  156. data/lib/hecks/deploy/bluebook/deploy.bluebook +219 -0
  157. data/lib/hecks/deploy/bluebook/deploy.hecksagon +4 -0
  158. data/lib/hecks/deploy/oidc.json +18 -0
  159. data/lib/hecks/doc/reference.rb +389 -0
  160. data/lib/hecks/embryonaut_bluebook.rb +75 -0
  161. data/lib/hecks/facade/cli_door.rb +116 -0
  162. data/lib/hecks/facade/cli_runner.rb +190 -0
  163. data/lib/hecks/facade/command_request.rb +105 -0
  164. data/lib/hecks/facade/handle.rb +173 -0
  165. data/lib/hecks/facade/json_door.rb +154 -0
  166. data/lib/hecks/facade/surface/aggregate_door.rb +185 -0
  167. data/lib/hecks/facade/surface/chapter.rb +107 -0
  168. data/lib/hecks/facade/surface.rb +48 -0
  169. data/lib/hecks/facade.rb +44 -0
  170. data/lib/hecks/forms/app.rb +300 -0
  171. data/lib/hecks/forms/command_form_renderer.rb +113 -0
  172. data/lib/hecks/forms/examples/banking_console.bluebook +3 -0
  173. data/lib/hecks/forms/field_renderer.rb +170 -0
  174. data/lib/hecks/forms/field_shape.rb +232 -0
  175. data/lib/hecks/forms/html.rb +53 -0
  176. data/lib/hecks/forms/index_renderer.rb +35 -0
  177. data/lib/hecks/forms/page.rb +157 -0
  178. data/lib/hecks/forms/params.rb +132 -0
  179. data/lib/hecks/forms/query_form_renderer.rb +114 -0
  180. data/lib/hecks/forms/record_renderer.rb +115 -0
  181. data/lib/hecks/forms/record_table.rb +63 -0
  182. data/lib/hecks/forms/reference_options.rb +30 -0
  183. data/lib/hecks/forms/value_object_shape.rb +46 -0
  184. data/lib/hecks/forms.rb +54 -0
  185. data/lib/hecks/fqn.rb +94 -0
  186. data/lib/hecks/framework/bluebook/compliance.bluebook +1 -0
  187. data/lib/hecks/framework/bluebook/console_settings.bluebook +489 -0
  188. data/lib/hecks/framework/bluebook/framework.hecksagon +32 -0
  189. data/lib/hecks/framework/bluebook/governance.bluebook +130 -0
  190. data/lib/hecks/framework/bluebook/identity.bluebook +90 -0
  191. data/lib/hecks/framework/oidc.json +39 -0
  192. data/lib/hecks/framework.rb +90 -0
  193. data/lib/hecks/freezer.rb +67 -0
  194. data/lib/hecks/fuzzing/invalid_value_generator.rb +86 -0
  195. data/lib/hecks/fuzzing/isolated_boot.rb +92 -0
  196. data/lib/hecks/fuzzing/properties.rb +1146 -0
  197. data/lib/hecks/fuzzing/replay.rb +635 -0
  198. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +93 -0
  199. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +54 -0
  200. data/lib/hecks/fuzzing/sequence_generator/picker.rb +96 -0
  201. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +185 -0
  202. data/lib/hecks/fuzzing/sequence_generator.rb +130 -0
  203. data/lib/hecks/fuzzing/value_generator.rb +177 -0
  204. data/lib/hecks/fuzzing.rb +12 -0
  205. data/lib/hecks/grammar/evolve.rb +291 -0
  206. data/lib/hecks/grammar/expression.bluebook +417 -0
  207. data/lib/hecks/grammar/expression_operators.json +1152 -0
  208. data/lib/hecks/grammar/grammar.hecksagon +20 -0
  209. data/lib/hecks/grammar/oidc.json +69 -0
  210. data/lib/hecks/grammar/translation.bluebook +203 -0
  211. data/lib/hecks/grammar.rb +178 -0
  212. data/lib/hecks/ir.rb +126 -0
  213. data/lib/hecks/language/adapter.bluebook +116 -0
  214. data/lib/hecks/language/bluebook/aggregate.bluebook +581 -0
  215. data/lib/hecks/language/bluebook/attaches/paging.bluebook +76 -0
  216. data/lib/hecks/language/bluebook/bluebook.bluebook +256 -0
  217. data/lib/hecks/language/bluebook/bluebook.hecksagon +24 -0
  218. data/lib/hecks/language/bluebook/command.bluebook +437 -0
  219. data/lib/hecks/language/bluebook/entity.bluebook +316 -0
  220. data/lib/hecks/language/bluebook/policy.bluebook +172 -0
  221. data/lib/hecks/language/bluebook/process_manager.bluebook +264 -0
  222. data/lib/hecks/language/bluebook/projection.bluebook +267 -0
  223. data/lib/hecks/language/bluebook/query.bluebook +245 -0
  224. data/lib/hecks/language/bluebook/shape.bluebook +292 -0
  225. data/lib/hecks/language/bluebook/syntax.bluebook +447 -0
  226. data/lib/hecks/language/bluebook/vocabulary.bluebook +364 -0
  227. data/lib/hecks/language/hecksagon/adapter_binding.bluebook +51 -0
  228. data/lib/hecks/language/hecksagon/domain_port.bluebook +76 -0
  229. data/lib/hecks/language/hecksagon/hecksagon.bluebook +131 -0
  230. data/lib/hecks/language/hecksagon/port_operation.bluebook +102 -0
  231. data/lib/hecks/language/oidc.json +313 -0
  232. data/lib/hecks/language/port.bluebook +92 -0
  233. data/lib/hecks/language/translation/translation.bluebook +110 -0
  234. data/lib/hecks/language/translation/translation_aggregate.bluebook +267 -0
  235. data/lib/hecks/language/world/wiring.bluebook +62 -0
  236. data/lib/hecks/language/world/world.bluebook +84 -0
  237. data/lib/hecks/literal.rb +125 -0
  238. data/lib/hecks/naming.rb +121 -0
  239. data/lib/hecks/ports/access_control.port +4 -0
  240. data/lib/hecks/ports/access_control.rb +62 -0
  241. data/lib/hecks/ports/agent/answers.rb +104 -0
  242. data/lib/hecks/ports/agent.port +4 -0
  243. data/lib/hecks/ports/agent.rb +167 -0
  244. data/lib/hecks/ports/authentication.port +4 -0
  245. data/lib/hecks/ports/authentication.rb +50 -0
  246. data/lib/hecks/ports/authorization.port +4 -0
  247. data/lib/hecks/ports/authorization.rb +59 -0
  248. data/lib/hecks/ports/clock.port +4 -0
  249. data/lib/hecks/ports/clock.rb +62 -0
  250. data/lib/hecks/ports/extraction.port +4 -0
  251. data/lib/hecks/ports/extraction.rb +37 -0
  252. data/lib/hecks/ports/identity_assignment.port +4 -0
  253. data/lib/hecks/ports/identity_assignment.rb +45 -0
  254. data/lib/hecks/ports/identity_generation.port +4 -0
  255. data/lib/hecks/ports/identity_generation.rb +49 -0
  256. data/lib/hecks/ports/identity_resolution.port +4 -0
  257. data/lib/hecks/ports/identity_resolution.rb +40 -0
  258. data/lib/hecks/ports/loading.port +4 -0
  259. data/lib/hecks/ports/loading.rb +13 -0
  260. data/lib/hecks/ports/persistence/append_only.rb +102 -0
  261. data/lib/hecks/ports/persistence/binding_policy.rb +56 -0
  262. data/lib/hecks/ports/persistence/execution.rb +18 -0
  263. data/lib/hecks/ports/persistence/lineage.rb +277 -0
  264. data/lib/hecks/ports/persistence/null_saga_store.rb +25 -0
  265. data/lib/hecks/ports/persistence/remote_runtime.rb +42 -0
  266. data/lib/hecks/ports/persistence/repository_factory.rb +30 -0
  267. data/lib/hecks/ports/persistence.port +4 -0
  268. data/lib/hecks/ports/persistence.rb +39 -0
  269. data/lib/hecks/ports/projection.port +4 -0
  270. data/lib/hecks/ports/projection.rb +76 -0
  271. data/lib/hecks/ports/query/in_memory.rb +60 -0
  272. data/lib/hecks/ports/query/ordering.rb +41 -0
  273. data/lib/hecks/ports/query.rb +36 -0
  274. data/lib/hecks/ports.rb +27 -0
  275. data/lib/hecks/projections/diagrams.rb +413 -0
  276. data/lib/hecks/projections/ir.rb +18 -0
  277. data/lib/hecks/projections/model/deviations.rb +98 -0
  278. data/lib/hecks/projections/model.rb +145 -0
  279. data/lib/hecks/projections/oidc.rb +110 -0
  280. data/lib/hecks/projections/parser_table.rb +159 -0
  281. data/lib/hecks/projections/reference.rb +38 -0
  282. data/lib/hecks/projections/shape.rb +31 -0
  283. data/lib/hecks/projections/statements.rb +110 -0
  284. data/lib/hecks/projections/vocabulary.rb +100 -0
  285. data/lib/hecks/projections.rb +32 -0
  286. data/lib/hecks/projector/cli_projector.rb +437 -0
  287. data/lib/hecks/projector/docs_projector.rb +321 -0
  288. data/lib/hecks/projector/exporter.rb +141 -0
  289. data/lib/hecks/projector/ir_projector.rb +18 -0
  290. data/lib/hecks/projector/narrate_projector.rb +243 -0
  291. data/lib/hecks/projector/target.rb +97 -0
  292. data/lib/hecks/projector.rb +186 -0
  293. data/lib/hecks/query_ir.rb +392 -0
  294. data/lib/hecks/query_specification/common/authorization_spec.rb +9 -0
  295. data/lib/hecks/query_specification/common/comparators.rb +25 -0
  296. data/lib/hecks/query_specification/common/comparison.rb +174 -0
  297. data/lib/hecks/query_specification/common/cursor_spec.rb +9 -0
  298. data/lib/hecks/query_specification/common/dsl.rb +58 -0
  299. data/lib/hecks/query_specification/common/inspection_spec.rb +9 -0
  300. data/lib/hecks/query_specification/common/limit_spec.rb +9 -0
  301. data/lib/hecks/query_specification/common/null_policy.rb +80 -0
  302. data/lib/hecks/query_specification/common/null_semantics.rb +11 -0
  303. data/lib/hecks/query_specification/common/offset_spec.rb +9 -0
  304. data/lib/hecks/query_specification/common/options.rb +32 -0
  305. data/lib/hecks/query_specification/common/order_by.rb +9 -0
  306. data/lib/hecks/query_specification/common/specification.rb +10 -0
  307. data/lib/hecks/query_specification/common/where_clause.rb +9 -0
  308. data/lib/hecks/query_specification/field_path.rb +89 -0
  309. data/lib/hecks/query_specification/hop_path.rb +130 -0
  310. data/lib/hecks/query_specification/read_model/specification.rb +18 -0
  311. data/lib/hecks/query_specification.rb +14 -0
  312. data/lib/hecks/rendering.rb +48 -0
  313. data/lib/hecks/router/namespace_installer.rb +157 -0
  314. data/lib/hecks/router.rb +70 -0
  315. data/lib/hecks/runtime/caller.rb +50 -0
  316. data/lib/hecks/runtime/capability_graph.rb +44 -0
  317. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +124 -0
  318. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +248 -0
  319. data/lib/hecks/runtime/command_interpreter.rb +413 -0
  320. data/lib/hecks/runtime/command_rules/admissibility.rb +307 -0
  321. data/lib/hecks/runtime/command_rules/arithmetic.rb +254 -0
  322. data/lib/hecks/runtime/command_rules/authorization.rb +64 -0
  323. data/lib/hecks/runtime/command_rules/emission.rb +34 -0
  324. data/lib/hecks/runtime/command_rules/references.rb +181 -0
  325. data/lib/hecks/runtime/command_rules.rb +28 -0
  326. data/lib/hecks/runtime/dependency_planning.rb +231 -0
  327. data/lib/hecks/runtime/dispatcher.rb +286 -0
  328. data/lib/hecks/runtime/entity_element.rb +253 -0
  329. data/lib/hecks/runtime/entity_interpreter.rb +228 -0
  330. data/lib/hecks/runtime/era_check.rb +136 -0
  331. data/lib/hecks/runtime/era_guard/shape_diff.rb +128 -0
  332. data/lib/hecks/runtime/era_guard.rb +193 -0
  333. data/lib/hecks/runtime/era_tamper.rb +61 -0
  334. data/lib/hecks/runtime/errors.rb +100 -0
  335. data/lib/hecks/runtime/event.rb +51 -0
  336. data/lib/hecks/runtime/identity.rb +128 -0
  337. data/lib/hecks/runtime/instance.rb +120 -0
  338. data/lib/hecks/runtime/interpreting.rb +69 -0
  339. data/lib/hecks/runtime/loader.rb +143 -0
  340. data/lib/hecks/runtime/policy_interpreter.rb +366 -0
  341. data/lib/hecks/runtime/port_operation_interpreter.rb +210 -0
  342. data/lib/hecks/runtime/query_interpreter.rb +254 -0
  343. data/lib/hecks/runtime/reaction_invocation.rb +245 -0
  344. data/lib/hecks/runtime/read_model_interpreter.rb +266 -0
  345. data/lib/hecks/runtime/rebuild_sweep.rb +74 -0
  346. data/lib/hecks/runtime/reference_hop.rb +99 -0
  347. data/lib/hecks/runtime/refusal_wording.rb +124 -0
  348. data/lib/hecks/runtime/registry/saga_persistence.rb +70 -0
  349. data/lib/hecks/runtime/registry/verification.rb +158 -0
  350. data/lib/hecks/runtime/registry.rb +218 -0
  351. data/lib/hecks/runtime/remote_dispatcher.rb +143 -0
  352. data/lib/hecks/runtime/routing.rb +96 -0
  353. data/lib/hecks/runtime/saga_interpreter/correlation.rb +97 -0
  354. data/lib/hecks/runtime/saga_interpreter.rb +301 -0
  355. data/lib/hecks/runtime/storage_shape.rb +120 -0
  356. data/lib/hecks/runtime/tenant_check.rb +84 -0
  357. data/lib/hecks/runtime/tenant_scope.rb +55 -0
  358. data/lib/hecks/runtime/value/admission.rb +112 -0
  359. data/lib/hecks/runtime/value/coercion.rb +500 -0
  360. data/lib/hecks/runtime/value/invariant_violation.rb +5 -0
  361. data/lib/hecks/runtime/value.rb +125 -0
  362. data/lib/hecks/runtime.rb +95 -0
  363. data/lib/hecks/translation/audit/approval_digest.rb +31 -0
  364. data/lib/hecks/translation/audit/layer_one.rb +37 -0
  365. data/lib/hecks/translation/audit/layer_two.rb +77 -0
  366. data/lib/hecks/translation/audit/unfed_report.rb +42 -0
  367. data/lib/hecks/translation/audit.rb +70 -0
  368. data/lib/hecks/translation/reattest.rb +72 -0
  369. data/lib/hecks/translation/rule_compiler.rb +120 -0
  370. data/lib/hecks/translation/scaffold/differ.rb +183 -0
  371. data/lib/hecks/translation/scaffold/renderer.rb +41 -0
  372. data/lib/hecks/translation/scaffold/writer.rb +28 -0
  373. data/lib/hecks/translation/scaffold.rb +30 -0
  374. data/lib/hecks/translation.rb +11 -0
  375. data/lib/hecks/version.rb +16 -0
  376. data/lib/hecks/vocabulary.rb +213 -0
  377. data/lib/hecks.rb +118 -6
  378. metadata +401 -222
  379. data/bin/hecks +0 -7
  380. data/bin/hecks-package +0 -65
  381. data/bin/hecks_console +0 -12
  382. data/bin/hecks_serverless +0 -6
  383. data/lib/cli/build.rb +0 -14
  384. data/lib/cli/command_runner.rb +0 -28
  385. data/lib/cli/console.rb +0 -10
  386. data/lib/cli/generate.rb +0 -37
  387. data/lib/cli/hecks-cli.rb +0 -27
  388. data/lib/cli/test.rb +0 -57
  389. data/lib/console/commands.rb +0 -8
  390. data/lib/console/hecks-console.rb +0 -1
  391. data/lib/packager/README.md +0 -0
  392. data/lib/packager/app_runner.rb +0 -21
  393. data/lib/packager/args.rb +0 -26
  394. data/lib/packager/compatibility/fixnum.rb +0 -6
  395. data/lib/packager/hecks.rb +0 -39
  396. data/lib/packager/query_runner.rb +0 -21
  397. data/lib/packager/resources/Dockerfile +0 -11
  398. data/lib/packager/resources/app_binary +0 -7
  399. data/lib/packager/resources/bundle_config +0 -3
  400. data/lib/packager/resources/traveling-ruby-20150715-2.2.2-linux-x86_64.tar.gz +0 -0
  401. data/lib/packager/resources/traveling-ruby-20150715-2.2.2-osx.tar.gz +0 -0
  402. data/lib/serverless/Domain +0 -32
  403. data/lib/serverless/cli.rb +0 -75
  404. data/lib/serverless/resources/command_name.js +0 -5
  405. data/lib/serverless/resources/environment.js +0 -7
  406. data/lib/serverless/resources/handler.js.tt +0 -28
  407. data/lib/serverless/resources/run_binary.js +0 -22
  408. data/lib/serverless/resources/serverless.yml +0 -20
@@ -0,0 +1,120 @@
1
+ require "json"
2
+ require "digest"
3
+
4
+ module Hecks
5
+ module Runtime
6
+ # The storage-shape projection of a bluebook: exactly the parts of
7
+ # the IR that decide what persisted data looks like — aggregates,
8
+ # their attributes (with full value-object/entity structure and
9
+ # cardinality), references, the lifecycle field, and the identity
10
+ # paths. Everything behavioral — commands, invariants, queries,
11
+ # policies, lifecycle transitions, defaults, descriptions, comments,
12
+ # the declared routing `version:` — is excluded, so editing behavior
13
+ # never bumps an era and editing shape always does.
14
+ #
15
+ # Three attribute facts on the wire are constraints on PERSISTED
16
+ # VALUES, not behavior, and are still excluded — each decided, not
17
+ # overlooked:
18
+ #
19
+ # `optional` — required-ness is enforced at dispatch; stored rows
20
+ # are never re-validated on read, so flipping it
21
+ # strands nothing already written. Excluded.
22
+ # `pattern` — same argument: a fact about what may be WRITTEN
23
+ # next, not about what was stored. Excluded.
24
+ # `admits` — the sharpest of the three: narrowing a closed set
25
+ # CAN strand stored rows outside it, and the wire
26
+ # carries only the set's NAME, so a set whose members
27
+ # changed under a stable name is invisible even to a
28
+ # projection that included the fact (the same lesson
29
+ # recursive value-object drift taught). Excluded, and
30
+ # NAMED as a gap: constraint tightening has no
31
+ # translation-rule vocabulary to acknowledge it yet,
32
+ # so including it would mint era bumps nothing can
33
+ # explain. When the translation language grows a
34
+ # constraint-acknowledgment rule, `admits` (by member
35
+ # list, not by name) is first in line, and that
36
+ # change bumps FORM_VERSION.
37
+ #
38
+ # Projection runs over the canonical dump form (`to_h`, JSON
39
+ # round-tripped), so a verdict depends only on the IR — never on live
40
+ # object graphs. Structural comparison only, never a hash comparison.
41
+ module StorageShape
42
+ module_function
43
+
44
+ def project(bluebook)
45
+ domain = JSON.parse(JSON.generate(bluebook.to_h))
46
+ {
47
+ "name" => bluebook.name,
48
+ "aggregates" => (domain["aggregates"] || [])
49
+ .map { |aggregate| project_aggregate(aggregate) }
50
+ .sort_by { |aggregate| aggregate["name"] }
51
+ }
52
+ end
53
+
54
+ def same?(held, current) = project(held) == project(current)
55
+
56
+ # The canonical serialization the Ruby scaffold hashes at MINT time
57
+ # — the one moment identity is computed. Nothing ever recomputes a
58
+ # stored era name to verify it, so this form can evolve freely.
59
+ def canonical(bluebook) = JSON.generate(project(bluebook))
60
+
61
+ def mint_hash(bluebook) = Digest::SHA256.hexdigest(canonical(bluebook))
62
+
63
+ LABEL_LENGTH = 6
64
+ def mint_label(bluebook) = mint_hash(bluebook)[0, LABEL_LENGTH]
65
+
66
+ # The version of the canonical serialization above. Minted-once
67
+ # means a stored name stays valid across form changes — but only
68
+ # if each name records WHICH form minted it, so v1-named and
69
+ # v2-named eras coexist legibly. Stored beside every minted hash
70
+ # (names.tsv fourth field / hecks_eras.canon_form); bump this in
71
+ # the same change that alters project/canonical output.
72
+ FORM_VERSION = 1
73
+
74
+ def project_aggregate(aggregate)
75
+ {
76
+ "name" => aggregate["name"],
77
+ # The declared identity paths, AS A LIST, in declaration order —
78
+ # order is semantic (the paths join in order to form the id).
79
+ # No "id" fallback: an aggregate that declares nothing has [],
80
+ # and that is a real declared state, distinct from an aggregate
81
+ # identified by a field named "id".
82
+ "identity" => Array(aggregate["identified_by"]).map(&:to_s),
83
+ "lifecycle_field" => aggregate.dig("lifecycle", "field"),
84
+ "attributes" => (aggregate["attributes"] || [])
85
+ .map { |attribute| project_attribute(aggregate, attribute, []) }
86
+ .sort_by { |attribute| attribute["name"] }
87
+ }
88
+ end
89
+
90
+ def project_attribute(aggregate, attribute, seen)
91
+ {
92
+ "name" => attribute["name"].to_s,
93
+ "list" => attribute["list"] ? true : false,
94
+ "type" => type_signature(aggregate, attribute["type"].to_s, seen)
95
+ }
96
+ end
97
+
98
+ # A plain type name for a primitive; the type name plus its
99
+ # members' full signatures for a value object or entity — so two
100
+ # attributes with the same declared type name but different
101
+ # internals are never mistaken for unchanged.
102
+ def type_signature(aggregate, type_name, seen)
103
+ container = nested_type(aggregate, type_name)
104
+ return type_name if container.nil? || seen.include?(type_name)
105
+
106
+ {
107
+ "type" => type_name,
108
+ "members" => (container["attributes"] || [])
109
+ .map { |member| project_attribute(aggregate, member, seen + [type_name]) }
110
+ .sort_by { |member| member["name"] }
111
+ }
112
+ end
113
+
114
+ def nested_type(aggregate, type_name)
115
+ (aggregate["value_objects"] || []).find { |vo| vo["name"] == type_name } ||
116
+ (aggregate["entities"] || []).find { |entity| entity["name"] == type_name }
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,84 @@
1
+ require_relative "../ports/persistence/binding_policy"
2
+
3
+ module Hecks
4
+ module Runtime
5
+ # The capability idiom for MULTI-TENANT hosting — mirrors EraCheck's
6
+ # own `lineage_capable?`, one level over. An adapter answers
7
+ # `tenant_capable?` with true when its OWN instances genuinely
8
+ # isolate one boot's data from another's, given each tenant is its
9
+ # own separate `Runtime.boot` call (its own Registry, its own
10
+ # Dispatcher, its own adapter instances) rather than one shared
11
+ # process switching connections mid-dispatch.
12
+ #
13
+ # THAT LAST PART IS THE FINDING THIS MODULE ENCODES. The project
14
+ # register (Bluebook::ProjectRegister) already resolves an address's
15
+ # REALM to a DISPATCHER at registration time — Router#resolve looks
16
+ # the FQN up in one flat table keyed by realm::domain::aggregate.verb,
17
+ # and each entry already carries its OWN dispatcher from its OWN
18
+ # boot. So "which tenant" is decided ONCE, at boot/registration time
19
+ # (which of possibly many boots of the same directory a request's
20
+ # realm resolves to), never per-dispatch inside a shared registry.
21
+ # No ambient thread-local "current tenant" is needed, and no
22
+ # connection cache is needed beyond what booting-once-per-tenant
23
+ # already gives for free — each tenant's own PostgresEra instance
24
+ # IS its own connection, held for the life of that boot.
25
+ #
26
+ # So `tenant_capable?` asks a narrower question than it might sound:
27
+ # not "can this adapter switch tenants," but "does booting this
28
+ # adapter twice, with different settings, for the same directory,
29
+ # actually keep the two boots' data apart." Memory answers true
30
+ # trivially — a `@records` Hash is a plain instance variable, and
31
+ # two `Runtime.boot` calls build two entirely separate Registry
32
+ # objects, so two Memory adapter instances never share state by
33
+ # construction. PostgresEra answers true because its own `schema:`
34
+ # setting (already built, already the Storehouse mechanism) puts
35
+ # each boot's tables in their own Postgres schema via `SET
36
+ # search_path` — proven for real, not assumed, by
37
+ # tenant_isolation_spec.rb. Plain Postgres (no schema story) and D1
38
+ # (no schema-equivalent at all — see world.bluebook's own comment on
39
+ # the lifeadelics D1 tradeoff) answer false, or don't answer at all,
40
+ # which this module treats identically to false.
41
+ module TenantCheck
42
+ module_function
43
+
44
+ # A domain is safe to boot for MORE THAN ONE TENANT only if every
45
+ # aggregate's resolved persistence adapter is tenant_capable? — one
46
+ # ungoverned adapter sharing state across two tenant boots is a
47
+ # real data leak, not a theoretical one, so this is checked before
48
+ # a second tenant boot of the same directory is trusted, the same
49
+ # severity EraCheck/refuse_ungoverned_roles! already hold their
50
+ # own gates to.
51
+ def refuse_unless_tenant_capable!(registry, domain)
52
+ bluebook = registry.bluebook(domain)
53
+ return unless bluebook
54
+
55
+ offender = bluebook.aggregates.find do |aggregate|
56
+ adapter_name = Ports::Persistence::BindingPolicy.resolve(registry, domain, aggregate).adapter
57
+ !tenant_capable?(registry, adapter_name)
58
+ end
59
+ return unless offender
60
+
61
+ adapter_name = Ports::Persistence::BindingPolicy.resolve(registry, domain, offender).adapter
62
+ raise WiringError,
63
+ "#{domain}::#{offender.hecks_name} is bound to #{adapter_name}, which is not " \
64
+ "tenant_capable? — booting #{domain} for more than one tenant would share " \
65
+ "#{adapter_name}'s own storage across tenants that must never see each other's data. " \
66
+ "Bind a tenant-capable adapter (Memory, PostgresEra with its own schema: per tenant), " \
67
+ "or keep #{domain} single-tenant."
68
+ end
69
+
70
+ # The capability idiom itself — an adapter CLASS that answers
71
+ # tenant_capable? with true keeps two boots' data apart by
72
+ # construction (Memory) or by an explicit per-boot isolation
73
+ # setting (PostgresEra's schema:). Same defensive shape
74
+ # EraCheck#lineage_capable? already uses: a class that doesn't
75
+ # respond at all is false, not an error.
76
+ def tenant_capable?(registry, adapter_name)
77
+ adapter_class = registry.adapters[adapter_name] && registry.adapter_class(adapter_name)
78
+ adapter_class.respond_to?(:tenant_capable?) && adapter_class.tenant_capable?
79
+ rescue StandardError
80
+ false
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,55 @@
1
+ require "delegate"
2
+ require_relative "errors"
3
+ require_relative "refusal_wording"
4
+ require_relative "../query_specification/common/where_clause"
5
+
6
+ module Hecks
7
+ module Runtime
8
+ # `authorize policy, tenant: :field` declared a tenant boundary that
9
+ # nothing enforced — the policy name and the field were stored and read
10
+ # by nothing at dispatch time. This is the half that CAN be enforced
11
+ # without a caller-identity/session system: the boundary itself, made
12
+ # mandatory. Whether THIS caller actually holds `policy` for THIS
13
+ # tenant needs real identity infrastructure this runtime does not have
14
+ # — that stays a named, open gap, not something this quietly pretends
15
+ # to answer.
16
+ #
17
+ # Enforcement is a synthetic `eq` where-clause, symbol-valued exactly
18
+ # the way a dynamic `where(field: :arg_name)` already resolves against
19
+ # args in every engine (QueryInterpreter#interpret,
20
+ # Ports::Query::InMemory, both SQL adapters via SqlQueryBuilder) — so
21
+ # every engine that already reads `.wheres` enforces the boundary for
22
+ # free, with no per-engine code and no way for one engine to forget it.
23
+ # `Scoped` is handed only to those engines as their `declared`/
24
+ # `specification` argument — never returned to a caller that might call
25
+ # an IR-level method (`filtered_head_name`, `to_h`, …) whose OWN
26
+ # internal `wheres` call would resolve against the original object, not
27
+ # this override, since `SimpleDelegator` only intercepts calls made
28
+ # directly on the wrapper.
29
+ module TenantScope
30
+ module_function
31
+
32
+ def apply(declared, args)
33
+ tenant = declared.authorization&.tenant
34
+ return declared unless tenant
35
+
36
+ tenant = tenant.to_sym
37
+ unless args.key?(tenant)
38
+ raise Unauthorized, RefusalWording.render("Unauthorized", "tenant_required",
39
+ query: declared.name, field: tenant)
40
+ end
41
+
42
+ Scoped.new(declared, QuerySpecification::Common::WhereClause.new(field: tenant, op: "eq", value: tenant))
43
+ end
44
+
45
+ class Scoped < SimpleDelegator
46
+ def initialize(declared, clause)
47
+ super(declared)
48
+ @clause = clause
49
+ end
50
+
51
+ def wheres = __getobj__.wheres + [@clause]
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,112 @@
1
+ require_relative "invariant_violation"
2
+ require_relative "../refusal_wording"
3
+
4
+ module Hecks
5
+ module Runtime
6
+ class Value
7
+ # Closed sets — `one_of` members and `admits:` declarations — and the
8
+ # refusals that make them rules rather than decoration. Extended into
9
+ # Value beside Coercion; `self` is the Value class.
10
+ module Admission
11
+ def admit_member(value_object, fields)
12
+ return if value_object.members.empty?
13
+
14
+ discriminant = value_object.attributes.first.name
15
+ offered = fields[discriminant]
16
+ admitted = value_object.members.map { |member| member[discriminant].to_s }
17
+ return if admitted.include?(offered.to_s)
18
+
19
+ raise InvariantViolation,
20
+ RefusalWording.render("InvariantViolation", "closed_set_member",
21
+ type: value_object.hecks_name,
22
+ admitted: admitted.map(&:inspect).join(", "), offered: offered.inspect)
23
+ end
24
+
25
+ # THE SAME REFUSAL, FOR A SET NAMED SOMEWHERE ELSE.
26
+ #
27
+ # `admit_member` above refuses a non-member when the value object BEING
28
+ # BUILT is itself the closed set — which is the only shape `one_of` can
29
+ # make, because it SYNTHESISES the set from the values written inline. An
30
+ # `admits:` attribute is the other direction: the value is an ordinary
31
+ # String or a plain text holder, and the set it must belong to was
32
+ # declared once, elsewhere, and is named rather than restated.
33
+ #
34
+ # Without this the word was a DECLARATION and nothing more — read by
35
+ # projections, read by nobody at the door. A rule
36
+ # that cannot be the one to refuse is decoration, and this language has
37
+ # paid for that mistake before.
38
+ def admit_declared_set(owner, attribute, value)
39
+ return value if attribute.nil? || attribute.admits.nil? || value.nil?
40
+
41
+ admitted = admitted_members(owner, attribute)
42
+ offered = admitted_scalar(value)
43
+ return value if admitted.include?(offered.to_s)
44
+
45
+ raise InvariantViolation,
46
+ RefusalWording.render("InvariantViolation", "admits_declared_set",
47
+ name: attribute.name, admits: attribute.admits,
48
+ admitted: admitted.map(&:inspect).join(", "), offered: offered.inspect)
49
+ end
50
+
51
+ # `Vocabulary::MutationOp` — the aggregate that HOLDS the set, then the
52
+ # set. Qualified because a closed set is a value object INSIDE an
53
+ # aggregate, which is exactly why `admits` could not be spelled as a
54
+ # reference: `reference_to` reaches aggregate heads and nothing below one.
55
+ #
56
+ # RESOLVED LATE, like `Reference#resolve` and for the same reason — the
57
+ # set may be declared further down the file than the attribute that names
58
+ # it. And REFUSED when it resolves to nothing, also like `Reference`: a
59
+ # link checked against nothing is worse than no link, because it reads
60
+ # like a rule.
61
+ def admitted_members(owner, attribute)
62
+ aggregate_name, set_name = attribute.admits.to_s.split("::", 2)
63
+ chapter = chapter_of(owner)
64
+ set = set_name && chapter&.aggregate(aggregate_name)&.value_object(set_name)
65
+
66
+ unless set
67
+ raise InvariantViolation,
68
+ RefusalWording.render("InvariantViolation", "undeclared_set",
69
+ name: attribute.name, admits: attribute.admits)
70
+ end
71
+
72
+ discriminant = set.attributes.first.name
73
+ set.members.map { |member| member.to_h[discriminant].to_s }
74
+ end
75
+
76
+ # UP TO THE CHAPTER, from wherever the attribute was declared. A value
77
+ # object's owner is its aggregate and an aggregate's owner is its chapter,
78
+ # so the walk stops at the first construct that can answer for an
79
+ # aggregate BY NAME — which is the chapter, and only the chapter.
80
+ def chapter_of(construct)
81
+ node = construct
82
+ node = node.hecks_owner while node && !node.respond_to?(:aggregate) && node.respond_to?(:hecks_owner)
83
+ node.respond_to?(:aggregate) ? node : nil
84
+ end
85
+
86
+ # An admitted value is a SCALAR however it arrived — as a bare string on a
87
+ # plain field, or wrapped in the one-field holder its type names.
88
+ def admitted_scalar(value)
89
+ return value unless value.is_a?(self)
90
+
91
+ fields = value.to_h
92
+ fields.size == 1 ? fields.values.first : value
93
+ end
94
+
95
+ # A FIELD OF A VALUE OBJECT MAY NAME A SET TOO.
96
+ #
97
+ # Beside check_patterns and for the same reason: `Query::Filter.op` is a
98
+ # plain String field that admits `Vocabulary::QueryComparator`, and the
99
+ # value object is what gets built — no attribute passes through
100
+ # `for_attribute` on the way. Both doors, or the word means one thing on
101
+ # an argument and nothing on a field.
102
+ private def check_admitted(value_object, fields)
103
+ value_object.attributes.each do |attribute|
104
+ next unless attribute.admits
105
+
106
+ admit_declared_set(value_object, attribute, fields[attribute.name])
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end