hecks 2.8.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (886) hide show
  1. checksums.yaml +4 -4
  2. data/exe/hecks +50 -7
  3. data/lib/hecks/adapters/driven/claude_code.rb +4 -104
  4. data/lib/hecks/adapters/driven/d1.rb +44 -237
  5. data/lib/hecks/adapters/driven/folder.rb +17 -76
  6. data/lib/hecks/adapters/driven/google_authentication.rb +15 -49
  7. data/lib/hecks/adapters/driven/governance_authorization.rb +23 -70
  8. data/lib/hecks/adapters/driven/heki/journal.rb +8 -41
  9. data/lib/hecks/adapters/driven/heki/saga_store.rb +12 -54
  10. data/lib/hecks/adapters/driven/heki/snapshot.rb +4 -12
  11. data/lib/hecks/adapters/driven/heki.rb +13 -42
  12. data/lib/hecks/adapters/driven/identity_registry.rb +3 -14
  13. data/lib/hecks/adapters/driven/in_memory_ordering.rb +9 -26
  14. data/lib/hecks/adapters/driven/in_process_key_vault.rb +2 -14
  15. data/lib/hecks/adapters/driven/lambda/client.rb +10 -51
  16. data/lib/hecks/adapters/driven/lambda.rb +10 -84
  17. data/lib/hecks/adapters/driven/local_storage.rb +5 -40
  18. data/lib/hecks/adapters/driven/memory.rb +32 -100
  19. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +5 -21
  20. data/lib/hecks/adapters/driven/postgres/codec.rb +6 -28
  21. data/lib/hecks/adapters/driven/postgres/outbox.rb +3 -12
  22. data/lib/hecks/adapters/driven/postgres/reconnect.rb +10 -32
  23. data/lib/hecks/adapters/driven/postgres/schema_builder.rb +34 -108
  24. data/lib/hecks/adapters/driven/postgres/shared_connection.rb +180 -0
  25. data/lib/hecks/adapters/driven/postgres.rb +149 -136
  26. data/lib/hecks/adapters/driven/postgres_era.adapter +4 -15
  27. data/lib/hecks/adapters/driven/prism.rb +48 -38
  28. data/lib/hecks/adapters/driven/sql_query_builder.rb +21 -121
  29. data/lib/hecks/adapters/driven/sqlite/codec.rb +8 -40
  30. data/lib/hecks/adapters/driven/sqlite/projection.rb +26 -82
  31. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +40 -84
  32. data/lib/hecks/adapters/driven/sqlite.rb +128 -65
  33. data/lib/hecks/adapters/driven/tenant_provisioner.rb +76 -62
  34. data/lib/hecks/adapters/driven.rb +5 -36
  35. data/lib/hecks/adapters/driving/github_webhook.rb +8 -76
  36. data/lib/hecks/behaviors/dsl.rb +7 -25
  37. data/lib/hecks/behaviors/expectations.rb +32 -142
  38. data/lib/hecks/behaviors/ir.rb +7 -20
  39. data/lib/hecks/behaviors/rspec.rb +6 -17
  40. data/lib/hecks/behaviors/runner.rb +10 -34
  41. data/lib/hecks/behaviors.rb +4 -8
  42. data/lib/hecks/bench/cli.rb +62 -0
  43. data/lib/hecks/bench/environment.rb +71 -0
  44. data/lib/hecks/bench/postgres_probe.rb +30 -0
  45. data/lib/hecks/bench/report.rb +76 -0
  46. data/lib/hecks/bench/ruby_runner.rb +93 -0
  47. data/lib/hecks/bench/run.rb +55 -0
  48. data/lib/hecks/bench/rust_runner.rb +101 -0
  49. data/lib/hecks/bench/stats.rb +46 -0
  50. data/lib/hecks/bench/suite.rb +98 -0
  51. data/lib/hecks/bench/workload.rb +89 -0
  52. data/lib/hecks/bench.rb +17 -0
  53. data/lib/hecks/bluebook/aggregate.rb +9 -75
  54. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +9 -38
  55. data/lib/hecks/bluebook/assembly/build.rb +4 -15
  56. data/lib/hecks/bluebook/assembly/contract.rb +15 -136
  57. data/lib/hecks/bluebook/assembly/contracts.rb +56 -174
  58. data/lib/hecks/bluebook/assembly/marks.rb +31 -223
  59. data/lib/hecks/bluebook/assembly/specializer.rb +6 -52
  60. data/lib/hecks/bluebook/assembly.rb +6 -45
  61. data/lib/hecks/bluebook/attribute.rb +12 -61
  62. data/lib/hecks/bluebook/behaviour/aggregate.rb +39 -39
  63. data/lib/hecks/bluebook/behaviour/attribute.rb +3 -14
  64. data/lib/hecks/bluebook/behaviour/chapter.rb +14 -42
  65. data/lib/hecks/bluebook/behaviour/command.rb +14 -66
  66. data/lib/hecks/bluebook/behaviour/domain_port.rb +11 -20
  67. data/lib/hecks/bluebook/behaviour/entity.rb +7 -27
  68. data/lib/hecks/bluebook/behaviour/hexagon.rb +23 -41
  69. data/lib/hecks/bluebook/behaviour/lifecycle.rb +15 -40
  70. data/lib/hecks/bluebook/behaviour/policy.rb +23 -52
  71. data/lib/hecks/bluebook/behaviour/process_manager.rb +30 -57
  72. data/lib/hecks/bluebook/behaviour/read_model.rb +25 -31
  73. data/lib/hecks/bluebook/behaviour/traits.rb +27 -64
  74. data/lib/hecks/bluebook/behaviour/value_object.rb +5 -24
  75. data/lib/hecks/bluebook/capabilities.rb +17 -49
  76. data/lib/hecks/bluebook/chapter.rb +16 -50
  77. data/lib/hecks/bluebook/command.rb +23 -81
  78. data/lib/hecks/bluebook/domain_port.rb +49 -67
  79. data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +50 -229
  80. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +50 -377
  81. data/lib/hecks/bluebook/dsl/attribute_collector.rb +33 -204
  82. data/lib/hecks/bluebook/dsl/binding_proxy.rb +16 -69
  83. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +96 -708
  84. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +63 -169
  85. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +3 -1
  86. data/lib/hecks/bluebook/dsl/command_builder.rb +74 -546
  87. data/lib/hecks/bluebook/dsl/const_shim.rb +8 -41
  88. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +42 -89
  89. data/lib/hecks/bluebook/dsl/entity_builder.rb +44 -330
  90. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +20 -269
  91. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +148 -197
  92. data/lib/hecks/bluebook/dsl/identity_declaration.rb +13 -88
  93. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +6 -20
  94. data/lib/hecks/bluebook/dsl/policy_builder.rb +16 -88
  95. data/lib/hecks/bluebook/dsl/port_builder.rb +2 -6
  96. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +22 -96
  97. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +31 -184
  98. data/lib/hecks/bluebook/dsl/query_builder.rb +38 -43
  99. data/lib/hecks/bluebook/dsl/read_model_builder.rb +75 -201
  100. data/lib/hecks/bluebook/dsl/rule_reference.rb +22 -163
  101. data/lib/hecks/bluebook/dsl/translation_builder.rb +28 -114
  102. data/lib/hecks/bluebook/dsl/value_object_builder.rb +10 -124
  103. data/lib/hecks/bluebook/dsl/word_gate.rb +16 -162
  104. data/lib/hecks/bluebook/dsl/world_builder.rb +46 -111
  105. data/lib/hecks/bluebook/entity.rb +13 -71
  106. data/lib/hecks/bluebook/expression/ast_json.rb +24 -190
  107. data/lib/hecks/bluebook/expression/ast_reader.rb +12 -54
  108. data/lib/hecks/bluebook/expression/canonical_form.rb +11 -88
  109. data/lib/hecks/bluebook/expression/evaluator.rb +47 -295
  110. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +30 -147
  111. data/lib/hecks/bluebook/expression/resolver.rb +39 -661
  112. data/lib/hecks/bluebook/hexagon.rb +18 -33
  113. data/lib/hecks/bluebook/lifecycle.rb +5 -16
  114. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -7
  115. data/lib/hecks/bluebook/meta_validator/judge.rb +111 -361
  116. data/lib/hecks/bluebook/meta_validator/plan.rb +33 -162
  117. data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -7
  118. data/lib/hecks/bluebook/meta_validator/readings.rb +56 -342
  119. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +25 -176
  120. data/lib/hecks/bluebook/meta_validator/shapes.rb +53 -267
  121. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +47 -306
  122. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +7 -43
  123. data/lib/hecks/bluebook/meta_validator/verdict_cache.rb +246 -0
  124. data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -18
  125. data/lib/hecks/bluebook/meta_validator.rb +87 -352
  126. data/lib/hecks/bluebook/model_check/client_profile.rb +6 -21
  127. data/lib/hecks/bluebook/model_check.rb +122 -596
  128. data/lib/hecks/bluebook/pattern_subset.rb +49 -69
  129. data/lib/hecks/bluebook/process_manager.rb +13 -83
  130. data/lib/hecks/bluebook/project_loader.rb +3 -39
  131. data/lib/hecks/bluebook/project_register.rb +12 -60
  132. data/lib/hecks/bluebook/query.rb +27 -51
  133. data/lib/hecks/bluebook/read_model.rb +57 -81
  134. data/lib/hecks/bluebook/reference.rb +7 -41
  135. data/lib/hecks/bluebook/smoke_test.rb +9 -99
  136. data/lib/hecks/bluebook/synthesizer.rb +13 -62
  137. data/lib/hecks/bluebook/translation.rb +26 -62
  138. data/lib/hecks/bluebook/value_object.rb +11 -36
  139. data/lib/hecks/bluebook.rb +5 -22
  140. data/lib/hecks/cache_dir.rb +4 -23
  141. data/lib/hecks/canonical_json.rb +30 -0
  142. data/lib/hecks/chapters.rb +102 -0
  143. data/lib/hecks/cli/behaviors.rb +61 -0
  144. data/lib/hecks/cli/canonicalise.rb +25 -0
  145. data/lib/hecks/cli/check_engine_agreement.rb +32 -0
  146. data/lib/hecks/cli/check_era.rb +88 -0
  147. data/lib/hecks/cli/console.rb +66 -0
  148. data/lib/hecks/cli/deploy_template_diff.rb +40 -0
  149. data/lib/hecks/cli/doc_coverage.rb +32 -0
  150. data/lib/hecks/cli/document.rb +5 -23
  151. data/lib/hecks/cli/expression_projection.rb +41 -0
  152. data/lib/hecks/cli/follow.rb +88 -0
  153. data/lib/hecks/cli/history.rb +44 -0
  154. data/lib/hecks/cli/ir.rb +4 -6
  155. data/lib/hecks/cli/mcp.rb +5 -6
  156. data/lib/hecks/cli/model_check.rb +24 -88
  157. data/lib/hecks/cli/pattern_cases.rb +47 -0
  158. data/lib/hecks/cli/present.rb +39 -0
  159. data/lib/hecks/cli/project_cli.rb +223 -64
  160. data/lib/hecks/cli/project_diagrams.rb +4 -10
  161. data/lib/hecks/cli/project_glossary.rb +44 -0
  162. data/lib/hecks/cli/reference.rb +46 -0
  163. data/lib/hecks/cli/refresh_projections.rb +44 -0
  164. data/lib/hecks/cli/refresh_rspec_runtime_baseline.rb +150 -0
  165. data/lib/hecks/cli/release.rb +70 -0
  166. data/lib/hecks/cli/release_gem.rb +59 -0
  167. data/lib/hecks/cli/rspec_io_parallel_files.rb +137 -0
  168. data/lib/hecks/cli/rspec_shard_files.rb +66 -0
  169. data/lib/hecks/cli/run.rb +15 -61
  170. data/lib/hecks/cli/seed_semantics_corpus.rb +71 -0
  171. data/lib/hecks/cli/serve_query_ir_mcp.rb +30 -0
  172. data/lib/hecks/cli/shape.rb +70 -0
  173. data/lib/hecks/cli/smoke_http.rb +230 -0
  174. data/lib/hecks/cli/smoke_test.rb +7 -19
  175. data/lib/hecks/cli/spec_example.rb +27 -0
  176. data/lib/hecks/cli/statements.rb +32 -0
  177. data/lib/hecks/cli/stores.rb +4 -6
  178. data/lib/hecks/cli/stress_concurrency_specs.rb +177 -0
  179. data/lib/hecks/cli.rb +216 -73
  180. data/lib/hecks/codemod.rb +324 -0
  181. data/lib/hecks/construct.rb +8 -34
  182. data/lib/hecks/corpus.rb +423 -0
  183. data/lib/hecks/deploy/bluebook/deploy.bluebook +617 -158
  184. data/lib/hecks/deploy/bluebook/deploy.hecksagon +41 -11
  185. data/lib/hecks/deploy/oidc.json +82 -2
  186. data/lib/hecks/doc/reference.rb +351 -0
  187. data/lib/hecks/doors/cli_door.rb +196 -0
  188. data/lib/hecks/doors/cli_runner.rb +297 -0
  189. data/lib/hecks/{facade → doors}/command_request.rb +14 -34
  190. data/lib/hecks/doors/handle.rb +206 -0
  191. data/lib/hecks/doors/json_door.rb +132 -0
  192. data/lib/hecks/doors/launcher_options.rb +129 -0
  193. data/lib/hecks/{cli → doors}/mcp_door.rb +25 -120
  194. data/lib/hecks/doors/mcp_door_scope.rb +97 -0
  195. data/lib/hecks/doors/ruby_door/aggregate_door.rb +162 -0
  196. data/lib/hecks/doors/ruby_door/chapter.rb +72 -0
  197. data/lib/hecks/doors/ruby_door.rb +77 -0
  198. data/lib/hecks/doors.rb +61 -0
  199. data/lib/hecks/embryonaut_bluebook/lock.rb +3 -35
  200. data/lib/hecks/embryonaut_bluebook/shape.rb +1 -17
  201. data/lib/hecks/embryonaut_bluebook/vendor.rb +8 -53
  202. data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +4 -19
  203. data/lib/hecks/embryonaut_bluebook.rb +5 -72
  204. data/lib/hecks/engine_agreement.rb +156 -0
  205. data/lib/hecks/facade.rb +23 -51
  206. data/lib/hecks/forms/app.rb +21 -76
  207. data/lib/hecks/forms/banking_presentation.rb +50 -0
  208. data/lib/hecks/forms/command_form_renderer.rb +10 -29
  209. data/lib/hecks/forms/field_renderer.rb +17 -156
  210. data/lib/hecks/forms/field_shape.rb +31 -222
  211. data/lib/hecks/forms/html.rb +12 -47
  212. data/lib/hecks/forms/index_renderer.rb +1 -4
  213. data/lib/hecks/forms/page.rb +3 -9
  214. data/lib/hecks/forms/params.rb +14 -60
  215. data/lib/hecks/forms/port_argument.rb +2 -19
  216. data/lib/hecks/forms/query_form_renderer.rb +4 -79
  217. data/lib/hecks/forms/record_renderer.rb +8 -75
  218. data/lib/hecks/forms/record_table.rb +7 -50
  219. data/lib/hecks/forms/reference_options.rb +3 -30
  220. data/lib/hecks/forms/value_object_shape.rb +8 -35
  221. data/lib/hecks/forms.rb +5 -33
  222. data/lib/hecks/fqn.rb +5 -12
  223. data/lib/hecks/framework/bluebook/compliance.bluebook +16 -65
  224. data/lib/hecks/framework/bluebook/console_settings.bluebook +47 -134
  225. data/lib/hecks/framework/bluebook/framework.hecksagon +5 -14
  226. data/lib/hecks/framework/bluebook/governance.bluebook +13 -34
  227. data/lib/hecks/framework/bluebook/identity.bluebook +11 -26
  228. data/lib/hecks/framework/bluebook/privacy.bluebook +8 -33
  229. data/lib/hecks/framework.rb +11 -80
  230. data/lib/hecks/freezer.rb +5 -39
  231. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +393 -0
  232. data/lib/hecks/fuzzing/combination_miner.rb +86 -0
  233. data/lib/hecks/fuzzing/concurrent_dispatch.rb +214 -0
  234. data/lib/hecks/fuzzing/coverage_campaign.rb +143 -0
  235. data/lib/hecks/fuzzing/differential.rb +156 -0
  236. data/lib/hecks/fuzzing/domain_generator.rb +615 -0
  237. data/lib/hecks/fuzzing/era_boundary.rb +71 -0
  238. data/lib/hecks/fuzzing/form_census.rb +136 -0
  239. data/lib/hecks/fuzzing/generated_domain_check.rb +93 -0
  240. data/lib/hecks/fuzzing/invalid_value_generator.rb +64 -0
  241. data/lib/hecks/fuzzing/isolated_boot.rb +301 -0
  242. data/lib/hecks/fuzzing/nondeterministic.rb +51 -0
  243. data/lib/hecks/fuzzing/outside_world.rb +45 -0
  244. data/lib/hecks/fuzzing/persistence_parity.rb +102 -0
  245. data/lib/hecks/fuzzing/properties/corrections.rb +88 -0
  246. data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +314 -0
  247. data/lib/hecks/fuzzing/properties/guards.rb +190 -0
  248. data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +300 -0
  249. data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +93 -0
  250. data/lib/hecks/fuzzing/properties/outbox.rb +89 -0
  251. data/lib/hecks/fuzzing/properties/querying.rb +175 -0
  252. data/lib/hecks/fuzzing/properties.rb +162 -0
  253. data/lib/hecks/fuzzing/qa_settings.rb +123 -0
  254. data/lib/hecks/fuzzing/replay.rb +505 -0
  255. data/lib/hecks/fuzzing/rotation_priority.rb +48 -0
  256. data/lib/hecks/fuzzing/rust_gap_manifest.rb +108 -0
  257. data/lib/hecks/fuzzing/self_consistency.rb +339 -0
  258. data/lib/hecks/fuzzing/sequence_generator/adversary.rb +385 -0
  259. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +132 -0
  260. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +95 -0
  261. data/lib/hecks/fuzzing/sequence_generator/picker.rb +77 -0
  262. data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +109 -0
  263. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +237 -0
  264. data/lib/hecks/fuzzing/sequence_generator.rb +189 -0
  265. data/lib/hecks/fuzzing/shrinker.rb +166 -0
  266. data/lib/hecks/fuzzing/structural_skips.rb +33 -0
  267. data/lib/hecks/fuzzing/sweep_depth.rb +43 -0
  268. data/lib/hecks/fuzzing/target_capabilities.rb +163 -0
  269. data/lib/hecks/fuzzing/value_generator.rb +216 -0
  270. data/lib/hecks/fuzzing.rb +23 -0
  271. data/lib/hecks/grammar/evolve.rb +336 -0
  272. data/lib/hecks/grammar/expression.bluebook +15 -40
  273. data/lib/hecks/grammar/translation.bluebook +3 -6
  274. data/lib/hecks/grammar.rb +16 -41
  275. data/lib/hecks/hecks/adapters/codebase/codemods.rb +45 -0
  276. data/lib/hecks/hecks/adapters/codebase/conformance.rb +71 -0
  277. data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +202 -0
  278. data/lib/hecks/hecks/adapters/codebase/gem_registry.rb +80 -0
  279. data/lib/hecks/hecks/adapters/codebase/kernel_tables.rb +54 -0
  280. data/lib/hecks/hecks/adapters/codebase/language.rb +240 -0
  281. data/lib/hecks/hecks/adapters/codebase/npm_registry.rb +102 -0
  282. data/lib/hecks/hecks/adapters/codebase/publishing.rb +142 -0
  283. data/lib/hecks/hecks/adapters/codebase/regeneration.rb +67 -0
  284. data/lib/hecks/hecks/adapters/codebase/release_facts.rb +90 -0
  285. data/lib/hecks/hecks/adapters/codebase/ruby_child.rb +83 -0
  286. data/lib/hecks/hecks/adapters/codebase/secret_vault.rb +36 -0
  287. data/lib/hecks/hecks/adapters/codebase/source_tree.adapter +7 -0
  288. data/lib/hecks/hecks/adapters/codebase/source_tree.rb +189 -0
  289. data/lib/hecks/hecks/adapters/codebase/sqlite_fixture.rb +71 -0
  290. data/lib/hecks/hecks/adapters/codebase/style.rb +171 -0
  291. data/lib/hecks/hecks/adapters/codebase/test_runner.rb +55 -0
  292. data/lib/hecks/hecks/adapters/codebase/test_suite.rb +165 -0
  293. data/lib/hecks/hecks/adapters/codebase/tree.rb +111 -0
  294. data/lib/hecks/hecks/adapters/console_capture.rb +79 -0
  295. data/lib/hecks/hecks/adapters/deploy_toolchain.adapter +7 -0
  296. data/lib/hecks/hecks/adapters/deploy_toolchain.rb +108 -0
  297. data/lib/hecks/hecks/adapters/git.adapter +7 -0
  298. data/lib/hecks/hecks/adapters/git.rb +102 -0
  299. data/lib/hecks/hecks/adapters/host_http.adapter +7 -0
  300. data/lib/hecks/hecks/adapters/host_http.rb +65 -0
  301. data/lib/hecks/hecks/adapters/in_process_boot.adapter +7 -0
  302. data/lib/hecks/hecks/adapters/in_process_boot.rb +197 -0
  303. data/lib/hecks/hecks/adapters/in_process_operations.rb +202 -0
  304. data/lib/hecks/hecks/adapters/journal_store/changes.rb +143 -0
  305. data/lib/hecks/hecks/adapters/journal_store/compaction.rb +145 -0
  306. data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +132 -0
  307. data/lib/hecks/hecks/adapters/journal_store/examination.rb +135 -0
  308. data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +163 -0
  309. data/lib/hecks/hecks/adapters/journal_store/readings.rb +187 -0
  310. data/lib/hecks/hecks/adapters/journal_store.adapter +7 -0
  311. data/lib/hecks/hecks/adapters/journal_store.rb +64 -0
  312. data/lib/hecks/hecks/adapters/local_files.adapter +7 -0
  313. data/lib/hecks/hecks/adapters/local_files.rb +46 -0
  314. data/lib/hecks/hecks/adapters/pg_admin.adapter +7 -0
  315. data/lib/hecks/hecks/adapters/pg_admin.rb +245 -0
  316. data/lib/hecks/hecks/adapters/process_pool.adapter +7 -0
  317. data/lib/hecks/hecks/adapters/process_pool.rb +119 -0
  318. data/lib/hecks/hecks/adapters/rust_toolchain.adapter +7 -0
  319. data/lib/hecks/hecks/adapters/rust_toolchain.rb +179 -0
  320. data/lib/hecks/hecks/adapters/rust_workspace.rb +150 -0
  321. data/lib/hecks/hecks/adapters/shell.adapter +7 -0
  322. data/lib/hecks/hecks/adapters/shell.rb +49 -0
  323. data/lib/hecks/hecks/adapters/terminal.adapter +7 -0
  324. data/lib/hecks/hecks/adapters/terminal.rb +74 -0
  325. data/lib/hecks/hecks/codebase.behaviors +172 -0
  326. data/lib/hecks/hecks/codebase.bluebook +2453 -0
  327. data/lib/hecks/hecks/context_map.hecksagon +13 -0
  328. data/lib/hecks/hecks/custodian.behaviors +179 -0
  329. data/lib/hecks/hecks/custodian.bluebook +1847 -0
  330. data/lib/hecks/hecks/deploy.behaviors +74 -0
  331. data/lib/hecks/hecks/deploy.world +12 -0
  332. data/lib/hecks/hecks/environments/memory.world +10 -0
  333. data/lib/hecks/hecks/governance.world +7 -0
  334. data/lib/hecks/hecks/hecks.behaviors +62 -0
  335. data/lib/hecks/hecks/hecks.bluebook +124 -0
  336. data/lib/hecks/hecks/hecks.hecksagon +390 -0
  337. data/lib/hecks/hecks/hecks.world +42 -0
  338. data/lib/hecks/ir.rb +14 -83
  339. data/lib/hecks/kernel_capabilities.rb +194 -0
  340. data/lib/hecks/language/adapter.bluebook +2 -7
  341. data/lib/hecks/language/bluebook/aggregate.bluebook +56 -221
  342. data/lib/hecks/language/bluebook/attaches/paging.bluebook +6 -15
  343. data/lib/hecks/language/bluebook/bluebook.bluebook +26 -83
  344. data/lib/hecks/language/bluebook/bluebook.hecksagon +3 -15
  345. data/lib/hecks/language/bluebook/command.bluebook +27 -144
  346. data/lib/hecks/language/bluebook/entity.bluebook +24 -97
  347. data/lib/hecks/language/bluebook/policy.bluebook +16 -67
  348. data/lib/hecks/language/bluebook/process_manager.bluebook +28 -151
  349. data/lib/hecks/language/bluebook/projection.bluebook +126 -60
  350. data/lib/hecks/language/bluebook/query.bluebook +19 -43
  351. data/lib/hecks/language/bluebook/shape.bluebook +23 -73
  352. data/lib/hecks/language/bluebook/syntax.bluebook +51 -262
  353. data/lib/hecks/language/bluebook/vocabulary.bluebook +83 -198
  354. data/lib/hecks/language/hecksagon/adapter_binding.bluebook +3 -10
  355. data/lib/hecks/language/hecksagon/domain_port.bluebook +14 -19
  356. data/lib/hecks/language/hecksagon/hecksagon.bluebook +26 -25
  357. data/lib/hecks/language/hecksagon/port_operation.bluebook +3 -14
  358. data/lib/hecks/language/oidc.json +35 -0
  359. data/lib/hecks/language/port.bluebook +4 -17
  360. data/lib/hecks/language/translation/translation.bluebook +3 -9
  361. data/lib/hecks/language/translation/translation_aggregate.bluebook +5 -24
  362. data/lib/hecks/language/world/wiring.bluebook +1 -3
  363. data/lib/hecks/language/world/world.bluebook +5 -7
  364. data/lib/hecks/literal.rb +8 -50
  365. data/lib/hecks/mcp_stdio_guard.rb +4 -41
  366. data/lib/hecks/naming.rb +29 -137
  367. data/lib/hecks/persistence_legacy_fixture/regenerate.rb +161 -0
  368. data/lib/hecks/persistence_legacy_fixture.rb +113 -0
  369. data/lib/hecks/ports/access_control.rb +7 -23
  370. data/lib/hecks/ports/agent/answers.rb +5 -23
  371. data/lib/hecks/ports/agent.rb +47 -172
  372. data/lib/hecks/ports/authentication.rb +12 -39
  373. data/lib/hecks/ports/authorization.rb +16 -43
  374. data/lib/hecks/ports/clock.rb +5 -45
  375. data/lib/hecks/ports/extraction.rb +7 -12
  376. data/lib/hecks/ports/identity_assignment.rb +8 -29
  377. data/lib/hecks/ports/identity_generation.rb +6 -29
  378. data/lib/hecks/ports/identity_resolution.rb +2 -10
  379. data/lib/hecks/ports/key_vault.rb +9 -45
  380. data/lib/hecks/ports/persistence/append_only.rb +61 -64
  381. data/lib/hecks/ports/persistence/binding_policy.rb +4 -14
  382. data/lib/hecks/ports/persistence/codec_boundary.rb +20 -80
  383. data/lib/hecks/ports/persistence/null_saga_store.rb +4 -20
  384. data/lib/hecks/ports/persistence/plugin.rb +13 -42
  385. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +44 -144
  386. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +15 -115
  387. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +20 -85
  388. data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +6 -25
  389. data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +18 -24
  390. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +55 -181
  391. data/lib/hecks/ports/persistence/plugins/era/postgres_era/events.rb +77 -0
  392. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +12 -122
  393. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +28 -128
  394. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +73 -474
  395. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +31 -124
  396. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +45 -219
  397. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +13 -108
  398. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +19 -76
  399. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +9 -49
  400. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +6 -123
  401. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +23 -55
  402. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +14 -72
  403. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +7 -16
  404. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +43 -127
  405. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +13 -45
  406. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +131 -555
  407. data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +13 -63
  408. data/lib/hecks/ports/persistence/plugins/era/translation/approval_file.rb +227 -0
  409. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +2 -17
  410. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +3 -14
  411. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +13 -58
  412. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -17
  413. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +9 -26
  414. data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +50 -47
  415. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +18 -124
  416. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +34 -123
  417. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +5 -12
  418. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +3 -9
  419. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -14
  420. data/lib/hecks/ports/persistence/plugins/era/translation.rb +1 -0
  421. data/lib/hecks/ports/persistence/plugins/era.rb +4 -23
  422. data/lib/hecks/ports/persistence/postgres_dump/connection.rb +7 -23
  423. data/lib/hecks/ports/persistence/postgres_dump.rb +4 -35
  424. data/lib/hecks/ports/persistence/remote_runtime.rb +2 -24
  425. data/lib/hecks/ports/persistence/repository_factory.rb +8 -27
  426. data/lib/hecks/ports/persistence/state_codec.rb +47 -108
  427. data/lib/hecks/ports/persistence.rb +7 -14
  428. data/lib/hecks/ports/projection.rb +42 -84
  429. data/lib/hecks/ports/query/in_memory.rb +10 -58
  430. data/lib/hecks/ports/query/ordering.rb +11 -32
  431. data/lib/hecks/ports/query.rb +14 -37
  432. data/lib/hecks/ports.rb +2 -8
  433. data/lib/hecks/projection_files.rb +285 -0
  434. data/lib/hecks/projections/bootstrap_table.rb +12 -44
  435. data/lib/hecks/projections/deploy/fargate/assembly.rb +2 -15
  436. data/lib/hecks/projections/deploy/fargate/cdn.rb +1 -48
  437. data/lib/hecks/projections/deploy/fargate/cdn_default.rb +2 -11
  438. data/lib/hecks/projections/deploy/fargate/check.rb +5 -14
  439. data/lib/hecks/projections/deploy/fargate/containers.rb +3 -78
  440. data/lib/hecks/projections/deploy/fargate/extras.rb +3 -44
  441. data/lib/hecks/projections/deploy/fargate/monitoring.rb +0 -44
  442. data/lib/hecks/projections/deploy/fargate/settings.rb +2 -54
  443. data/lib/hecks/projections/deploy/fargate/yaml.rb +13 -58
  444. data/lib/hecks/projections/deploy/fargate.rb +40 -207
  445. data/lib/hecks/projections/deploy/lambda.rb +191 -708
  446. data/lib/hecks/projections/deploy/preview/access_yaml.rb +1 -33
  447. data/lib/hecks/projections/deploy/preview/containers.rb +6 -111
  448. data/lib/hecks/projections/deploy/preview/preview.sh.erb +1 -1
  449. data/lib/hecks/projections/deploy/preview/routing_yaml.rb +4 -56
  450. data/lib/hecks/projections/deploy/preview/script.rb +2 -14
  451. data/lib/hecks/projections/deploy/preview/settings.rb +3 -33
  452. data/lib/hecks/projections/deploy/preview/task_yaml.rb +2 -38
  453. data/lib/hecks/projections/deploy/preview/template.rb +3 -59
  454. data/lib/hecks/projections/deploy/preview.rb +2 -67
  455. data/lib/hecks/projections/deploy/scripts/deploy-service.sh.tmpl +1 -1
  456. data/lib/hecks/projections/deploy/scripts/expected-era.header +1 -1
  457. data/lib/hecks/projections/deploy/scripts/hosting.mk.tmpl +3 -3
  458. data/lib/hecks/projections/deploy/scripts/settings.rb +3 -25
  459. data/lib/hecks/projections/deploy/scripts/smoke-after-deploy.sh.tmpl +1 -1
  460. data/lib/hecks/projections/deploy/scripts.rb +4 -57
  461. data/lib/hecks/projections/deploy/shared.rb +48 -147
  462. data/lib/hecks/projections/deploy/smoke.rb +4 -61
  463. data/lib/hecks/projections/deploy/template_diff/comparer.rb +3 -25
  464. data/lib/hecks/projections/deploy/template_diff/loader.rb +2 -11
  465. data/lib/hecks/projections/deploy/template_diff.rb +5 -57
  466. data/lib/hecks/projections/diagrams.rb +22 -584
  467. data/lib/hecks/projections/glossary/html.rb +14 -130
  468. data/lib/hecks/projections/glossary/markdown.rb +8 -69
  469. data/lib/hecks/projections/glossary/mermaid.rb +9 -66
  470. data/lib/hecks/projections/glossary/sensitivity.rb +5 -34
  471. data/lib/hecks/projections/glossary/sentences.rb +14 -159
  472. data/lib/hecks/projections/glossary.rb +30 -222
  473. data/lib/hecks/projections/ir.rb +3 -10
  474. data/lib/hecks/projections/model/deviations.rb +16 -43
  475. data/lib/hecks/projections/model.rb +12 -51
  476. data/lib/hecks/projections/oidc.rb +12 -56
  477. data/lib/hecks/projections/parser_table.rb +13 -32
  478. data/lib/hecks/projections/reference.rb +4 -18
  479. data/lib/hecks/projections/rust_vocabulary.rb +13 -251
  480. data/lib/hecks/projections/shape.rb +3 -29
  481. data/lib/hecks/projections/statements.rb +7 -86
  482. data/lib/hecks/projections/vocabulary.rb +6 -22
  483. data/lib/hecks/projections.rb +2 -16
  484. data/lib/hecks/projector/cli_projector.rb +154 -400
  485. data/lib/hecks/projector/docs_projector.rb +10 -201
  486. data/lib/hecks/projector/exporter.rb +42 -134
  487. data/lib/hecks/projector/ir_projector.rb +2 -9
  488. data/lib/hecks/projector/narrate_projector.rb +15 -189
  489. data/lib/hecks/projector/target.rb +13 -76
  490. data/lib/hecks/projector.rb +30 -121
  491. data/lib/hecks/quality_control/adapters/agent.adapter +7 -0
  492. data/lib/hecks/quality_control/adapters/agent.rb +58 -0
  493. data/lib/hecks/quality_control/adapters/angle_tools.adapter +7 -0
  494. data/lib/hecks/quality_control/adapters/angle_tools.rb +15 -0
  495. data/lib/hecks/quality_control/adapters/clearance_recorder.rb +36 -0
  496. data/lib/hecks/quality_control/adapters/clearance_tools.adapter +7 -0
  497. data/lib/hecks/quality_control/adapters/clearance_tools.rb +17 -0
  498. data/lib/hecks/quality_control/adapters/git_pr.adapter +7 -0
  499. data/lib/hecks/quality_control/adapters/git_pr.rb +226 -0
  500. data/lib/hecks/quality_control/adapters/github_checks.adapter +9 -0
  501. data/lib/hecks/quality_control/adapters/github_checks.rb +83 -0
  502. data/lib/hecks/quality_control/adapters/github_ci_webhook.rb +56 -0
  503. data/lib/hecks/quality_control/adapters/github_issues.adapter +7 -0
  504. data/lib/hecks/quality_control/adapters/github_issues.rb +49 -0
  505. data/lib/hecks/quality_control/adapters/qa_tool.rb +59 -0
  506. data/lib/hecks/quality_control/adapters/sweep_tools.adapter +7 -0
  507. data/lib/hecks/quality_control/adapters/sweep_tools.rb +51 -0
  508. data/lib/hecks/quality_control/adapters/target_tools.adapter +7 -0
  509. data/lib/hecks/quality_control/adapters/target_tools.rb +43 -0
  510. data/lib/hecks/quality_control/cli/child.rb +45 -0
  511. data/lib/hecks/quality_control/cli/qa_concurrency_racer.rb +45 -0
  512. data/lib/hecks/quality_control/cli/qa_discover_external_domains.rb +248 -0
  513. data/lib/hecks/quality_control/cli/qa_domain_novelty.rb +163 -0
  514. data/lib/hecks/quality_control/cli/qa_generated_domains.rb +450 -0
  515. data/lib/hecks/quality_control/cli/qa_log_bug.rb +195 -0
  516. data/lib/hecks/quality_control/cli/qa_mine_combinations.rb +220 -0
  517. data/lib/hecks/quality_control/cli/qa_open_pr.rb +305 -0
  518. data/lib/hecks/quality_control/cli/qa_postgres_migrate.rb +154 -0
  519. data/lib/hecks/quality_control/cli/qa_postgres_role.rb +159 -0
  520. data/lib/hecks/quality_control/cli/qa_pr_check.rb +232 -0
  521. data/lib/hecks/quality_control/cli/qa_seed_angles.rb +142 -0
  522. data/lib/hecks/quality_control/cli/qa_seed_targets.rb +69 -0
  523. data/lib/hecks/quality_control/cli/qa_sweep/all_mode.rb +280 -0
  524. data/lib/hecks/quality_control/cli/qa_sweep/checks.rb +329 -0
  525. data/lib/hecks/quality_control/cli/qa_sweep/dials.rb +92 -0
  526. data/lib/hecks/quality_control/cli/qa_sweep/finding_report.rb +117 -0
  527. data/lib/hecks/quality_control/cli/qa_sweep/parsing.rb +175 -0
  528. data/lib/hecks/quality_control/cli/qa_sweep/release_mode.rb +60 -0
  529. data/lib/hecks/quality_control/cli/qa_sweep.rb +611 -0
  530. data/lib/hecks/quality_control/cli/qa_tick.rb +274 -0
  531. data/lib/hecks/quality_control/quality_control.bluebook +2224 -0
  532. data/lib/hecks/quality_control/quality_control.hecksagon +13 -0
  533. data/lib/hecks/quality_control/quality_control.ports.hecksagon +54 -0
  534. data/lib/hecks/query_ir.rb +346 -0
  535. data/lib/hecks/query_ir_mcp.rb +198 -0
  536. data/lib/hecks/query_specification/common/comparators.rb +5 -26
  537. data/lib/hecks/query_specification/common/comparison.rb +35 -143
  538. data/lib/hecks/query_specification/common/dsl.rb +8 -24
  539. data/lib/hecks/query_specification/common/null_policy.rb +20 -70
  540. data/lib/hecks/query_specification/common/options.rb +2 -6
  541. data/lib/hecks/query_specification/common/where_clause.rb +2 -10
  542. data/lib/hecks/query_specification/field_path.rb +37 -77
  543. data/lib/hecks/query_specification/hop_path.rb +12 -76
  544. data/lib/hecks/release/gem_pin.rb +2 -26
  545. data/lib/hecks/release/runner/ci_publisher.rb +5 -8
  546. data/lib/hecks/release/runner/clean_tree.rb +42 -0
  547. data/lib/hecks/release/runner/commands.rb +2 -4
  548. data/lib/hecks/release/runner/console.rb +6 -0
  549. data/lib/hecks/release/runner/gem_publisher.rb +15 -9
  550. data/lib/hecks/release/runner/npm_publisher.rb +9 -53
  551. data/lib/hecks/release/runner/preflight.rb +29 -20
  552. data/lib/hecks/release/runner/published.rb +8 -26
  553. data/lib/hecks/release/runner/tagger.rb +31 -23
  554. data/lib/hecks/release/runner.rb +60 -38
  555. data/lib/hecks/rendering.rb +4 -26
  556. data/lib/hecks/router/namespace_installer.rb +15 -39
  557. data/lib/hecks/router.rb +4 -8
  558. data/lib/hecks/runtime/adapter_lookup.rb +124 -0
  559. data/lib/hecks/runtime/aggregate_lock.rb +8 -33
  560. data/lib/hecks/runtime/boot_gates.rb +3 -18
  561. data/lib/hecks/runtime/caller.rb +19 -59
  562. data/lib/hecks/runtime/capability_graph.rb +5 -21
  563. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +16 -78
  564. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +27 -160
  565. data/lib/hecks/runtime/command_interpreter.rb +124 -306
  566. data/lib/hecks/runtime/command_rules/admissibility.rb +95 -366
  567. data/lib/hecks/runtime/command_rules/arithmetic.rb +66 -196
  568. data/lib/hecks/runtime/command_rules/authorization.rb +13 -45
  569. data/lib/hecks/runtime/command_rules/emission.rb +8 -21
  570. data/lib/hecks/runtime/command_rules/references.rb +23 -202
  571. data/lib/hecks/runtime/dependency_planning.rb +50 -104
  572. data/lib/hecks/runtime/dispatcher.rb +134 -243
  573. data/lib/hecks/runtime/entity_element.rb +40 -462
  574. data/lib/hecks/runtime/entity_interpreter.rb +64 -219
  575. data/lib/hecks/runtime/errors.rb +32 -115
  576. data/lib/hecks/runtime/event.rb +3 -25
  577. data/lib/hecks/runtime/identity.rb +18 -154
  578. data/lib/hecks/runtime/instance.rb +18 -150
  579. data/lib/hecks/runtime/interpreting.rb +14 -70
  580. data/lib/hecks/runtime/invocation.rb +28 -164
  581. data/lib/hecks/runtime/loader.rb +109 -194
  582. data/lib/hecks/runtime/outbox.rb +39 -262
  583. data/lib/hecks/runtime/policy_interpreter.rb +43 -202
  584. data/lib/hecks/runtime/port_operation_interpreter.rb +28 -97
  585. data/lib/hecks/runtime/query_interpreter.rb +122 -187
  586. data/lib/hecks/runtime/reaction_invocation.rb +36 -138
  587. data/lib/hecks/runtime/reaction_outcome.rb +89 -0
  588. data/lib/hecks/runtime/read_model_interpreter.rb +117 -208
  589. data/lib/hecks/runtime/rebuild_sweep.rb +8 -54
  590. data/lib/hecks/runtime/reference_hop.rb +8 -81
  591. data/lib/hecks/runtime/refusal_wording.rb +28 -87
  592. data/lib/hecks/runtime/registry/saga_persistence.rb +10 -102
  593. data/lib/hecks/runtime/registry/verification.rb +213 -227
  594. data/lib/hecks/runtime/registry/world_defaults.rb +4 -53
  595. data/lib/hecks/runtime/registry.rb +156 -247
  596. data/lib/hecks/runtime/remote_dispatcher.rb +68 -154
  597. data/lib/hecks/runtime/routing.rb +4 -15
  598. data/lib/hecks/runtime/saga_interpreter/correlation.rb +14 -61
  599. data/lib/hecks/runtime/saga_interpreter.rb +79 -263
  600. data/lib/hecks/runtime/saga_pending_dispatch.rb +2 -43
  601. data/lib/hecks/runtime/tenant_check.rb +6 -68
  602. data/lib/hecks/runtime/tenant_scope.rb +3 -28
  603. data/lib/hecks/runtime/value/admission.rb +16 -67
  604. data/lib/hecks/runtime/value/coercion.rb +162 -760
  605. data/lib/hecks/runtime/value/entity_list_coercion.rb +26 -219
  606. data/lib/hecks/runtime/value/field_checks.rb +172 -0
  607. data/lib/hecks/runtime/value.rb +15 -84
  608. data/lib/hecks/runtime.rb +35 -69
  609. data/lib/hecks/rust_build/conformance.rb +158 -0
  610. data/lib/hecks/rust_build/conformance_fuzz.rb +71 -0
  611. data/lib/hecks/rust_build/coverage.rb +218 -0
  612. data/lib/hecks/rust_build/native_build.rb +124 -0
  613. data/lib/hecks/rust_build/project_rust/root_mod.rb +120 -0
  614. data/lib/hecks/rust_build/project_rust.rb +332 -0
  615. data/lib/hecks/rust_build/wasm.rb +105 -0
  616. data/lib/hecks/rust_build/wasm_browser.rb +113 -0
  617. data/lib/hecks/rust_build.rb +144 -0
  618. data/lib/hecks/storehouse.rb +155 -582
  619. data/lib/hecks/tenancy/bluebook/tenancy.bluebook +10 -34
  620. data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +6 -23
  621. data/lib/hecks/three_zero/forms.yml +127 -0
  622. data/lib/hecks/three_zero.rb +12 -0
  623. data/lib/hecks/tools/argument_gate_matrix.rb +316 -0
  624. data/lib/hecks/tools/comment_style.rb +1070 -0
  625. data/lib/hecks/tools/corpus_report.rb +87 -0
  626. data/lib/hecks/tools/deploy_recipe.rb +255 -0
  627. data/lib/hecks/tools/deploy_recipe_lint.rb +282 -0
  628. data/lib/hecks/tools/drop_implicit_append_fields.rb +95 -0
  629. data/lib/hecks/tools/era_projection_backfill.rb +94 -0
  630. data/lib/hecks/tools/era_reattest.rb +146 -0
  631. data/lib/hecks/tools/evolve_run.rb +189 -0
  632. data/lib/hecks/tools/fuzz_sweep.rb +373 -0
  633. data/lib/hecks/tools/heki_compaction.rb +100 -0
  634. data/lib/hecks/tools/hoist_local_givens.rb +246 -0
  635. data/lib/hecks/tools/journal_compaction.rb +89 -0
  636. data/lib/hecks/tools/oidc_manifests.rb +70 -0
  637. data/lib/hecks/tools/query_ir_run.rb +81 -0
  638. data/lib/hecks/tools/regeneration_run.rb +166 -0
  639. data/lib/hecks/tools/rust_comment_style.rb +642 -0
  640. data/lib/hecks/tools/sequence_script.rb +62 -0
  641. data/lib/hecks/tools/tail_merge.rb +117 -0
  642. data/lib/hecks/tools/tenant_provisioning.rb +142 -0
  643. data/lib/hecks/tools/translation_audit.rb +208 -0
  644. data/lib/hecks/tools/translation_scaffold.rb +131 -0
  645. data/lib/hecks/tools.rb +86 -0
  646. data/lib/hecks/vendoring/git_environment.rb +2 -8
  647. data/lib/hecks/vendoring/git_source.rb +4 -10
  648. data/lib/hecks/vendoring.rb +7 -46
  649. data/lib/hecks/version.rb +3 -14
  650. data/lib/hecks.rb +52 -90
  651. data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +8 -46
  652. data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +11 -80
  653. data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +10 -99
  654. data/qa/settings.yml +66 -0
  655. data/rust/.cargo/config.toml +6 -0
  656. data/rust/.gitignore +2 -0
  657. data/rust/Cargo.lock +54 -0
  658. data/rust/Cargo.toml +61 -0
  659. data/rust/build/.cargo/config.toml +3 -0
  660. data/rust/build/.gitignore +1 -0
  661. data/rust/build/Cargo.lock +7 -0
  662. data/rust/build/Cargo.toml +19 -0
  663. data/rust/build/src/build_artifact.rs +47 -0
  664. data/rust/build/src/cargo_sync.rs +248 -0
  665. data/rust/build/src/json.rs +421 -0
  666. data/rust/build/src/lineage_pass.rs +285 -0
  667. data/rust/build/src/main.rs +51 -0
  668. data/rust/build/src/optional_pass.rs +150 -0
  669. data/rust/build/src/pipeline.rs +264 -0
  670. data/rust/build/src/reserved_names.rs +76 -0
  671. data/rust/build/src/resolve.rs +124 -0
  672. data/rust/build/src/root.rs +25 -0
  673. data/rust/build/src/sidecars.rs +73 -0
  674. data/rust/build/src/subprocess.rs +51 -0
  675. data/rust/build/src/tmp.rs +31 -0
  676. data/rust/codegen/.cargo/config.toml +3 -0
  677. data/rust/codegen/.gitignore +1 -0
  678. data/rust/codegen/Cargo.lock +7 -0
  679. data/rust/codegen/Cargo.toml +20 -0
  680. data/rust/codegen/src/attr.rs +32 -0
  681. data/rust/codegen/src/bridging.rs +481 -0
  682. data/rust/codegen/src/commands.rs +1226 -0
  683. data/rust/codegen/src/constraints.rs +109 -0
  684. data/rust/codegen/src/dependency_planning.rs +209 -0
  685. data/rust/codegen/src/domain_generator.rs +1288 -0
  686. data/rust/codegen/src/exemplar.rs +230 -0
  687. data/rust/codegen/src/expr_emitter.rs +87 -0
  688. data/rust/codegen/src/fielded.rs +192 -0
  689. data/rust/codegen/src/hecks_naming.rs +33 -0
  690. data/rust/codegen/src/json.rs +335 -0
  691. data/rust/codegen/src/json_codec.rs +697 -0
  692. data/rust/codegen/src/literal.rs +207 -0
  693. data/rust/codegen/src/main.rs +290 -0
  694. data/rust/codegen/src/manifest.rs +227 -0
  695. data/rust/codegen/src/mutations.rs +784 -0
  696. data/rust/codegen/src/naming.rs +286 -0
  697. data/rust/codegen/src/ports.rs +208 -0
  698. data/rust/codegen/src/prelude.rs +116 -0
  699. data/rust/codegen/src/queries.rs +786 -0
  700. data/rust/codegen/src/reactions.rs +532 -0
  701. data/rust/codegen/src/read_models.rs +697 -0
  702. data/rust/codegen/src/reference_specs.rs +40 -0
  703. data/rust/codegen/src/registry.rs +966 -0
  704. data/rust/codegen/src/reserved_names.rs +76 -0
  705. data/rust/codegen/src/shared.rs +93 -0
  706. data/rust/codegen/src/skip_reason.rs +25 -0
  707. data/rust/codegen/src/types.rs +362 -0
  708. data/rust/host/.cargo/config.toml +3 -0
  709. data/rust/host/.gitignore +1 -0
  710. data/rust/host/Cargo.lock +4297 -0
  711. data/rust/host/Cargo.toml +61 -0
  712. data/rust/host/HECKS_RELEASE +1 -0
  713. data/rust/host/rds-ca-bundle.pem +2736 -0
  714. data/rust/host/src/api.rs +1596 -0
  715. data/rust/host/src/approval.rs +652 -0
  716. data/rust/host/src/auth.rs +1287 -0
  717. data/rust/host/src/bin/expr_harness.rs +46 -0
  718. data/rust/host/src/bin/lineage_harness.rs +119 -0
  719. data/rust/host/src/bin/mint_harness.rs +135 -0
  720. data/rust/host/src/checkout.rs +265 -0
  721. data/rust/host/src/dispatch.rs +1443 -0
  722. data/rust/host/src/expr_json.rs +1117 -0
  723. data/rust/host/src/field_hints.rs +52 -0
  724. data/rust/host/src/ir.rs +733 -0
  725. data/rust/host/src/journal.rs +874 -0
  726. data/rust/host/src/lambda_client.rs +378 -0
  727. data/rust/host/src/log.rs +147 -0
  728. data/rust/host/src/main.rs +474 -0
  729. data/rust/host/src/mint.rs +1865 -0
  730. data/rust/host/src/payments/keystore.rs +330 -0
  731. data/rust/host/src/payments/tests.rs +1400 -0
  732. data/rust/host/src/payments.rs +767 -0
  733. data/rust/host/src/presentation.rs +698 -0
  734. data/rust/host/src/presentation_write.rs +1431 -0
  735. data/rust/host/src/query_step.rs +149 -0
  736. data/rust/host/src/rate_limit.rs +904 -0
  737. data/rust/host/src/reference_transform.rs +241 -0
  738. data/rust/host/src/reference_validate.rs +338 -0
  739. data/rust/host/src/resend.rs +296 -0
  740. data/rust/host/src/secrets.rs +106 -0
  741. data/rust/host/src/server.rs +663 -0
  742. data/rust/host/src/storage_shape.rs +175 -0
  743. data/rust/host/src/test_pg.rs +40 -0
  744. data/rust/host/src/ui_schema.rs +1351 -0
  745. data/rust/host/src/wasm_runner.rs +191 -0
  746. data/rust/host/src/web/newsletter/cooldown.rs +126 -0
  747. data/rust/host/src/web/newsletter/tests.rs +104 -0
  748. data/rust/host/src/web/newsletter.rs +310 -0
  749. data/rust/host/src/web/newsletter_send.rs +357 -0
  750. data/rust/host/src/web/registrations.rs +1505 -0
  751. data/rust/host/src/web.rs +2937 -0
  752. data/rust/lsp/.gitignore +1 -0
  753. data/rust/lsp/Cargo.lock +7 -0
  754. data/rust/lsp/Cargo.toml +16 -0
  755. data/rust/lsp/README.md +133 -0
  756. data/rust/lsp/src/diagnostics.rs +165 -0
  757. data/rust/lsp/src/json.rs +385 -0
  758. data/rust/lsp/src/main.rs +399 -0
  759. data/rust/lsp/src/outline.rs +177 -0
  760. data/rust/lsp/src/rpc.rs +67 -0
  761. data/rust/parser/.cargo/config.toml +5 -0
  762. data/rust/parser/.gitignore +1 -0
  763. data/rust/parser/Cargo.lock +7 -0
  764. data/rust/parser/Cargo.toml +21 -0
  765. data/rust/parser/src/build/closed_sets.rs +27 -0
  766. data/rust/parser/src/build/identity.rs +276 -0
  767. data/rust/parser/src/build/mod.rs +12 -0
  768. data/rust/parser/src/build/naming.rs +141 -0
  769. data/rust/parser/src/build/pattern_subset.rs +161 -0
  770. data/rust/parser/src/build/query_derive.rs +72 -0
  771. data/rust/parser/src/build/query_inference.rs +269 -0
  772. data/rust/parser/src/build/query_options.rs +100 -0
  773. data/rust/parser/src/build/read_model.rs +94 -0
  774. data/rust/parser/src/build/references.rs +32 -0
  775. data/rust/parser/src/canonical.rs +114 -0
  776. data/rust/parser/src/diag.rs +55 -0
  777. data/rust/parser/src/emit.rs +953 -0
  778. data/rust/parser/src/expr/ast_json.rs +147 -0
  779. data/rust/parser/src/expr/evaluator.rs +81 -0
  780. data/rust/parser/src/expr/mod.rs +84 -0
  781. data/rust/parser/src/expr/resolver.rs +497 -0
  782. data/rust/parser/src/ir.rs +387 -0
  783. data/rust/parser/src/keywords.rs +585 -0
  784. data/rust/parser/src/lex.rs +662 -0
  785. data/rust/parser/src/main.rs +252 -0
  786. data/rust/parser/src/parse/aggregate.rs +612 -0
  787. data/rust/parser/src/parse/chapter.rs +517 -0
  788. data/rust/parser/src/parse/command.rs +637 -0
  789. data/rust/parser/src/parse/domain_port.rs +127 -0
  790. data/rust/parser/src/parse/entity.rs +527 -0
  791. data/rust/parser/src/parse/file.rs +67 -0
  792. data/rust/parser/src/parse/hecksagon.rs +231 -0
  793. data/rust/parser/src/parse/lifecycle.rs +162 -0
  794. data/rust/parser/src/parse/mod.rs +1262 -0
  795. data/rust/parser/src/parse/policy.rs +87 -0
  796. data/rust/parser/src/parse/process_manager.rs +305 -0
  797. data/rust/parser/src/parse/query.rs +100 -0
  798. data/rust/parser/src/parse/read_model.rs +214 -0
  799. data/rust/parser/src/parse/value_object.rs +250 -0
  800. data/rust/parser/src/ruby_value.rs +422 -0
  801. data/rust/project/bridging.rb +257 -0
  802. data/rust/project/commands.rb +877 -0
  803. data/rust/project/constraints.rb +86 -0
  804. data/rust/project/dependency_planning.rb +178 -0
  805. data/rust/project/domain_generator.rb +980 -0
  806. data/rust/project/exemplar.rb +148 -0
  807. data/rust/project/expr_emitter.rb +72 -0
  808. data/rust/project/fielded.rb +141 -0
  809. data/rust/project/json_codec.rb +641 -0
  810. data/rust/project/mutations.rb +721 -0
  811. data/rust/project/naming.rb +205 -0
  812. data/rust/project/ports.rb +65 -0
  813. data/rust/project/queries.rb +493 -0
  814. data/rust/project/reactions.rb +317 -0
  815. data/rust/project/read_models.rb +690 -0
  816. data/rust/project/reference_specs.rb +27 -0
  817. data/rust/project/registry.rb +396 -0
  818. data/rust/project/skip_reason.rb +29 -0
  819. data/rust/project/types.rb +225 -0
  820. data/rust/project/write_if_changed.rb +83 -0
  821. data/rust/project.rb +30 -0
  822. data/rust/project_rust_pipeline.rb +383 -0
  823. data/rust/src/exemplar/commands.rs +279 -0
  824. data/rust/src/exemplar/constraints.rs +18 -0
  825. data/rust/src/exemplar/fielded.rs +280 -0
  826. data/rust/src/exemplar/json.rs +277 -0
  827. data/rust/src/exemplar/mod.rs +17 -0
  828. data/rust/src/exemplar/mutations.rs +80 -0
  829. data/rust/src/exemplar/queries.rs +33 -0
  830. data/rust/src/exemplar/reactions.rs +88 -0
  831. data/rust/src/exemplar/read_models.rs +48 -0
  832. data/rust/src/exemplar/registry.rs +166 -0
  833. data/rust/src/exemplar/types.rs +44 -0
  834. data/rust/src/kernel/attribute_shapes/composite.rs +88 -0
  835. data/rust/src/kernel/attribute_shapes/list.rs +18 -0
  836. data/rust/src/kernel/attribute_shapes/mod.rs +44 -0
  837. data/rust/src/kernel/attribute_shapes/optional.rs +9 -0
  838. data/rust/src/kernel/attribute_shapes/scalar.rs +39 -0
  839. data/rust/src/kernel/cli.rs +585 -0
  840. data/rust/src/kernel/dispatch.rs +1090 -0
  841. data/rust/src/kernel/expr.rs +458 -0
  842. data/rust/src/kernel/expression_operators/arithmetic.rs +128 -0
  843. data/rust/src/kernel/expression_operators/comparison.rs +48 -0
  844. data/rust/src/kernel/expression_operators/enumeration.rs +232 -0
  845. data/rust/src/kernel/expression_operators/logical.rs +13 -0
  846. data/rust/src/kernel/expression_operators/membership.rs +18 -0
  847. data/rust/src/kernel/expression_operators/mod.rs +68 -0
  848. data/rust/src/kernel/expression_operators/pattern_match.rs +73 -0
  849. data/rust/src/kernel/expression_operators/positional.rs +126 -0
  850. data/rust/src/kernel/expression_operators/presence.rs +101 -0
  851. data/rust/src/kernel/expression_operators/sign_test.rs +16 -0
  852. data/rust/src/kernel/expression_operators/sized.rs +35 -0
  853. data/rust/src/kernel/expression_operators/text.rs +79 -0
  854. data/rust/src/kernel/expression_operators/to_string.rs +18 -0
  855. data/rust/src/kernel/json.rs +779 -0
  856. data/rust/src/kernel/mod.rs +133 -0
  857. data/rust/src/kernel/named_query.rs +219 -0
  858. data/rust/src/kernel/orchestrate.rs +1810 -0
  859. data/rust/src/kernel/pattern.rs +307 -0
  860. data/rust/src/kernel/query_comparators.rs +206 -0
  861. data/rust/src/kernel/query_ordering.rs +103 -0
  862. data/rust/src/kernel/read_model.rs +914 -0
  863. data/rust/src/kernel/reference_lookup.rs +149 -0
  864. data/rust/src/kernel/repository.rs +468 -0
  865. data/rust/src/kernel/routing.rs +612 -0
  866. data/rust/src/kernel/vocab/aggregate_dispatch_order.rs +118 -0
  867. data/rust/src/kernel/vocab/entity_dispatch_order.rs +114 -0
  868. data/rust/src/kernel/vocab/field_hint.rs +70 -0
  869. data/rust/src/kernel/vocab/mod.rs +20 -0
  870. data/rust/src/kernel/vocab/query_comparator.rs +65 -0
  871. data/rust/src/kernel/vocab/refusal_template.rs +1592 -0
  872. data/rust/src/lib.rs +8 -0
  873. data/rust/src/main.rs +16 -0
  874. data/rust/web/.gitignore +1 -0
  875. data/rust/web/Cargo.lock +119 -0
  876. data/rust/web/Cargo.toml +18 -0
  877. data/rust/web/src/lib.rs +8 -0
  878. metadata +478 -12
  879. data/lib/hecks/facade/cli_door.rb +0 -178
  880. data/lib/hecks/facade/cli_runner.rb +0 -271
  881. data/lib/hecks/facade/handle.rb +0 -293
  882. data/lib/hecks/facade/json_door.rb +0 -247
  883. data/lib/hecks/facade/surface/aggregate_door.rb +0 -222
  884. data/lib/hecks/facade/surface/chapter.rb +0 -116
  885. data/lib/hecks/facade/surface.rb +0 -61
  886. data/lib/hecks/mcp_door_scope.rb +0 -176
