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,181 @@
1
+ require_relative "../errors"
2
+ require_relative "../refusal_wording"
3
+ require_relative "../value"
4
+
5
+ module Hecks
6
+ module Runtime
7
+ class CommandRules
8
+ # A reference must point at something that EXISTS.
9
+ #
10
+ # `reference_to Customer` is the one guarantee an aggregate reference is
11
+ # for, and it was declared 14 times across banking and enforced nowhere :
12
+ # an Account could belong to a customer who was never registered, and
13
+ # every gate stayed green because
14
+ # no corpus step ever passed a dangling reference.
15
+ module References
16
+ # Resolved here rather than in coercion because coercion is pure — it
17
+ # holds no repository. A reference INTO ANOTHER DOMAIN is left alone : a
18
+ # cross-domain target may legitimately not be loaded, which is the same
19
+ # reading `across` policies already get.
20
+ #
21
+ # Shared by CommandInterpreter and EntityInterpreter — an entity command
22
+ # can declare a reference-typed attribute the same way an aggregate
23
+ # command can, even though nothing in the real corpus does yet.
24
+ def resolve_references(domain, command, args)
25
+ command.attributes.each do |attribute|
26
+ next unless attribute.reference?
27
+ next unless args.key?(attribute.name)
28
+
29
+ held = args[attribute.name]
30
+ next if held.nil?
31
+
32
+ target = referenced_aggregate(attribute)
33
+ next unless target
34
+
35
+ validate_reference_values(domain, target, held, list: attribute.list?)
36
+ end
37
+ end
38
+
39
+ # Structural references are checked again against the settled state.
40
+ # This is what makes a `has_many` declared on an aggregate honest even
41
+ # when a command supplies its list through an ordinary typed argument.
42
+ def resolve_state_references(domain, construct, state)
43
+ construct.attributes.each do |attribute|
44
+ next unless attribute.reference?
45
+
46
+ held = state[attribute.name]
47
+ validate_relationship_cardinality(construct, attribute, held)
48
+ next if held.nil?
49
+
50
+ target = referenced_aggregate(attribute)
51
+ next unless target
52
+
53
+ validate_reference_values(domain, target, held, list: attribute.list?)
54
+ end
55
+
56
+ Array(construct.entities).each do |entity|
57
+ field = construct.attribute(Naming.snake(entity.hecks_name).to_sym) ||
58
+ construct.attributes.find { |attribute| attribute.type.to_s == entity.hecks_name.to_s }
59
+ next unless field
60
+
61
+ Array(state[field.name]).each { |row| resolve_state_references(domain, entity, row) }
62
+ end
63
+ end
64
+
65
+ # `has_one` and `belongs_to` mean exactly one target unless the
66
+ # declaration explicitly says optional. State validation owns this
67
+ # boundary because a command may leave an aggregate field untouched;
68
+ # checking only command arguments would let a required relationship be
69
+ # persisted as nil. `has_many` admits zero members, so its empty list is
70
+ # already a valid cardinality and needs no presence refusal.
71
+ def validate_relationship_cardinality(construct, attribute, held)
72
+ return if attribute.relationship.nil? || attribute.list?
73
+ return unless held.nil? && !attribute.optional?
74
+
75
+ raise TypeMismatch,
76
+ "#{construct.hecks_name}.#{attribute.name} is a required " \
77
+ "#{attribute.relationship} relationship — expected one " \
78
+ "#{attribute.type.target_name} identity, got nil"
79
+ end
80
+
81
+ # The reference RESOLVES itself — through the chapter's own IR, so the
82
+ # bluebook's declared heads are the index. This used to regex the target's
83
+ # name out of "Reference<Customer>" and then search
84
+ # `registry.bluebook(domain).aggregates` for it — and later reached the
85
+ # target through Ruby's constant tree, a class thrown away for its `.ir`
86
+ # the moment it was found.
87
+ def referenced_aggregate(attribute)
88
+ attribute.type.resolve
89
+ end
90
+
91
+ def validate_reference_values(domain, target, held, list:)
92
+ values = list ? Array(held) : [held]
93
+ values.each do |value|
94
+ key = reference_key(value)
95
+ next if key.empty?
96
+ next if @registry.repository(domain, target).find(key)
97
+
98
+ raise NotFound,
99
+ RefusalWording.render("NotFound", "reference_target_missing",
100
+ target: target.name, heads: target.identity_heads.join(", "),
101
+ key: key.inspect)
102
+ end
103
+ end
104
+
105
+ # `value` is the referenced record's own id, EXACTLY as `Identity.of`
106
+ # would build it for that record — a bare scalar for a single-field
107
+ # identity (the overwhelming common case; Banking's own plain
108
+ # `reference_to Customer` holds one already, so `Value.
109
+ # materialize_unwrapped` is a no-op passthrough here), or a
110
+ # `Naming.identity`-joined string for a compound one
111
+ # (`belongs_to Translation, as: :translation_ref` — Translation's
112
+ # own `identified_by :domain, :from, :to`, THREE fields). Before
113
+ # this, plain `value.to_s` on that compound case's own coerced
114
+ # Value hit Ruby's default `Object#to_s` (a raw, run-to-run-random
115
+ # memory address) instead of joining the record's real id — found
116
+ # live via bin/fuzz on the self-hosted "translation" domain
117
+ # (replay_is_deterministic), the SAME class of gap `Identity.from`
118
+ # already had for a compound `identified_by`'s own bare (undotted)
119
+ # attribute paths. `materialize_unwrapped` recurses a multi-
120
+ # attribute value object to a plain Hash keyed by attribute name,
121
+ # in declaration order — `Naming.identity` on `.values` reproduces
122
+ # the identical join `Identity.of` itself would produce for the
123
+ # SAME fields.
124
+ def reference_key(value)
125
+ unwrapped = Value.materialize_unwrapped(value)
126
+ return Naming.identity(unwrapped.values).to_s if unwrapped.is_a?(Hash)
127
+
128
+ unwrapped.to_s
129
+ end
130
+
131
+ # A related record's OWN fields, reachable by name from `given`/
132
+ # `ensures` — `customer.status`, `account.customer.status` — without
133
+ # teaching the pure expression evaluator anything about
134
+ # repositories. The lookup happens HERE, once, before evaluation;
135
+ # `Resolver#lookup` just digs into a plain Hash exactly as it
136
+ # always has.
137
+ #
138
+ # `owner` is either the declaring aggregate/entity (its OWN
139
+ # `reference_to`, read off `source` — the record's stored state)
140
+ # or the command itself (a reference-typed ARGUMENT, read off
141
+ # `source` — the dispatch payload). Same shape either way: every
142
+ # reference-typed attribute `owner` declares becomes a key in the
143
+ # result, named by stripping the attribute's own `_id` suffix
144
+ # (`customer_id` → `customer`) — a no-op for an aliased reference
145
+ # that already carries no suffix (`reference_to Account, as:
146
+ # :source` → `source`), which is why this needs no separate case
147
+ # for `as:`.
148
+ #
149
+ # RECURSES into what it finds, so a chain like
150
+ # `account.customer.status` resolves in one pass: hydrating
151
+ # `account` also hydrates ITS OWN `customer_id` into a nested
152
+ # `customer` key. Depth-bounded rather than cycle-detected — nothing
153
+ # in this corpus dots more than two hops, and a bound is simpler
154
+ # than tracking visited (type, id) pairs for a cycle nothing here
155
+ # declares.
156
+ DEREFERENCE_DEPTH = 4
157
+ private_constant :DEREFERENCE_DEPTH
158
+
159
+ def dereference(domain, owner, source, depth: DEREFERENCE_DEPTH)
160
+ return {} if depth <= 0 || owner.nil?
161
+
162
+ owner.attributes.each_with_object({}) do |attribute, hydrated|
163
+ next unless attribute.reference?
164
+
165
+ id = source[attribute.name]
166
+ next if id.nil?
167
+
168
+ target = referenced_aggregate(attribute)
169
+ next unless target
170
+
171
+ record = @registry.repository(domain, target).find(id.to_s)
172
+ next unless record
173
+
174
+ name = attribute.name.to_s.sub(/_id\z/, "").to_sym
175
+ hydrated[name] = record.state.merge(dereference(domain, target, record.state, depth: depth - 1))
176
+ end
177
+ end
178
+ end
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,28 @@
1
+ require_relative "command_rules/admissibility"
2
+ require_relative "command_rules/references"
3
+ require_relative "command_rules/arithmetic"
4
+ require_relative "command_rules/emission"
5
+ require_relative "command_rules/authorization"
6
+
7
+ module Hecks
8
+ module Runtime
9
+ # The rules both interpreters consult, one concern per file beside
10
+ # this one: whether a command may run (admissibility), whether its
11
+ # references point at anything (references), what its arithmetic
12
+ # mutations mean (arithmetic), what its emits become (emission), and
13
+ # whether the caller may run it at all (authorization).
14
+ class CommandRules
15
+ include Admissibility
16
+ include References
17
+ include Arithmetic
18
+ include Emission
19
+ include Authorization
20
+
21
+ attr_reader :registry
22
+
23
+ def initialize(registry)
24
+ @registry = registry
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,231 @@
1
+ require_relative "../bluebook/expression"
2
+
3
+ module Hecks
4
+ module Runtime
5
+ # Persistence-neutral facts derived from a command's existing semantic IR.
6
+ # This module deliberately does not execute a plan or choose a repository.
7
+ module DependencyPlanning
8
+ ATOMIC_PUT = :atomic_put
9
+ TRANSACTIONAL_FALLBACK = :load_apply_validate_store
10
+
11
+ Plan = Struct.new(
12
+ :read_set,
13
+ :write_set,
14
+ :payload_read_set,
15
+ :complete_state,
16
+ :state_independent,
17
+ :unresolved_dependencies,
18
+ keyword_init: true
19
+ ) do
20
+ def complete_state? = complete_state
21
+ def state_independent? = state_independent
22
+
23
+ # Capability negotiation is correctness-first: an optimization is
24
+ # selected only when both the semantic proof and adapter capability
25
+ # are present. This is planning data only; no runtime path calls it yet.
26
+ def strategy_for(capabilities: [])
27
+ return TRANSACTIONAL_FALLBACK unless complete_state? && state_independent?
28
+ return TRANSACTIONAL_FALLBACK unless capabilities.map(&:to_sym).include?(ATOMIC_PUT)
29
+
30
+ ATOMIC_PUT
31
+ end
32
+ end
33
+
34
+ module ExpressionReads
35
+ module_function
36
+
37
+ # Read the same parsed canonical-expression nodes the evaluator uses.
38
+ # A generic Struct walk keeps this additive when the expression grammar
39
+ # gains a composed node; only Lookup nodes carry domain dependencies.
40
+ def paths(canonical)
41
+ collect(Bluebook::Expression::Evaluator.parse(canonical), Set.new)
42
+ end
43
+
44
+ def collect(node, bound_names)
45
+ case node
46
+ when Bluebook::Expression::Resolver::Lookup
47
+ root = node.path.to_s.split(".", 2).first
48
+ bound_names.include?(root) ? [] : [node.path.to_s]
49
+ when Bluebook::Expression::Resolver::BlockPredicate
50
+ collect(node.receiver, bound_names) +
51
+ collect(node.predicate, bound_names | [node.param.to_s])
52
+ when Struct
53
+ node.each_pair.flat_map { |_name, value| collect(value, bound_names) }
54
+ when Array
55
+ node.flat_map { |value| collect(value, bound_names) }
56
+ else
57
+ []
58
+ end
59
+ end
60
+ end
61
+
62
+ class Analyzer
63
+ STATEFUL_MUTATIONS = %i[append increment decrement multiply clamp remove].freeze
64
+
65
+ def self.call(aggregate:, command:) = new(aggregate, command).call
66
+
67
+ def initialize(aggregate, command)
68
+ @aggregate = aggregate
69
+ @command = command
70
+ @owner_fields = aggregate.attributes.to_set(&:name)
71
+ @owner_fields << aggregate.lifecycle.field.to_sym if aggregate.lifecycle
72
+ @payload_fields = command.attributes.to_set(&:name)
73
+ @state_reads = Set.new
74
+ @payload_reads = Set.new
75
+ @writes = Set.new
76
+ @known_writes = Set.new
77
+ @unresolved = Set.new
78
+ end
79
+
80
+ def call
81
+ analyze_initial_state
82
+ analyze_mutations
83
+ analyze_lifecycle
84
+ analyze_rules(command.givens, phase: :before)
85
+ analyze_rules(command.ensures, phase: :after)
86
+ analyze_rules(aggregate.invariants, phase: :after)
87
+ add_preservation_reads
88
+
89
+ complete = unresolved.empty? && owner_fields.subset?(known_writes)
90
+ independent = complete && state_reads.empty?
91
+
92
+ Plan.new(
93
+ read_set: sorted(state_reads),
94
+ write_set: sorted(writes),
95
+ payload_read_set: sorted(payload_reads),
96
+ complete_state: complete,
97
+ state_independent: independent,
98
+ unresolved_dependencies: unresolved.to_a.sort.freeze
99
+ ).freeze
100
+ end
101
+
102
+ private
103
+
104
+ attr_reader :aggregate, :command, :owner_fields, :payload_fields,
105
+ :state_reads, :payload_reads, :writes, :known_writes, :unresolved
106
+
107
+ # A fresh Instance supplies these values without reading a stored
108
+ # record. Keep this aligned with Instance.defaults/default_for. They
109
+ # establish completeness but are not command mutations, so they do not
110
+ # appear in write_set.
111
+ def analyze_initial_state
112
+ aggregate.attributes.each do |attribute|
113
+ known_writes << attribute.name if deterministic_initial_value?(attribute)
114
+ end
115
+
116
+ known_writes << aggregate.lifecycle.field.to_sym if aggregate.lifecycle
117
+ end
118
+
119
+ def deterministic_initial_value?(attribute)
120
+ return true if attribute.list? || attribute.optional? || !attribute.default.nil?
121
+ return false unless aggregate.respond_to?(:value_object)
122
+
123
+ value_object = aggregate.value_object(attribute.type)
124
+ value_object&.attributes&.all? { |field| !field.default.nil? }
125
+ end
126
+
127
+ def analyze_mutations
128
+ command.mutations.each do |mutation|
129
+ target = mutation.target.to_sym
130
+ writes << target
131
+
132
+ unless owner_fields.include?(target)
133
+ unresolved << "mutation target #{target} is not an aggregate field"
134
+ next
135
+ end
136
+
137
+ if mutation.op == :set
138
+ known_writes << target if analyze_source?(mutation.source)
139
+ elsif STATEFUL_MUTATIONS.include?(mutation.op)
140
+ state_reads << target
141
+ analyze_source?(mutation.source)
142
+ else
143
+ unresolved << "mutation operation #{mutation.op} has no dependency rule"
144
+ end
145
+ end
146
+ end
147
+
148
+ # Returns true only when the source is known without prior aggregate
149
+ # state. Hash sources are the canonical append binding shape.
150
+ def analyze_source?(source)
151
+ case source
152
+ when Symbol
153
+ if payload_fields.include?(source)
154
+ payload_reads << source
155
+ return true
156
+ end
157
+ if owner_fields.include?(source)
158
+ state_reads << source
159
+ return false
160
+ end
161
+
162
+ unresolved << "mutation source #{source} has no payload or aggregate field"
163
+ false
164
+ when Hash
165
+ source.values.map { |value| analyze_source?(value) }.all?
166
+ else
167
+ true
168
+ end
169
+ end
170
+
171
+ def analyze_lifecycle
172
+ lifecycle = aggregate.lifecycle
173
+ return unless lifecycle
174
+
175
+ if command.from
176
+ state_reads << lifecycle.field
177
+ end
178
+
179
+ return if lifecycle.transitions_for(command.hecks_name).empty?
180
+
181
+ writes << lifecycle.field
182
+ known_writes << lifecycle.field
183
+ end
184
+
185
+ def analyze_rules(rules, phase:)
186
+ rules.each do |rule|
187
+ ExpressionReads.paths(rule.canonical).each { |path| classify_path(path, phase) }
188
+ rescue ArgumentError => error
189
+ unresolved << "expression #{rule.canonical.inspect} could not be analyzed: #{error.message}"
190
+ end
191
+ end
192
+
193
+ def classify_path(path, phase)
194
+ head, nested = path.split(".", 2)
195
+ name = head.to_sym
196
+
197
+ if name == :parent
198
+ parent_field = nested.to_s.split(".", 2).first
199
+ if parent_field.empty? || !owner_fields.include?(parent_field.to_sym)
200
+ unresolved << "#{path} does not name parent aggregate state"
201
+ else
202
+ state_reads << parent_field.to_sym
203
+ end
204
+ elsif name == :old
205
+ old_field = nested.to_s.split(".", 2).first
206
+ if old_field.empty? || !owner_fields.include?(old_field.to_sym)
207
+ unresolved << "#{path} does not name prior aggregate state"
208
+ else
209
+ state_reads << old_field.to_sym
210
+ end
211
+ elsif payload_fields.include?(name)
212
+ payload_reads << name
213
+ elsif owner_fields.include?(name)
214
+ state_reads << name if phase == :before || !known_writes.include?(name)
215
+ else
216
+ unresolved << "expression path #{path} has no payload or aggregate field"
217
+ end
218
+ end
219
+
220
+ # A partial mutation must preserve every untouched field on the
221
+ # correctness path. Those prior values are real reads even when no rule
222
+ # names them. A deterministic write needs no preservation read.
223
+ def add_preservation_reads
224
+ state_reads.merge(owner_fields - known_writes)
225
+ end
226
+
227
+ def sorted(values) = values.to_a.sort.freeze
228
+ end
229
+ end
230
+ end
231
+ end