hecks 0.2.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (419) 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 +427 -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 +101 -0
  12. data/lib/hecks/adapters/driven/heki/journal.rb +56 -0
  13. data/lib/hecks/adapters/driven/heki/saga_store.rb +99 -0
  14. data/lib/hecks/adapters/driven/heki/snapshot.rb +65 -0
  15. data/lib/hecks/adapters/driven/heki.adapter +4 -0
  16. data/lib/hecks/adapters/driven/heki.rb +179 -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 +145 -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 +88 -0
  28. data/lib/hecks/adapters/driven/postgres/schema_builder.rb +207 -0
  29. data/lib/hecks/adapters/driven/postgres.adapter +5 -0
  30. data/lib/hecks/adapters/driven/postgres.rb +438 -0
  31. data/lib/hecks/adapters/driven/postgres_era.adapter +17 -0
  32. data/lib/hecks/adapters/driven/prism.adapter +3 -0
  33. data/lib/hecks/adapters/driven/prism.rb +80 -0
  34. data/lib/hecks/adapters/driven/secure_random_identity.adapter +3 -0
  35. data/lib/hecks/adapters/driven/secure_random_identity.rb +14 -0
  36. data/lib/hecks/adapters/driven/sql_query_builder.rb +221 -0
  37. data/lib/hecks/adapters/driven/sqlite/codec.rb +80 -0
  38. data/lib/hecks/adapters/driven/sqlite/projection.rb +172 -0
  39. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +192 -0
  40. data/lib/hecks/adapters/driven/sqlite.adapter +9 -0
  41. data/lib/hecks/adapters/driven/sqlite.rb +306 -0
  42. data/lib/hecks/adapters/driven/system_clock.adapter +3 -0
  43. data/lib/hecks/adapters/driven/system_clock.rb +14 -0
  44. data/lib/hecks/adapters/driven.rb +54 -0
  45. data/lib/hecks/adapters.rb +6 -0
  46. data/lib/hecks/behaviors/dsl.rb +125 -0
  47. data/lib/hecks/behaviors/expectations.rb +340 -0
  48. data/lib/hecks/behaviors/ir.rb +31 -0
  49. data/lib/hecks/behaviors/rspec.rb +42 -0
  50. data/lib/hecks/behaviors/runner.rb +96 -0
  51. data/lib/hecks/behaviors.rb +25 -0
  52. data/lib/hecks/bluebook/aggregate.rb +108 -0
  53. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +134 -0
  54. data/lib/hecks/bluebook/assembly/build.rb +48 -0
  55. data/lib/hecks/bluebook/assembly/contract.rb +112 -0
  56. data/lib/hecks/bluebook/assembly/contracts.rb +438 -0
  57. data/lib/hecks/bluebook/assembly/marks.rb +228 -0
  58. data/lib/hecks/bluebook/assembly/specializer.rb +70 -0
  59. data/lib/hecks/bluebook/assembly.rb +91 -0
  60. data/lib/hecks/bluebook/attribute.rb +96 -0
  61. data/lib/hecks/bluebook/behaviour/aggregate.rb +83 -0
  62. data/lib/hecks/bluebook/behaviour/attribute.rb +27 -0
  63. data/lib/hecks/bluebook/behaviour/chapter.rb +72 -0
  64. data/lib/hecks/bluebook/behaviour/command.rb +116 -0
  65. data/lib/hecks/bluebook/behaviour/domain_port.rb +25 -0
  66. data/lib/hecks/bluebook/behaviour/entity.rb +59 -0
  67. data/lib/hecks/bluebook/behaviour/hexagon.rb +50 -0
  68. data/lib/hecks/bluebook/behaviour/lifecycle.rb +68 -0
  69. data/lib/hecks/bluebook/behaviour/policy.rb +52 -0
  70. data/lib/hecks/bluebook/behaviour/process_manager.rb +51 -0
  71. data/lib/hecks/bluebook/behaviour/query.rb +10 -0
  72. data/lib/hecks/bluebook/behaviour/read_model.rb +29 -0
  73. data/lib/hecks/bluebook/behaviour/traits.rb +81 -0
  74. data/lib/hecks/bluebook/behaviour/value_object.rb +33 -0
  75. data/lib/hecks/bluebook/chapter.rb +78 -0
  76. data/lib/hecks/bluebook/command.rb +124 -0
  77. data/lib/hecks/bluebook/domain_port.rb +102 -0
  78. data/lib/hecks/bluebook/dsl/adapter_builder.rb +34 -0
  79. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +1018 -0
  80. data/lib/hecks/bluebook/dsl/attribute_collector.rb +348 -0
  81. data/lib/hecks/bluebook/dsl/binding_proxy.rb +71 -0
  82. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +1087 -0
  83. data/lib/hecks/bluebook/dsl/command_builder.rb +714 -0
  84. data/lib/hecks/bluebook/dsl/const_shim.rb +81 -0
  85. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +79 -0
  86. data/lib/hecks/bluebook/dsl/entity_builder.rb +430 -0
  87. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +366 -0
  88. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +163 -0
  89. data/lib/hecks/bluebook/dsl/identity_declaration.rb +191 -0
  90. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +44 -0
  91. data/lib/hecks/bluebook/dsl/malformed.rb +7 -0
  92. data/lib/hecks/bluebook/dsl/policy_builder.rb +135 -0
  93. data/lib/hecks/bluebook/dsl/port_builder.rb +39 -0
  94. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +142 -0
  95. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +306 -0
  96. data/lib/hecks/bluebook/dsl/query_builder.rb +113 -0
  97. data/lib/hecks/bluebook/dsl/read_model_builder.rb +233 -0
  98. data/lib/hecks/bluebook/dsl/rule_reference.rb +173 -0
  99. data/lib/hecks/bluebook/dsl/translation_builder.rb +243 -0
  100. data/lib/hecks/bluebook/dsl/value_object_builder.rb +178 -0
  101. data/lib/hecks/bluebook/dsl/word_gate.rb +228 -0
  102. data/lib/hecks/bluebook/dsl/world_builder.rb +117 -0
  103. data/lib/hecks/bluebook/dsl.rb +45 -0
  104. data/lib/hecks/bluebook/entity.rb +103 -0
  105. data/lib/hecks/bluebook/expression/canonical_form.rb +123 -0
  106. data/lib/hecks/bluebook/expression/evaluator.rb +304 -0
  107. data/lib/hecks/bluebook/expression/projection.json +218 -0
  108. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +233 -0
  109. data/lib/hecks/bluebook/expression/resolver.rb +781 -0
  110. data/lib/hecks/bluebook/expression.rb +13 -0
  111. data/lib/hecks/bluebook/hexagon.rb +60 -0
  112. data/lib/hecks/bluebook/lifecycle.rb +42 -0
  113. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +54 -0
  114. data/lib/hecks/bluebook/meta_validator/judge.rb +621 -0
  115. data/lib/hecks/bluebook/meta_validator/plan.rb +332 -0
  116. data/lib/hecks/bluebook/meta_validator/port_judge.rb +51 -0
  117. data/lib/hecks/bluebook/meta_validator/readings.rb +360 -0
  118. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +351 -0
  119. data/lib/hecks/bluebook/meta_validator/shapes.rb +266 -0
  120. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +255 -0
  121. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +138 -0
  122. data/lib/hecks/bluebook/meta_validator/world_judge.rb +78 -0
  123. data/lib/hecks/bluebook/meta_validator.rb +542 -0
  124. data/lib/hecks/bluebook/model_check.rb +445 -0
  125. data/lib/hecks/bluebook/pattern_subset.rb +184 -0
  126. data/lib/hecks/bluebook/policy.rb +41 -0
  127. data/lib/hecks/bluebook/process_manager.rb +128 -0
  128. data/lib/hecks/bluebook/project_discovery.rb +30 -0
  129. data/lib/hecks/bluebook/project_loader.rb +40 -0
  130. data/lib/hecks/bluebook/project_register.rb +82 -0
  131. data/lib/hecks/bluebook/query.rb +61 -0
  132. data/lib/hecks/bluebook/read_model.rb +109 -0
  133. data/lib/hecks/bluebook/reference.rb +74 -0
  134. data/lib/hecks/bluebook/smoke_test.rb +166 -0
  135. data/lib/hecks/bluebook/synthesizer.rb +95 -0
  136. data/lib/hecks/bluebook/translation.rb +92 -0
  137. data/lib/hecks/bluebook/value_object.rb +66 -0
  138. data/lib/hecks/bluebook.rb +74 -0
  139. data/lib/hecks/codemod.rb +342 -0
  140. data/lib/hecks/construct.rb +71 -0
  141. data/lib/hecks/deploy/bluebook/deploy.bluebook +219 -0
  142. data/lib/hecks/deploy/bluebook/deploy.hecksagon +4 -0
  143. data/lib/hecks/deploy/oidc.json +18 -0
  144. data/lib/hecks/doc/reference.rb +410 -0
  145. data/lib/hecks/embryonaut_bluebook.rb +75 -0
  146. data/lib/hecks/facade/cli_door.rb +119 -0
  147. data/lib/hecks/facade/cli_runner.rb +190 -0
  148. data/lib/hecks/facade/command_request.rb +105 -0
  149. data/lib/hecks/facade/handle.rb +173 -0
  150. data/lib/hecks/facade/json_door.rb +166 -0
  151. data/lib/hecks/facade/surface/aggregate_door.rb +185 -0
  152. data/lib/hecks/facade/surface/chapter.rb +107 -0
  153. data/lib/hecks/facade/surface.rb +48 -0
  154. data/lib/hecks/facade.rb +44 -0
  155. data/lib/hecks/forms/app.rb +341 -0
  156. data/lib/hecks/forms/command_form_renderer.rb +113 -0
  157. data/lib/hecks/forms/examples/banking_console.bluebook +3 -0
  158. data/lib/hecks/forms/field_renderer.rb +177 -0
  159. data/lib/hecks/forms/field_shape.rb +232 -0
  160. data/lib/hecks/forms/html.rb +84 -0
  161. data/lib/hecks/forms/index_renderer.rb +35 -0
  162. data/lib/hecks/forms/page.rb +157 -0
  163. data/lib/hecks/forms/params.rb +161 -0
  164. data/lib/hecks/forms/port_argument.rb +46 -0
  165. data/lib/hecks/forms/query_form_renderer.rb +114 -0
  166. data/lib/hecks/forms/record_renderer.rb +119 -0
  167. data/lib/hecks/forms/record_table.rb +68 -0
  168. data/lib/hecks/forms/reference_options.rb +30 -0
  169. data/lib/hecks/forms/value_object_shape.rb +46 -0
  170. data/lib/hecks/forms.rb +54 -0
  171. data/lib/hecks/fqn.rb +94 -0
  172. data/lib/hecks/framework/bluebook/compliance.bluebook +1 -0
  173. data/lib/hecks/framework/bluebook/console_settings.bluebook +489 -0
  174. data/lib/hecks/framework/bluebook/framework.hecksagon +32 -0
  175. data/lib/hecks/framework/bluebook/governance.bluebook +145 -0
  176. data/lib/hecks/framework/bluebook/identity.bluebook +90 -0
  177. data/lib/hecks/framework/oidc.json +39 -0
  178. data/lib/hecks/framework.rb +90 -0
  179. data/lib/hecks/freezer.rb +67 -0
  180. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +527 -0
  181. data/lib/hecks/fuzzing/invalid_value_generator.rb +86 -0
  182. data/lib/hecks/fuzzing/isolated_boot.rb +286 -0
  183. data/lib/hecks/fuzzing/properties.rb +1192 -0
  184. data/lib/hecks/fuzzing/replay.rb +668 -0
  185. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +93 -0
  186. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +80 -0
  187. data/lib/hecks/fuzzing/sequence_generator/picker.rb +96 -0
  188. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +250 -0
  189. data/lib/hecks/fuzzing/sequence_generator.rb +131 -0
  190. data/lib/hecks/fuzzing/value_generator.rb +200 -0
  191. data/lib/hecks/fuzzing.rb +12 -0
  192. data/lib/hecks/grammar/evolve.rb +324 -0
  193. data/lib/hecks/grammar/expression.bluebook +420 -0
  194. data/lib/hecks/grammar/expression_operators.json +1648 -0
  195. data/lib/hecks/grammar/grammar.hecksagon +20 -0
  196. data/lib/hecks/grammar/oidc.json +69 -0
  197. data/lib/hecks/grammar/translation.bluebook +203 -0
  198. data/lib/hecks/grammar.rb +178 -0
  199. data/lib/hecks/ir.rb +126 -0
  200. data/lib/hecks/language/adapter.bluebook +116 -0
  201. data/lib/hecks/language/bluebook/aggregate.bluebook +581 -0
  202. data/lib/hecks/language/bluebook/attaches/paging.bluebook +76 -0
  203. data/lib/hecks/language/bluebook/bluebook.bluebook +256 -0
  204. data/lib/hecks/language/bluebook/bluebook.hecksagon +24 -0
  205. data/lib/hecks/language/bluebook/command.bluebook +471 -0
  206. data/lib/hecks/language/bluebook/entity.bluebook +392 -0
  207. data/lib/hecks/language/bluebook/policy.bluebook +189 -0
  208. data/lib/hecks/language/bluebook/process_manager.bluebook +381 -0
  209. data/lib/hecks/language/bluebook/projection.bluebook +267 -0
  210. data/lib/hecks/language/bluebook/query.bluebook +245 -0
  211. data/lib/hecks/language/bluebook/shape.bluebook +292 -0
  212. data/lib/hecks/language/bluebook/syntax.bluebook +448 -0
  213. data/lib/hecks/language/bluebook/vocabulary.bluebook +379 -0
  214. data/lib/hecks/language/hecksagon/adapter_binding.bluebook +51 -0
  215. data/lib/hecks/language/hecksagon/domain_port.bluebook +76 -0
  216. data/lib/hecks/language/hecksagon/hecksagon.bluebook +131 -0
  217. data/lib/hecks/language/hecksagon/port_operation.bluebook +102 -0
  218. data/lib/hecks/language/oidc.json +333 -0
  219. data/lib/hecks/language/port.bluebook +120 -0
  220. data/lib/hecks/language/translation/translation.bluebook +110 -0
  221. data/lib/hecks/language/translation/translation_aggregate.bluebook +267 -0
  222. data/lib/hecks/language/world/wiring.bluebook +62 -0
  223. data/lib/hecks/language/world/world.bluebook +84 -0
  224. data/lib/hecks/literal.rb +125 -0
  225. data/lib/hecks/naming.rb +174 -0
  226. data/lib/hecks/ports/access_control.port +9 -0
  227. data/lib/hecks/ports/access_control.rb +62 -0
  228. data/lib/hecks/ports/agent/answers.rb +104 -0
  229. data/lib/hecks/ports/agent.port +8 -0
  230. data/lib/hecks/ports/agent.rb +167 -0
  231. data/lib/hecks/ports/authentication.port +6 -0
  232. data/lib/hecks/ports/authentication.rb +50 -0
  233. data/lib/hecks/ports/authorization.port +7 -0
  234. data/lib/hecks/ports/authorization.rb +62 -0
  235. data/lib/hecks/ports/clock.port +5 -0
  236. data/lib/hecks/ports/clock.rb +62 -0
  237. data/lib/hecks/ports/extraction.port +5 -0
  238. data/lib/hecks/ports/extraction.rb +37 -0
  239. data/lib/hecks/ports/identity_assignment.port +5 -0
  240. data/lib/hecks/ports/identity_assignment.rb +45 -0
  241. data/lib/hecks/ports/identity_generation.port +5 -0
  242. data/lib/hecks/ports/identity_generation.rb +49 -0
  243. data/lib/hecks/ports/identity_resolution.port +5 -0
  244. data/lib/hecks/ports/identity_resolution.rb +40 -0
  245. data/lib/hecks/ports/loading.port +4 -0
  246. data/lib/hecks/ports/loading.rb +13 -0
  247. data/lib/hecks/ports/persistence/append_only.rb +138 -0
  248. data/lib/hecks/ports/persistence/binding_policy.rb +56 -0
  249. data/lib/hecks/ports/persistence/execution.rb +23 -0
  250. data/lib/hecks/ports/persistence/null_saga_store.rb +25 -0
  251. data/lib/hecks/ports/persistence/plugin.rb +54 -0
  252. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +169 -0
  253. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +128 -0
  254. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +161 -0
  255. data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +61 -0
  256. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +304 -0
  257. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +171 -0
  258. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +190 -0
  259. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +478 -0
  260. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +166 -0
  261. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +314 -0
  262. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +168 -0
  263. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +170 -0
  264. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +134 -0
  265. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +137 -0
  266. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +89 -0
  267. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +85 -0
  268. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +43 -0
  269. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +132 -0
  270. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +74 -0
  271. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +758 -0
  272. data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +120 -0
  273. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +31 -0
  274. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +46 -0
  275. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +102 -0
  276. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +46 -0
  277. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +70 -0
  278. data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +72 -0
  279. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +120 -0
  280. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +183 -0
  281. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +41 -0
  282. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +28 -0
  283. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +30 -0
  284. data/lib/hecks/ports/persistence/plugins/era/translation.rb +11 -0
  285. data/lib/hecks/ports/persistence/plugins/era.rb +48 -0
  286. data/lib/hecks/ports/persistence/remote_runtime.rb +42 -0
  287. data/lib/hecks/ports/persistence/repository_factory.rb +30 -0
  288. data/lib/hecks/ports/persistence.port +4 -0
  289. data/lib/hecks/ports/persistence.rb +39 -0
  290. data/lib/hecks/ports/projection.port +4 -0
  291. data/lib/hecks/ports/projection.rb +96 -0
  292. data/lib/hecks/ports/query/in_memory.rb +60 -0
  293. data/lib/hecks/ports/query/ordering.rb +41 -0
  294. data/lib/hecks/ports/query.rb +36 -0
  295. data/lib/hecks/ports.rb +27 -0
  296. data/lib/hecks/projections/diagrams.rb +642 -0
  297. data/lib/hecks/projections/ir.rb +18 -0
  298. data/lib/hecks/projections/model/deviations.rb +98 -0
  299. data/lib/hecks/projections/model.rb +145 -0
  300. data/lib/hecks/projections/oidc.rb +110 -0
  301. data/lib/hecks/projections/parser_table.rb +159 -0
  302. data/lib/hecks/projections/reference.rb +38 -0
  303. data/lib/hecks/projections/shape.rb +44 -0
  304. data/lib/hecks/projections/statements.rb +110 -0
  305. data/lib/hecks/projections/vocabulary.rb +100 -0
  306. data/lib/hecks/projections.rb +32 -0
  307. data/lib/hecks/projector/cli_projector.rb +446 -0
  308. data/lib/hecks/projector/docs_projector.rb +321 -0
  309. data/lib/hecks/projector/exporter.rb +158 -0
  310. data/lib/hecks/projector/ir_projector.rb +18 -0
  311. data/lib/hecks/projector/narrate_projector.rb +243 -0
  312. data/lib/hecks/projector/target.rb +97 -0
  313. data/lib/hecks/projector.rb +186 -0
  314. data/lib/hecks/query_ir.rb +411 -0
  315. data/lib/hecks/query_specification/common/authorization_spec.rb +9 -0
  316. data/lib/hecks/query_specification/common/comparators.rb +25 -0
  317. data/lib/hecks/query_specification/common/comparison.rb +174 -0
  318. data/lib/hecks/query_specification/common/cursor_spec.rb +9 -0
  319. data/lib/hecks/query_specification/common/dsl.rb +58 -0
  320. data/lib/hecks/query_specification/common/inspection_spec.rb +9 -0
  321. data/lib/hecks/query_specification/common/limit_spec.rb +9 -0
  322. data/lib/hecks/query_specification/common/null_policy.rb +92 -0
  323. data/lib/hecks/query_specification/common/null_semantics.rb +11 -0
  324. data/lib/hecks/query_specification/common/offset_spec.rb +9 -0
  325. data/lib/hecks/query_specification/common/options.rb +32 -0
  326. data/lib/hecks/query_specification/common/order_by.rb +9 -0
  327. data/lib/hecks/query_specification/common/specification.rb +10 -0
  328. data/lib/hecks/query_specification/common/where_clause.rb +9 -0
  329. data/lib/hecks/query_specification/field_path.rb +107 -0
  330. data/lib/hecks/query_specification/hop_path.rb +132 -0
  331. data/lib/hecks/query_specification/read_model/specification.rb +18 -0
  332. data/lib/hecks/query_specification.rb +14 -0
  333. data/lib/hecks/rendering.rb +48 -0
  334. data/lib/hecks/router/namespace_installer.rb +157 -0
  335. data/lib/hecks/router.rb +70 -0
  336. data/lib/hecks/runtime/aggregate_lock.rb +45 -0
  337. data/lib/hecks/runtime/boot_gates.rb +41 -0
  338. data/lib/hecks/runtime/caller.rb +66 -0
  339. data/lib/hecks/runtime/capability_graph.rb +44 -0
  340. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +135 -0
  341. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +260 -0
  342. data/lib/hecks/runtime/command_interpreter.rb +497 -0
  343. data/lib/hecks/runtime/command_rules/admissibility.rb +357 -0
  344. data/lib/hecks/runtime/command_rules/arithmetic.rb +260 -0
  345. data/lib/hecks/runtime/command_rules/authorization.rb +65 -0
  346. data/lib/hecks/runtime/command_rules/emission.rb +34 -0
  347. data/lib/hecks/runtime/command_rules/references.rb +189 -0
  348. data/lib/hecks/runtime/command_rules.rb +28 -0
  349. data/lib/hecks/runtime/dependency_planning.rb +245 -0
  350. data/lib/hecks/runtime/dispatcher.rb +301 -0
  351. data/lib/hecks/runtime/entity_element.rb +253 -0
  352. data/lib/hecks/runtime/entity_interpreter.rb +299 -0
  353. data/lib/hecks/runtime/errors.rb +122 -0
  354. data/lib/hecks/runtime/event.rb +51 -0
  355. data/lib/hecks/runtime/identity.rb +156 -0
  356. data/lib/hecks/runtime/instance.rb +175 -0
  357. data/lib/hecks/runtime/interpreting.rb +90 -0
  358. data/lib/hecks/runtime/loader.rb +184 -0
  359. data/lib/hecks/runtime/policy_interpreter.rb +366 -0
  360. data/lib/hecks/runtime/port_operation_interpreter.rb +210 -0
  361. data/lib/hecks/runtime/query_interpreter.rb +286 -0
  362. data/lib/hecks/runtime/reaction_invocation.rb +253 -0
  363. data/lib/hecks/runtime/read_model_interpreter.rb +341 -0
  364. data/lib/hecks/runtime/rebuild_sweep.rb +74 -0
  365. data/lib/hecks/runtime/reference_hop.rb +99 -0
  366. data/lib/hecks/runtime/refusal_wording.rb +126 -0
  367. data/lib/hecks/runtime/registry/saga_persistence.rb +142 -0
  368. data/lib/hecks/runtime/registry/verification.rb +246 -0
  369. data/lib/hecks/runtime/registry.rb +279 -0
  370. data/lib/hecks/runtime/remote_dispatcher.rb +143 -0
  371. data/lib/hecks/runtime/routing.rb +96 -0
  372. data/lib/hecks/runtime/saga_interpreter/correlation.rb +97 -0
  373. data/lib/hecks/runtime/saga_interpreter.rb +503 -0
  374. data/lib/hecks/runtime/saga_pending_dispatch.rb +45 -0
  375. data/lib/hecks/runtime/tenant_check.rb +84 -0
  376. data/lib/hecks/runtime/tenant_scope.rb +55 -0
  377. data/lib/hecks/runtime/value/admission.rb +130 -0
  378. data/lib/hecks/runtime/value/coercion.rb +565 -0
  379. data/lib/hecks/runtime/value/invariant_violation.rb +5 -0
  380. data/lib/hecks/runtime/value.rb +125 -0
  381. data/lib/hecks/runtime.rb +107 -0
  382. data/lib/hecks/storehouse.rb +632 -0
  383. data/lib/hecks/version.rb +16 -0
  384. data/lib/hecks/vocabulary.rb +218 -0
  385. data/lib/hecks.rb +123 -6
  386. data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +90 -0
  387. data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +128 -0
  388. data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +160 -0
  389. metadata +412 -222
  390. data/bin/hecks +0 -7
  391. data/bin/hecks-package +0 -65
  392. data/bin/hecks_console +0 -12
  393. data/bin/hecks_serverless +0 -6
  394. data/lib/cli/build.rb +0 -14
  395. data/lib/cli/command_runner.rb +0 -28
  396. data/lib/cli/console.rb +0 -10
  397. data/lib/cli/generate.rb +0 -37
  398. data/lib/cli/hecks-cli.rb +0 -27
  399. data/lib/cli/test.rb +0 -57
  400. data/lib/console/commands.rb +0 -8
  401. data/lib/console/hecks-console.rb +0 -1
  402. data/lib/packager/README.md +0 -0
  403. data/lib/packager/app_runner.rb +0 -21
  404. data/lib/packager/args.rb +0 -26
  405. data/lib/packager/compatibility/fixnum.rb +0 -6
  406. data/lib/packager/hecks.rb +0 -39
  407. data/lib/packager/query_runner.rb +0 -21
  408. data/lib/packager/resources/Dockerfile +0 -11
  409. data/lib/packager/resources/app_binary +0 -7
  410. data/lib/packager/resources/bundle_config +0 -3
  411. data/lib/packager/resources/traveling-ruby-20150715-2.2.2-linux-x86_64.tar.gz +0 -0
  412. data/lib/packager/resources/traveling-ruby-20150715-2.2.2-osx.tar.gz +0 -0
  413. data/lib/serverless/Domain +0 -32
  414. data/lib/serverless/cli.rb +0 -75
  415. data/lib/serverless/resources/command_name.js +0 -5
  416. data/lib/serverless/resources/environment.js +0 -7
  417. data/lib/serverless/resources/handler.js.tt +0 -28
  418. data/lib/serverless/resources/run_binary.js +0 -22
  419. data/lib/serverless/resources/serverless.yml +0 -20