@@ -1,32 +1,16 @@
1
1
  module Hecks
2
2
  module Ports
3
3
  module Persistence
4
- # **The no-op saga store** — what `Registry#saga_persistence` hands
5
- # back for a domain whose resolved adapter doesn't implement the
6
- # (optional) saga-persistence capability: Memory, deliberately
7
- # (sagas stay in-memory-only, exactly as they always have), and
8
- # any `RemoteRuntime`-shaped adapter (Lambda; the real durability
9
- # for those lives on the other side of the call — Phase 1, not
10
- # here). `SagaInterpreter`'s hook points call through
11
- # `saga_persistence(domain)` unconditionally; this is what makes
12
- # that safe without a `respond_to?` check at every call site,
13
- # mirroring the same optional-capability shape
14
- # `Ports::Persistence::AppendOnly` already gives adapters that
15
- # don't implement `reset!`/`events`/`record_event`.
4
+ # A saga store that keeps nothing, for adapters without the optional saga-persistence
5
+ # capability; callers call through it unconditionally instead of checking `respond_to?`.
16
6
  class NullSagaStore
17
- # Accepts and discards a saga checkpoint, whatever keywords it carries.
18
- #
19
- # @return [nil] always; nothing is stored
7
+ # Discards the checkpoint.
20
8
  def save_saga(**) = nil
21
9
 
22
- # Accepts and ignores a request to forget a saga.
23
- #
24
- # @return [nil] always; there is nothing to delete
10
+ # Ignores the request; there is nothing to delete.
25
11
  def delete_saga(**) = nil
26
12
 
27
13
  # Yields nothing, because no saga is ever stored here.
28
- #
29
- # @return [nil] always; a block, if given, is never called
30
14
  def each_saga(*) = nil
31
15
  end
32
16
 
@@ -1,28 +1,12 @@
1
1
  module Hecks
2
2
  module Ports
3
- # Reopened to hold the persistence-plugin registry (`Plugin`, below) and
4
- # its call surface (`register_plugin`/`plugin?`/`each_plugin`) — see ADR
5
- # 0033 and `Plugin`'s own header for the seam this fills.
3
+ # Holds the persistence-plugin registry and its `register_plugin`/`plugin?`/`each_plugin`
4
+ # surface.
6
5
  module Persistence
7
- # A tiny, real seam — ADR 0033. Core never names a persistence plugin;
8
- # a plugin makes itself known as a side effect of being `require`d, the
9
- # same way an adapter's own `.rb` file already registers itself
10
- # (`Runtime::Registry#add_adapter`) rather than core listing adapter
11
- # names anywhere. `register_plugin` is the entire contract a plugin
12
- # must satisfy: anything responding to `contribute_boot_gates(registry,
13
- # gates)` (a no-op is a valid implementation).
6
+ # The persistence-plugin registry (ADR 0033). A plugin registers itself when required, and
7
+ # need only respond to `contribute_boot_gates(registry, gates)`; a no-op is valid.
14
8
  #