@@ -0,0 +1,286 @@
1
+ require "fileutils"
2
+ require "tmpdir"
3
+ require "securerandom"
4
+
5
+ module Hecks
6
+ module Fuzzing
7
+ # A FRESH, IN-PROCESS ADAPTER FOR EVERY EPHEMERAL BOOT.
8
+ #
9
+ # Fuzzing/replay copies a domain to a tmpdir and boots from there
10
+ # specifically to get zero-history state — `rm_rf`ing the copy's own
11
+ # `data/` achieves that for a file-based adapter (Memory,
12
+ # SqlitePersistence, Heki), because copying the DIRECTORY copies the
13
+ # store. It achieves nothing for an adapter that lives outside the
14
+ # copied directory entirely — Postgres, named by a fixed connection
15
+ # string in `.world` (examples/pizzas/bluebook/pizzas.world, for
16
+ # instance). Copying the directory does not copy or isolate the
17
+ # DATABASE, so a "fresh" boot against a Postgres-bound domain would
18
+ # still see every record any other run, ever, wrote to it.
19
+ #
20
+ # So every `.hecksagon` in the copy gets its persistence binding
21
+ # rewritten to Memory before booting, and any `projected_by` bind
22
+ # dropped outright (optional — `Registry#read_repository` already
23
+ # falls back to the authoritative repository when none exists). The
24
+ # domain's own rules and shape are untouched ; only WHICH adapter this
25
+ # one ephemeral copy answers through changes. What the domain is
26
+ # bound to for real deployment is never touched — only this tmp copy.
27
+ #
28
+ # `adapter:` (PRD 02) — Memory is the default and the only mode every
29
+ # existing caller still gets with no change. `:sqlite` rebinds to the
30
+ # REAL SQLite adapter instead of the in-memory one, for exactly the
31
+ # same reason PRD 02 exists: 15 declared properties (properties.rb)
32
+ # and every fuzz/replay run has only ever been checked against
33
+ # Memory's own hand-written repository, never against a real,
34
+ # persisted, SQL-backed one — and `spec/adapters/query_agreement_spec
35
+ # .rb` already found 4 shipped query bugs from exactly that
36
+ # comparison, on a fixed corpus far smaller than what the fuzzer
37
+ # generates. `:sqlite` rewrites to `"SqlitePersistence"` — the name
38
+ # `lib/hecks/adapters/driven/sqlite.adapter` actually registers under
39
+ # (`Sqlite` is the class; `SqlitePersistence` is a thin subclass
40
+ # that's the one real port binding names) — and needs no `.world`
41
+ # settings at all, the same reason Memory needs none:
42
+ # `Sqlite#resolve_path` already defaults an
43
+ # unbound `database` setting to `"data/<table>.db"` relative to
44
+ # `root:`, which `Hecks.boot(copy)` passes as this ephemeral copy's
45
+ # own directory — a fresh, empty `data/` per run, exactly like
46
+ # Memory's own zero-history guarantee, just backed by a real SQLite
47
+ # file instead of a Hash. Postgres/PostgresEra are deliberately NOT
48
+ # added here: a real Postgres run needs a live server and shared
49
+ # connection settings this in-process, no-adapter-config path has no
50
+ # place to source safely — that stays `io: true`-gated, direct-adapter
51
+ # coverage (`spec/adapters/driven/postgres_*_spec.rb`), not this.
52
+ module IsolatedBoot
53
+ module_function
54
+
55
+ # PRD 02 (docs/future-features.md) — `adapter:` picks WHICH real
56
+ # persistence this one ephemeral boot answers through, not just
57
+ # Memory. `:memory` is the original, zero-config behavior (every
58
+ # other caller in this codebase that doesn't pass `adapter:` gets
59
+ # exactly what it always got). `:sqlite` is nearly as cheap —
60
+ # `Adapters::Sqlite#resolve_path` already defaults to
61
+ # `data/<table>.db` under the copy's own root with no settings at
62
+ # all, the same "needs nothing declared" property Memory has, so a
63
+ # real on-disk B-tree gets exercised for free. `:postgres` is the
64
+ # expensive one — a real server, a real round trip per dispatch —
65
+ # so `bin/fuzz --adapter postgres` is meant to run with smaller
66
+ # seed/step counts than the Memory default, not as a like-for-like
67
+ # swap; see that flag's own comment.
68
+ def call(domain_path, adapter: :memory)
69
+ Dir.mktmpdir("hecks-fuzz") do |tmp|
70
+ copy = File.join(tmp, File.basename(domain_path))
71
+ copy_dereferencing(domain_path, copy)
72
+ FileUtils.rm_rf(File.join(copy, "data"))
73
+ case adapter
74
+ when :memory then rebind_to_memory!(copy)
75
+ when :sqlite then rebind_to_sqlite!(copy)
76
+ when :postgres then rebind_to_postgres!(copy)
77
+ else raise ArgumentError, "unknown fuzz adapter #{adapter.inspect} — :memory, :sqlite, or :postgres"
78
+ end
79
+ yield copy
80
+ end
81
+ end
82
+
83
+ # SYMLINKS ARE FOLLOWED, NOT COPIED. `FileUtils.cp_r` reproduces a
84
+ # symlink AS a symlink, and a RELATIVE one then points at nothing
85
+ # from a tmpdir — `lib/hecks/framework/bluebook/compliance
86
+ # .bluebook` is exactly that, a link to
87
+ # `examples/compliance/bluebook/compliance.bluebook`, so the whole
88
+ # framework domain failed to boot here with a LoadError naming a
89
+ # path under /var/folders that had never existed. Nothing about the
90
+ # domain was wrong; the copy was.
91
+ #
92
+ # `FileUtils.cp` follows a symlink and copies its CONTENT, which is
93
+ # what an isolated boot wants: the copy has to stand alone, since
94
+ # rebind! rewrites files in it and must not reach back through a
95
+ # link into the real tree.
96
+ def copy_dereferencing(source, destination)
97
+ FileUtils.mkdir_p(destination)
98
+ Dir.glob(File.join(source, "**", "*"), File::FNM_DOTMATCH).each do |path|
99
+ next if [".", ".."].include?(File.basename(path))
100
+
101
+ target = File.join(destination, path.delete_prefix("#{source}/"))
102
+ if File.directory?(path)
103
+ FileUtils.mkdir_p(target)
104
+ else
105
+ FileUtils.mkdir_p(File.dirname(target))
106
+ FileUtils.cp(path, target)
107
+ end
108
+ end
109
+ end
110
+
111
+ def rebind_to_memory!(copy)
112
+ rewrite_bindings!(copy, "Memory")
113
+
114
+ # THE SETTINGS, NOT JUST THE BIND — `WorldBuilder#method_missing`
115
+ # stores a settings block under BOTH "verb:adapter" and the bare
116
+ # "verb" (world_builder.rb:32-33), so a bind rewritten to Memory
117
+ # still falls back to whatever adapter's settings were declared
118
+ # bare — Postgres's `database:`, which Memory does not take and
119
+ # WiringError refuses on sight. Both Memory and Sqlite need no
120
+ # settings at all (`Sqlite#resolve_path` defaults `database` to
121
+ # `data/<table>.db` under `root:` when unset — the same
122
+ # zero-config default Memory gets from having no `.world` at
123
+ # all), so the simplest correct fix for either target is
124
+ # dropping `.world` from the copy entirely.
125
+ Dir.glob(File.join(copy, "**", "*.world")).each { |path| File.delete(path) }
126
+ end
127
+
128
+ # SAME DANCE AS MEMORY, ONE ADAPTER OVER — `Adapters::Sqlite#
129
+ # resolve_path` (adapters/driven/sqlite.rb) defaults to
130
+ # `data/<table>.db` under the boot's own root when no `database`
131
+ # setting is declared, which `data/` already being cleared makes a
132
+ # fresh on-disk store with zero configuration, the same "no .world
133
+ # needed" property Memory has. `data/` itself is left for Sqlite to
134
+ # recreate on first write, same as it always was for Memory/Heki —
135
+ # nothing here creates it up front.
136
+ def rebind_to_sqlite!(copy)
137
+ rewrite_bindings!(copy, "SqlitePersistence")
138
+ Dir.glob(File.join(copy, "**", "*.world")).each { |path| File.delete(path) }
139
+ end
140
+
141
+ # THE EXPENSIVE ONE — Postgres has no zero-config default the way
142
+ # Sqlite/Memory do (`Adapters::Postgres.connect_for` refuses outright
143
+ # with no `database` setting), so dropping `.world` the way the
144
+ # other two do would just move the WiringError from "wrong adapter"
145
+ # to "no adapter." Every domain name this copy declares gets a
146
+ # FRESH `.world` written for it instead — not a rewrite of whatever
147
+ # was there, a replacement, same reasoning `rewrite_bindings!`
148
+ # already applies to `.hecksagon`: this ephemeral boot owns every
149
+ # binding decision, nothing about a real deployment's own settings
150
+ # is relevant or safe to half-preserve here.
151
+ #
152
+ # ONE SHARED SCHEMA, DROPPED AND RECREATED BEFORE EVERY BOOT — not a
153
+ # fresh randomly-named one per call. `bin/fuzz` drives every
154
+ # ephemeral boot sequentially (one `IsolatedBoot.call` fully exits
155
+ # before the next begins — see that file's own single-threaded
156
+ # `while` loop), so nothing is ever concurrent here ; a fresh name
157
+ # every time would just leak schemas in `FUZZ_POSTGRES_DATABASE`
158
+ # forever with nothing to ever drop them. If a caller ever DOES
159
+ # start running fuzz adapters concurrently, this needs to move to a
160
+ # process-unique schema name (`SecureRandom.hex` is already
161
+ # `require`d here for exactly that day) — flagged, not solved,
162
+ # since nothing today calls this from more than one thread.
163
+ FUZZ_POSTGRES_DATABASE = "hecks_fuzz"
164
+ FUZZ_POSTGRES_SCHEMA = "hecks_fuzz"
165
+
166
+ def rebind_to_postgres!(copy)
167
+ require "pg"
168
+ rewrite_bindings!(copy, "Postgres")
169
+ ensure_fuzz_schema!
170
+
171
+ # ONE `.world` PER DIRECTORY A `.hecksagon` ACTUALLY LIVES IN, not
172
+ # one at `copy`'s own root — `Folder#load_domain` resolves a
173
+ # SINGLE `bluebook_directory` and globs `*.world` there, non-
174
+ # recursively (`Folder#load_each`); a domain can hold several
175
+ # `Hecks.hecksagon "<Name>" do ... end` SIBLING blocks in that one
176
+ # file (banking.hecksagon declares "Banking", "Governance", and
177
+ # "Identity" together), so every name found in one `.hecksagon`
178
+ # file gets bundled into one `.world` written beside it, not
179
+ # scattered by name.
180
+ Dir.glob(File.join(copy, "**", "*.hecksagon")).each do |hecksagon_path|
181
+ names = File.read(hecksagon_path).scan(/Hecks\.hecksagon\s+"([^"]+)"/).flatten.uniq
182
+ next if names.empty?
183
+
184
+ world_path = File.join(File.dirname(hecksagon_path), "hecks_fuzz_postgres.world")
185
+ File.write(world_path, names.map { |name|
186
+ <<~WORLD
187
+ Hecks.world "#{name}" do
188
+ persisted_by("Postgres") do
189
+ database "#{FUZZ_POSTGRES_DATABASE}"
190
+ schema "#{FUZZ_POSTGRES_SCHEMA}"
191
+ end
192
+ end
193
+ WORLD
194
+ }.join("\n"))
195
+ end
196
+
197
+ # Any PRE-EXISTING `.world` this copy shipped with (a real
198
+ # deployment's own connection string) is now redundant with — and
199
+ # would conflict with, `Registry#add_world`'s own header on
200
+ # loading the same domain name twice — the fresh one just
201
+ # written above, so it goes the same way `rebind_to_memory!`
202
+ # already sends every `.world` in a Memory-mode boot.
203
+ Dir.glob(File.join(copy, "**", "*.world")).each do |path|
204
+ File.delete(path) unless File.basename(path) == "hecks_fuzz_postgres.world"
205
+ end
206
+ end
207
+
208
+ # ADMIN CONNECTION LIVES OUTSIDE THE TMP COPY ENTIRELY — same as
209
+ # every other real-Postgres spec in this repo (`support/
210
+ # postgres_probe.rb`'s own header). Database created once per
211
+ # process and remembered (`@fuzz_database_ready` on this module's
212
+ # own singleton, the same memoization shape `PostgresProbe
213
+ # .available?` already uses) ; the schema inside it is dropped and
214
+ # recreated on EVERY call, which is what actually isolates one
215
+ # ephemeral boot's data from the next.
216
+ def ensure_fuzz_schema!
217
+ # `Adapters::Postgres#initialize` opens ONE real `PG::Connection`
218
+ # PER AGGREGATE and never explicitly closes it — fine for a
219
+ # process that boots once and runs, exactly what every other
220
+ # caller of this adapter is. A fuzz run boots dozens to hundreds
221
+ # of EPHEMERAL times in one process (every seed does at least a
222
+ # generate + a replay, `replay_is_deterministic` doubles that,
223
+ # shrinking multiplies it further), and `PG::Connection` only
224
+ # actually closes its socket when Ruby's GC finalizes the
225
+ # (by-then-unreferenced) object — which, under a tight loop like
226
+ # this, does not reliably keep pace with how fast new
227
+ # connections open. Discovered live: `bin/fuzz --adapter
228
+ # postgres` against `examples/banking` hit a real local
229
+ # Postgres's own `max_connections` after roughly a dozen
230
+ # ephemeral boots, `PG::ConnectionBad: ... "too many clients
231
+ # already"`. A `GC.start` here — right before the next ephemeral
232
+ # boot's connections open, not on some timer — reclaims every
233
+ # connection the PREVIOUS boot's now-unreferenced adapters held,
234
+ # keeping the live count bounded regardless of run length. This
235
+ # is a real constraint on running Postgres in a loop, not
236
+ # something to route around by connecting less carefully.
237
+ GC.start
238
+
239
+ unless @fuzz_database_ready
240
+ admin = PG.connect(dbname: "postgres")
241
+ exists = admin.exec_params(
242
+ "SELECT 1 FROM pg_database WHERE datname = $1", [FUZZ_POSTGRES_DATABASE]
243
+ ).ntuples.positive?
244
+ admin.exec(%(CREATE DATABASE "#{FUZZ_POSTGRES_DATABASE}")) unless exists
245
+ admin.close
246
+ @fuzz_database_ready = true
247
+ end
248
+
249
+ db = PG.connect(dbname: FUZZ_POSTGRES_DATABASE)
250
+ # QUIET ON PURPOSE — same as `Adapters::Postgres.connect_for`'s
251
+ # own `SET client_min_messages`: a `DROP SCHEMA ... CASCADE` that
252
+ # actually has something to drop (every boot after the first)
253
+ # NOTICEs once per dropped object, which is the ordinary case
254
+ # here, not news, and would otherwise bury `bin/fuzz`'s own
255
+ # output under a wall of "drop cascades to table ..." on every
256
+ # single ephemeral boot.
257
+ db.exec("SET client_min_messages = warning")
258
+ quoted = db.quote_ident(FUZZ_POSTGRES_SCHEMA)
259
+ db.exec("DROP SCHEMA IF EXISTS #{quoted} CASCADE")
260
+ db.exec("CREATE SCHEMA #{quoted}")
261
+ db.close
262
+ end
263
+
264
+ # THE SHARED REWRITE — factored out of `rebind_to_memory!` when
265
+ # Sqlite/Postgres modes needed the identical `.hecksagon` surgery
266
+ # with only the target adapter name differing. `persisted_by`/
267
+ # `projected_by` can be spelled two ways: aggregate-scoped
268
+ # (`Banking::Customer.persisted_by("Heki")`, always parenthesised)
269
+ # and, since §0's domain-level default binds, a bare call at the
270
+ # hecksagon's own root (`persisted_by "Heki"`, no parens, no
271
+ # receiver). Both must be caught here or a domain that only
272
+ # declares the bare form keeps its real adapter under an
273
+ # "isolated" fuzz boot. `projected_by` is dropped outright rather
274
+ # than rebound, for every target adapter — `Registry
275
+ # #read_repository` already falls back to the authoritative
276
+ # repository when none exists, so a read model this ephemeral copy
277
+ # never wires is simply unread, not broken.
278
+ def rewrite_bindings!(copy, adapter_name)
279
+ Dir.glob(File.join(copy, "**", "*.hecksagon")).each do |path|
280
+ lines = File.readlines(path).reject { |line| line.match?(/\bprojected_by\s*\(?\s*"/) }
281
+ File.write(path, lines.join.gsub(/persisted_by\s*\(?\s*"[^"]+"\s*\)?/, "persisted_by(\"#{adapter_name}\")"))
282
+ end
283
+ end
284
+ end
285
+ end
286
+ end