15
- # This is deliberately not the same registry `Hecks::Projector` uses
16
- # (ADR 0027) or `Runtime::BootGates` (ADR 0031) — each of those is
17
- # scoped to its own seam (IR-in/artifact-out; per-boot phased gates).
18
- # A shared base is deferred until a third registry actually wants one.
19
- #
20
- # **Name-keyed, process-wide, not per-boot** — unlike `BootGates` (one
21
- # instance per `Loader.boot` call, because gate registration is
22
- # capability-conditional per registry), a persistence plugin is either
23
- # `require`d into this process or it isn't; there is no "this boot's
24
- # registry doesn't need it" case to isolate against, so a plain
25
- # module-level hash is the right shape here, not an instantiable class.
9
+ # Process-wide and name-keyed: a plugin is either required into this process or it is not.
26
10
  module Plugin
27
11
  @plugins = {}
28
12
 
@@ -37,33 +21,25 @@ module Hecks
37
21
  @plugins[name.to_sym] = plugin
38
22
  end
39
23
 
40
- # Reports whether a plugin of that name has been required into this process.
24
+ # Whether a plugin is registered under `name`.
41
25
  #
42
- # @param name [Symbol, String] the plugin's name
43
- # @return [Boolean] true when a plugin is registered under `name`
26
+ # @return [Boolean]
44
27
  def registered?(name)
45
28
  @plugins.key?(name.to_sym)
46
29
  end
47
30
 
48
31
  # Yields every registered plugin, in registration order.
49
- #
50
- # @yieldparam plugin [Object] a registered plugin
51
- # @return [Hash{Symbol => Object}, Enumerator] the plugin table when a block is
52
- # given, otherwise an Enumerator over the plugins
53
32
  def each(&)
54
33
  @plugins.each_value(&)
55
34
  end
56
35
 
57
- # Reports whether any persistence plugin is loaded at all.
36
+ # Whether at least one plugin is registered.
58
37
  #
59
- # @return [Boolean] true when at least one plugin is registered
38
+ # @return [Boolean]
60
39
  def any? = !@plugins.empty?
61
40
  end
62
41
  end
63
42
 
64
- # `Ports::Persistence.plugin?(:era)` / `.each_plugin` — the ordinary
65
- # call surface; `Plugin.register`/`.registered?`/`.each` stay reachable
66
- # directly for a plugin's own file to call at require-time.
67
43
  module_function
68
44
 
69
45
  # Registers a persistence plugin; a plugin's own file calls this when it is required.
@@ -73,22 +49,17 @@ module Hecks
73
49
  # @return [Object] the plugin just registered
74
50
  def register_plugin(name, plugin) = Plugin.register(name, plugin)
75
51
 
76
- # Reports whether the named persistence plugin is loaded in this process.
52
+ # Whether the named persistence plugin is loaded in this process.
77
53
  #
78
- # @param name [Symbol, String] the plugin's name
79
- # @return [Boolean] true when a plugin is registered under `name`
54
+ # @return [Boolean]
80
55
  def plugin?(name) = Plugin.registered?(name)
81
56
 
82
57
  # Yields every loaded persistence plugin, in registration order.
83
- #
84
- # @yieldparam plugin [Object] a registered plugin
85
- # @return [Hash{Symbol => Object}, Enumerator] the plugin table when a block is given,
86
- # otherwise an Enumerator over the plugins
87
58
  def each_plugin(&) = Plugin.each(&)
88
59
 
89
- # Reports whether any persistence plugin is loaded in this process.
60
+ # Whether any persistence plugin is loaded in this process.
90
61
  #
91
- # @return [Boolean] true when at least one plugin is registered
62
+ # @return [Boolean]
92
63
  def plugins_loaded? = Plugin.any?
93
64
  end
94
65
  end
@@ -3,57 +3,29 @@ require_relative "../../../../ports/persistence/binding_policy"
3
3
  require_relative "lineage"
4
4
  require_relative "../../../../naming"
5
5
  require_relative "../../../../framework"
6
+ require_relative "../../../../chapters"
6
7
  require_relative "../../../../runtime/registry"
7
8
  require_relative "expected_era"
8
9
 
9
10
  module Hecks
10
11
  module Runtime
11
- # The boot-time era gate, run for the adapters that have eras — the
12
- # lineage-capable ones. An era is a fact about stored data that some
13
- # adapter can carry across a shape change; an adapter that cannot
14
- # translate has no era to hold, and holding one for it would record
15
- # history about data nothing can act on.
16
- #
17
- # The whole domain is handed to the capable adapter's own era check
18
- # (Postgres: hold, recognize, mint, or refuse toward the scaffold),
19
- # which keeps its era facts as rows beside its data. That
20
- # co-location is load-bearing — a watermark only means something
21
- # against the journal it was cut from, and an approval recorded
22
- # anywhere but the reviewed database binds to nothing.
23
- #
24
- # The capability is asked of the adapter, never of its name: a
25
- # second adapter that grows an era story declares lineage_capable?
26
- # and era_check! and needs no change here.
27
- #
28
- # Detection and identity are separate jobs: this check never hashes
29
- # anything — era names come from the store, already minted (by the
30
- # scaffold) or absent. Refusal wordings are contract, pinned by the
31
- # corpus.
12
+ # The boot-time era gate for lineage-capable adapters (Postgres today):
13
+ # each capable adapter's own era_check! decides hold, recognize, mint, or refuse.
32
14
  module EraCheck
33
15
  module_function
34
16
 
35
17
  # Runs both halves of the era gate over every bluebook in a registry.
36
18
  #
37
- # Each bluebook's own source, not one file read once and reused
38
- # for every bluebook in the registry — true as long as a domain
39
- # directory only ever held exactly one, and silently wrong the
40
- # moment `uses_framework` made a second, differently-sourced
41
- # bluebook (Governance, Identity — `lib/hecks/framework/bluebook/`,
42
- # not the domain's own directory) share a boot with the first.
43
- # Caught the hard way: three domains booted together, one real
44
- # source text (the domain's own), and every other domain's era-1
45
- # held that text under its own name — a shadow-parse of it later
46
- # reconstructs a completely different shape, and every boot after
47
- # the first refuses toward a scaffold that was never the real
48
- # drift.
19
+ # Looks up each bluebook's own source separately: `uses_framework` can share a boot between
20
+ # the domain's own bluebook and a differently-sourced one, so one file read once and reused
21
+ # for every bluebook would attribute the wrong text.
49
22
  #
50
23
  # @param registry [Runtime::Registry] the registry being booted
51
- # @param directory [String] path of the domain's own bluebook directory, searched for
52
- # each bluebook's `.bluebook` source
24
+ # @param directory [String] the domain's bluebook directory, searched for each source
53
25
  # @return [void]
54
- # @raise [Runtime::WiringError] if a compute rule is bound to an adapter that is not
55
- # lineage-capable, a persistence binding cannot be resolved, a lineage-bound bluebook
56
- # has no findable source, or the adapter's own `era_check!` refuses the boot
26
+ # @raise [Runtime::WiringError] if a compute rule is bound to a non-lineage-capable adapter,
27
+ # a persistence binding cannot be resolved, a lineage-bound bluebook has no findable
28
+ # source, or `era_check!` refuses the boot
57
29
  def check!(registry, directory)
58
30
  check_compute_rules_for_registry!(registry)
59
31
  check_lineage!(registry, directory)
@@ -61,12 +33,8 @@ module Hecks
61
33
 
62
34
  # Refuses the boot when any bluebook's compute rule is bound away from Postgres.
63
35
  #
64
- # The domain-agnostic half, split out for ADR 0031's boot-gate
65
- # registry: a compute rule requires Postgres whatever adapter is
66
- # actually bound, so this must run for every registry, the same way
67
- # `registry.verify!` does — it is not conditional on any adapter
68
- # being lineage-capable, and must never be skipped by
69
- # `check_lineage!`'s own capability gate below.
36
+ # Runs unconditionally for every registry, unlike check_lineage!'s
37
+ # capability-gated pass below (ADR 0031).
70
38
  #
71
39
  # @param registry [Runtime::Registry] the registry whose bluebooks are all checked
72
40
  # @return [void]
@@ -78,11 +46,8 @@ module Hecks
78
46
 
79
47
  # Hands every bluebook, with its own source text, to its adapter's era check.
80
48
  #
81
- # The capability-gated half — ADR 0031's registered `:era_check`
82
- # gate. Registration is conditional on `lineage_capable_registry?`;
83
- # `check_bluebook!` below still carries its own per-bluebook
84
- # `lineage_capable?` return-early, unchanged, for a registry with a
85
- # mix of lineage-capable and plain-adapter bluebooks.
49
+ # Capability-gated (ADR 0031): check_bluebook! below still returns
50
+ # early for any bluebook whose own binding isn't lineage-capable.
86
51
  #
87
52
  # @param registry [Runtime::Registry] the registry being booted
88
53
  # @param directory [String] path of the domain's own bluebook directory
@@ -98,12 +63,9 @@ module Hecks
98
63
 
99
64
  # Decides whether a registry binds anything that carries eras.
100
65
  #
101
- # The `:era_check` gate's own registration predicate: true iff at
102
- # least one bluebook's own anchor (first) aggregate resolves to a
103
- # lineage-capable adapter — mirrors `check_bluebook!`'s existing
104
- # per-bluebook anchor check, just asked once, up front, of the
105
- # whole registry, so a registry with nothing lineage-capable bound
106
- # anywhere never registers the gate at all.
66
+ # Mirrors check_bluebook!'s own per-bluebook anchor check, asked
67
+ # once up front so a registry with nothing lineage-capable never
68
+ # registers the `:era_check` gate at all.
107
69
  #
108
70
  # @param registry [Runtime::Registry] the registry whose bluebooks are asked
109
71
  # @return [Boolean] true when some bluebook's first aggregate is bound to a
@@ -121,51 +83,15 @@ module Hecks
121
83
 
122
84
  # Reads the source text one bluebook was declared in, wherever that source lives.
123
85
  #
124
- # The domain's own directory first, matched by name — a real app's
125
- # directory may hold more than one file once `uses_framework`
126
- # exists, so ".first" alone cannot be trusted, the exact
127
- # way it silently wasn't the day this was found: three domains
128
- # booted together, one real source text read once (the domain's
129
- # own, ".first"'d), and every other domain's era-1 held that text
130
- # under its own name — a later shadow-parse of it reconstructs a
131
- # completely different shape, and every boot after the first
132
- # refuses toward a scaffold that was never the real drift.
133
- #
134
- # A single-file directory whose one file names something else
135
- # falls back to it anyway (a fixture may legitimately name its
136
- # file differently from the `Hecks.bluebook` it declares) — unless
137
- # this bluebook is a known framework member or a vendored
138
- # embryonaut bluebook (see `vendored_source_for` below), in which
139
- # case that one file is certainly some other domain's, not this
140
- # one's, and the real registry is asked instead — the only other
141
- # two places a bluebook in this registry could have come from, per
142
- # `uses_framework` and `uses_embryonaut_bluebook`.
143
- #
144
- # The bug this guards against, found live: `Framework.members` was
145
- # the only exclusion checked here, so a domain attaching a
146
- # vendored bluebook instead (`uses_embryonaut_bluebook`, which has
147
- # no equivalent registry — see embryonaut_bluebook.rb's own
148
- # header) fell straight through the single-file fallback: a
149
- # directory holding exactly one `.bluebook` file (the target
150
- # domain's own) handed that same text back for the vendored
151
- # bluebook's era check too. PostgresEra minted era 1 for the
152
- # vendored domain with the target's own source stamped as its
153
- # `held_text` — the label computed from it, too — so the very
154
- # next boot re-derived the vendored domain's real shape, found it
155
- # didn't match what got (wrongly) stored, and refused to boot
156
- # toward a scaffold for drift that never actually happened.
157
- # `registry:` is what lets this check the one thing
158
- # `Framework.members` cannot: whether some hecksagon in this
159
- # registry declared `uses_embryonaut_bluebook` for this exact
160
- # bluebook name, the same way `EmbryonautBluebook.load!` itself
161
- # already resolves the vendored package's own directory.
86
+ # Matched by declared name, not position: a domain directory using
87
+ # `uses_framework` may hold more than one file, and a framework
88
+ # member or vendored bluebook is excluded from the single-file
89
+ # fallback so its own real source is read, not a sibling's.
162
90
  #
163
91
  # @param bluebook [Bluebook::Chapter] the bluebook whose source is wanted
164
92
  # @param directory [String] path of the domain's own bluebook directory
165
- # @param registry [Runtime::Registry, nil] the registry asked whether some hecksagon
166
- # vendored this bluebook; nil skips the vendored lookup
167
- # @return [String, nil] the UTF-8 text of every matching file joined with `"\n"`; nil
168
- # when no source file could be found
93
+ # @param registry [Runtime::Registry, nil] nil skips the vendored-bluebook lookup
94
+ # @return [String, nil] UTF-8 text of every matching file joined with `"\n"`, or nil
169
95
  def source_text_for(bluebook, directory, registry: nil)
170
96
  domain_files = Dir[File.join(directory, "*.bluebook")]
171
97
  own = domain_files.select { |path| declares_bluebook?(path, bluebook.name) }
@@ -190,26 +116,23 @@ module Hecks
190
116
 
191
117
  # Picks the files to read for a bluebook no file in the domain directory declares.
192
118
  #
193
- # Only reached once nothing in the domain's own directory actually
194
- # declares this bluebook by name. Three remaining sources, in
195
- # order: a genuinely single-file domain directory whose one file
196
- # just happens to name something else (but only when this
197
- # bluebook isn't already known to come from somewhere else
198
- # entirely — the exact guard the bug below was missing half of);
199
- # a framework member; a vendored embryonaut bluebook.
119
+ # Tries, in order: a chapter the gem carries (the QA ledger's QualityControl), the domain's
120
+ # own single remaining file, a framework member, then a vendored embryonaut bluebook.
200
121
  #
201
122
  # @param bluebook [Bluebook::Chapter] the bluebook whose source is wanted
202
123
  # @param directory [String] path of the domain's own bluebook directory
203
124
  # @param domain_files [Array<String>] paths of every `.bluebook` file in `directory`
204
125
  # @param registry [Runtime::Registry, nil] the registry asked for a vendored name; nil
205
126
  # skips the vendored lookup
206
- # @return [Array<String>] file paths to read, in load order; `[]` when the bluebook
207
- # comes from none of the three sources
127
+ # @return [Array<String>] file paths to read, in load order; `[]` when none applies
208
128
  def fallback_source_files(bluebook, directory, domain_files, registry)
209
129
  vendored_name = registry && vendored_bluebook_name_for(registry, bluebook.name)
210
130
  framework_path = Framework.members[bluebook.name]
131
+ attached = Chapters.index.fetch(bluebook.name, [])
211
132
 
212
- if domain_files.size == 1 && !framework_path && !vendored_name
133
+ if attached.any? && !framework_path && !vendored_name
134
+ attached
135
+ elsif domain_files.size == 1 && !framework_path && !vendored_name
213
136
  domain_files
214
137
  elsif framework_path
215
138
  [framework_path]
@@ -222,13 +145,8 @@ module Hecks
222
145
 
223
146
  # Recovers the vendored package name behind a bluebook, if some hecksagon vendored it.
224
147
  #
225
- # The name `uses_embryonaut_bluebook` was actually called with —
226
- # recovered from whichever hecksagon in this registry recorded it
227
- # (`HecksagonBuilder#uses_embryonaut_bluebook`'s own
228
- # `@vendored_bluebooks`), matched the same way
229
- # `EmbryonautBluebook.load!` itself decides idempotency: the
230
- # vendored name Pascal-cases to this bluebook's own declared name.
231
- # Nil for an ordinary bluebook nothing ever vendored.
148
+ # Matched by Pascal-casing: the vendored name Pascal-cases to this
149
+ # bluebook's own declared name.
232
150
  #
233
151
  # @param registry [Runtime::Registry] the registry whose hecksagons are searched
234
152
  # @param bluebook_name [String] the bluebook's declared Pascal-case name
@@ -244,17 +162,9 @@ module Hecks
244
162
 
245
163
  # Lists the `.bluebook` files a vendored embryonaut package ships.
246
164
  #
247
- # The same path `EmbryonautBluebook.load!` itself resolves from —
248
- # `<registry.root>/vendor/embryonaut_bluebooks/<name>/bluebook/`,
249
- # rebuilt here from `directory` (the domain's own bluebook
250
- # directory, always `registry.root`'s immediate child — see
251
- # `Runtime::Loader.boot`) rather than threading `registry.root`
252
- # through as a second parameter. Every `.bluebook` file the
253
- # package ships, in the same `Dir.glob` order actually loaded at
254
- # boot time — order matters here because this text is later
255
- # re-parsed whole (`EraCheck::shadow`) to reconstruct the shape a
256
- # held era claims, and that reconstruction must see the files in
257
- # the order that actually built the live shape.
165
+ # Listed in `Dir.glob` order, matching load order at boot, since a
166
+ # later reconstruction of this text depends on seeing files in the
167
+ # order that built the live shape.
258
168
  #
259
169
  # @param directory [String] path of the domain's own bluebook directory, whose parent
260
170
  # holds `vendor/embryonaut_bluebooks`
@@ -269,16 +179,12 @@ module Hecks
269
179
 
270
180
  # Hands one bluebook to its adapter's `era_check!`, when that adapter carries eras.
271
181
  #
272
- # The bluebook's first aggregate is the anchor: its binding alone decides
273
- # which adapter is asked, and a bluebook with no aggregates, or one bound
274
- # to an adapter that is not lineage-capable, is skipped without a word.
182
+ # The first aggregate is the anchor: its binding alone decides the adapter asked.
275
183
  #
276
184
  # @param registry [Runtime::Registry] the registry being booted
277
185
  # @param bluebook [Bluebook::Chapter] the bluebook to check
278
- # @param current_text [String, nil] the bluebook's source, as `source_text_for` found
279
- # it; nil means no source file was found
280
- # @param directory [String, nil] the domain's bluebook directory, named in the
281
- # missing-source refusal and passed through to the adapter
186
+ # @param current_text [String, nil] the bluebook's source; nil means none was found
187
+ # @param directory [String, nil] the domain's bluebook directory, named in the refusal
282
188
  # @return [void]
283
189
  # @raise [Runtime::WiringError] if the first aggregate's binding cannot be resolved,
284
190
  # `current_text` is nil for a lineage-bound bluebook, or the adapter's `era_check!`
@@ -305,10 +211,8 @@ module Hecks
305
211
 
306
212
  # Refuses the boot when one bluebook's compute rule is bound away from Postgres.
307
213
  #
308
- # The per-rule capability gate — not an era fact, and so it
309
- # survives on every adapter: a compute rule's SQL is its only
310
- # implementation, so an aggregate carrying one cannot boot
311
- # anywhere but Postgres, whatever any shape comparison would say.
214
+ # A compute rule's SQL is its only implementation, so it cannot
215
+ # boot on any adapter but Postgres, independent of shape checks.
312
216
  #
313
217
  # @param registry [Runtime::Registry] the registry holding the declared translations
314
218
  # and the aggregate's bindings
@@ -343,17 +247,13 @@ module Hecks
343
247
 
344
248
  # Asks a named adapter whether it carries eras.
345
249
  #
346
- # The capability idiom: an adapter class that answers
347
- # lineage_capable? with true carries eras and may act on drift
348
- # (translate, fork, merge). Postgres alone does today; the seam is
349
- # what lets a second one arrive without touching this file.
250
+ # Postgres alone answers true today; the seam lets a second
251
+ # lineage-capable adapter arrive without touching this file.
350
252
  #
351
253
  # @param registry [Runtime::Registry] the registry whose `adapters` must list the name
352
254
  # @param adapter_name [String] the adapter's name, as `adapter_for` returns it
353
- # @return [Boolean] the adapter's own `lineage_capable?` answer; false when the registry
354
- # does not list the adapter, the adapter does not respond to `lineage_capable?`, or
355
- # any `StandardError` is raised on the way (including an adapter with no Ruby
356
- # implementation)
255
+ # @return [Boolean] the adapter's own answer; false if unlisted, not lineage-capable, or
256
+ # any `StandardError` is raised
357
257
  def lineage_capable?(registry, adapter_name)
358
258
  adapter_class = registry.adapters[adapter_name] && registry.adapter_class(adapter_name)
359
259
  adapter_class.respond_to?(:lineage_capable?) && adapter_class.lineage_capable?
@@ -1,37 +1,18 @@
1
1
  module Hecks
2
2
  module Runtime
3
3
  module EraGuard
4
- # The pure half: computing an aggregate's structural signature and
5
- # diffing two eras' shapes. No file I/O — everything here answers
6
- # from the IR it is handed, which is why the Postgres mint path can
7
- # call it too.
4
+ # Structural signature and diff of aggregate shapes, computed from the IR alone
5
+ # (no file I/O), so the Postgres mint path can call it too.
8
6
  module ShapeDiff
9
- # Computes an aggregate's structural signature, for comparing two eras of it.
10
- #
11
- # @param aggregate [Bluebook::Aggregate] the aggregate to describe
12
- # @return [Array<Array>] one `[name, signature]` pair per attribute, sorted by name;
13
- # `name` is a Symbol and `signature` is whatever `attribute_signature` returns
7
+ # Structural signature of an aggregate: sorted `[name, signature]` pairs per attribute.
14
8
  def shape(aggregate)
15
9
  aggregate.attributes.map do |attribute|
16
10
  [attribute.name, attribute_signature(aggregate, attribute.type)]
17
11
  end.sort_by(&:first)
18
12
  end
19
13
 
20
- # Expands a declared type into a signature that exposes its members.
21
- #
22
- # A plain type name for a primitive; `[type_name, member_signatures]`
23
- # for a value object or entity, walked recursively — so two
24
- # attributes with the same declared type name but a different
25
- # internal shape are never mistaken for unchanged.
26
- #
27
- # @param aggregate [Bluebook::Aggregate] the aggregate whose value objects and entities
28
- # are searched for `type_name`
29
- # @param type_name [String, Bluebook::Reference] the attribute's declared type
30
- # @param seen [Array<String, Bluebook::Reference>] types already being expanded, which
31
- # stops a self-referencing type from recursing forever
32
- # @return [String, Bluebook::Reference, Array] `type_name` itself for a primitive, a
33
- # reference, or a type already in `seen`; otherwise `[type_name, members]`, where
34
- # `members` is an Array of `[member_name, signature]` pairs sorted by member name
14
+ # Expands a declared type so same-named types with different members never compare equal.
15
+ # Primitives and references come back as-is; `seen` stops self-referencing types.
35
16
  def attribute_signature(aggregate, type_name, seen = [])
36
17
  container = nested_type(aggregate, type_name)
37
18
  return type_name if container.nil? || seen.include?(type_name)
@@ -42,42 +23,13 @@ module Hecks
42
23
  [type_name, members]
43
24
  end
44
25
 
45
- # Looks a type name up among an aggregate's value objects, then its entities.
46
- #
47
- # @param aggregate [Bluebook::Aggregate] the aggregate to search
48
- # @param type_name [String, Bluebook::Reference] the declared type to find
49
- # @return [Bluebook::ValueObject, Bluebook::Entity, nil] the matching declaration; nil
50
- # when the type is a primitive, a reference, or nothing this aggregate declares
51
26
  def nested_type(aggregate, type_name)
52
27
  aggregate.value_object(type_name) || aggregate.entities.find { |entity| entity.name == type_name }
53
28
  end
54
29
 
55
- # Lists the new attributes that would leave an existing record with a required gap.
56
- #
57
- # Attributes present now that the held shape never had — the
58
- # addition side of drift, which `uncovered_attributes` below never
59
- # looks at, since it only walks the held shape (vanish/retype).
60
- # Most additions are free (ADR 0025, "Added attributes and
61
- # absence"): a default:, a list_of (frozen []), or a value object
62
- # whose fields all default fill an existing record automatically
63
- # via `Instance.hydrate_with_defaults`. Only the fourth case — a
64
- # non-optional attribute with no way to fill itself — can leave an
65
- # existing record with the field genuinely absent, and that is
66
- # what this reports: unfilled by a declared translation's own
67
- # `backfill`, or by a move/convert that lands an old field inside
68
- # this brand-new attribute (`Lineage#fills?` — the destination-
69
- # side question, never `explains?`'s source-side one, since a
70
- # rename from Crate to Bin can introduce a top-level attribute
71
- # name that never existed to have "vanished").
72
- #
73
- # @param aggregate [Bluebook::Aggregate] the aggregate as currently declared
74
- # @param held_aggregate [Bluebook::Aggregate] the same aggregate as the held era's text
75
- # declares it
76
- # @param lineage [Ports::Persistence::Lineage, nil] the edge's rules for this aggregate; nil
77
- # when the edge declares none, so nothing can fill an addition
78
- # @return [Array<Symbol>] names of new, non-optional attributes with no default, no
79
- # list cardinality, no fully-defaulted value object and no rule filling them; `[]`
80
- # when every addition is safe
30
+ # Names of new, non-optional attributes that no default, list, defaulted value object
31
+ # or translation rule (`Lineage#fills?`) can fill on an existing record.
32
+ # Destination-side check: a rename can add a name that never existed to "vanish".
81
33
  def unsafe_additions(aggregate, held_aggregate, lineage)
82
34
  held_names = held_aggregate.attributes.map(&:name)
83
35
 
@@ -88,17 +40,7 @@ module Hecks
88
40
  .map(&:name)
89
41
  end
90
42
 
91
- # Decides whether a new attribute could be genuinely absent from an existing record.
92
- #
93
- # The four-row table, as a predicate over the fourth row only — the
94
- # other three (default:, list_of, a fully-defaulted value object)
95
- # all fill an existing record for free and never reach here.
96
- #
97
- # @param aggregate [Bluebook::Aggregate] the aggregate declaring the attribute, searched
98
- # for the value object its type may name
99
- # @param attribute [Bluebook::Attribute] the newly added attribute
100
- # @return [Boolean] false when the attribute is optional, has a default, is a list, or
101
- # is a value object whose every field has a default; true otherwise
43
+ # True when a new attribute could be genuinely absent from an existing record (ADR 0025).
102
44
  def possibly_absent?(aggregate, attribute)
103
45
  return false if attribute.optional?
104
46
  return false unless attribute.default.nil?
@@ -110,24 +52,8 @@ module Hecks
110
52
  true
111
53
  end
112
54
 
113
- # Lists the held paths that vanished or changed type with no rule explaining them.
114
- #
115
- # Paths the translation needs to explain: attributes that vanished
116
- # by name, attributes that kept their name but changed type (a
117
- # `convert` is what lets that be declared at all), and — recursing
118
- # into a same-named, same-typed value object — its own members
119
- # vanishing or changing type one level down, reported as a dotted
120
- # path ("price.currency"). A pure addition, at any depth, never
121
- # needs covering; only vanish-or-retype does, matching the
122
- # top-level rule at every depth.
123
- #
124
- # @param aggregate [Bluebook::Aggregate] the aggregate as currently declared
125
- # @param held_aggregate [Bluebook::Aggregate] the same aggregate as the held era's text
126
- # declares it
127
- # @param lineage [Ports::Persistence::Lineage, nil] the edge's rules for this aggregate; nil
128
- # when the edge declares none, so every vanished or retyped path is reported
129
- # @return [Array<String>] bare attribute names and dotted member paths such as
130
- # `"price.currency"`; `[]` when the whole diff is explained
55
+ # Held attribute paths that vanished or changed type with no rule explaining them,
56
+ # recursing into value objects as dotted paths ("price.currency"). Additions never count.
131
57
  def uncovered_attributes(aggregate, held_aggregate, lineage)
132
58
  paths = held_aggregate.attributes.flat_map do |held_attribute|
133
59
  current_attribute = aggregate.attribute(held_attribute.name)
@@ -142,38 +68,12 @@ module Hecks
142
68
  end
143
69
 
144
70
  # Compares one path's held and current types, recursing into shared members.
145
- #
146
- # `held_type`/`current_type` are type names, resolved against each
147
- # side's own value_object and entity declarations — neither is ever
148
- # nested in the DSL, only in the type graph, so both are always
149
- # looked up flat off their respective aggregate. A `list_of` entity
150
- # is only reached here to detect a member vanish-or-retype; there is
151
- # no per-element translation machinery yet (`move`/`convert`/`drop`
152
- # only reach into a single nested hash, not each element of an
153
- # array) — the only way to satisfy a refusal on an entity path
154
- # today is a top-level `drop` of the whole list attribute, which
155
- # `explains?` already recognizes as covering everything nested
156
- # under it. Blunt, but loud beats silent.
157
- #
158
- # @param path [String] the bare or dotted path being compared, reported on a mismatch
159
- # @param held_type [String, Bluebook::Reference] the type the held era declares there
160
- # @param current_type [String, Bluebook::Reference] the type declared there now
161
- # @param held_aggregate [Bluebook::Aggregate] the held aggregate, searched for
162
- # `held_type`'s declaration
163
- # @param aggregate [Bluebook::Aggregate] the current aggregate, searched for
164
- # `current_type`'s declaration
165
- # @param lineage [Ports::Persistence::Lineage, nil] the edge's rules, asked whether a retype
166
- # pairs the two type names; nil means no retype is accepted
167
- # @param seen [Array<String, Bluebook::Reference>] current types already being
168
- # expanded, which stops a self-referencing type from recursing forever
169
- # @return [Array<String>] `[path]` when the types differ with no retype declared; the
170
- # dotted paths of members that vanished or changed type beneath it; `[]` when
171
- # nothing differs or either type is not a value object or entity
71
+ # A `list_of` entity is diffed only for member drift; no per-element translation exists, so
72
+ # only a top-level `drop` of the whole list satisfies it.
172
73
  def diff_type(path, held_type, current_type, held_aggregate, aggregate, lineage, seen = [])
173
74
  if held_type != current_type
174
- # A declared retype says the two type names mean the same shape
175
- # — accept the pair, but still recurse into the members so a
176
- # member drift hiding beneath the rename is caught by name.
75
+ # A declared retype accepts the pair but members are still compared, so drift
76
+ # hidden under the rename is caught.
177
77
  return [path] unless lineage&.retype?(held_type, current_type)
178
78
  end
179
79
  return [] if seen.include?(current_type)