hecks 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (408) hide show
  1. checksums.yaml +5 -5
  2. data/lib/hecks/adapters/driven/claude_code.adapter +3 -0
  3. data/lib/hecks/adapters/driven/claude_code.rb +127 -0
  4. data/lib/hecks/adapters/driven/d1.adapter +12 -0
  5. data/lib/hecks/adapters/driven/d1.rb +403 -0
  6. data/lib/hecks/adapters/driven/folder.adapter +3 -0
  7. data/lib/hecks/adapters/driven/folder.rb +199 -0
  8. data/lib/hecks/adapters/driven/google_authentication.adapter +3 -0
  9. data/lib/hecks/adapters/driven/google_authentication.rb +100 -0
  10. data/lib/hecks/adapters/driven/governance_authorization.adapter +3 -0
  11. data/lib/hecks/adapters/driven/governance_authorization.rb +62 -0
  12. data/lib/hecks/adapters/driven/heki/journal.rb +51 -0
  13. data/lib/hecks/adapters/driven/heki/saga_store.rb +0 -0
  14. data/lib/hecks/adapters/driven/heki/snapshot.rb +38 -0
  15. data/lib/hecks/adapters/driven/heki.adapter +4 -0
  16. data/lib/hecks/adapters/driven/heki.rb +148 -0
  17. data/lib/hecks/adapters/driven/identity_registry.adapter +3 -0
  18. data/lib/hecks/adapters/driven/identity_registry.rb +26 -0
  19. data/lib/hecks/adapters/driven/in_memory_ordering.rb +51 -0
  20. data/lib/hecks/adapters/driven/lambda/client.rb +63 -0
  21. data/lib/hecks/adapters/driven/lambda.adapter +4 -0
  22. data/lib/hecks/adapters/driven/lambda.rb +131 -0
  23. data/lib/hecks/adapters/driven/memory.adapter +3 -0
  24. data/lib/hecks/adapters/driven/memory.rb +103 -0
  25. data/lib/hecks/adapters/driven/mock_stripe_adapter.adapter +3 -0
  26. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +28 -0
  27. data/lib/hecks/adapters/driven/postgres/codec.rb +80 -0
  28. data/lib/hecks/adapters/driven/postgres/schema_builder.rb +168 -0
  29. data/lib/hecks/adapters/driven/postgres.adapter +5 -0
  30. data/lib/hecks/adapters/driven/postgres.rb +391 -0
  31. data/lib/hecks/adapters/driven/postgres_era/lineage/era_store.rb +171 -0
  32. data/lib/hecks/adapters/driven/postgres_era/lineage/field_cache.rb +190 -0
  33. data/lib/hecks/adapters/driven/postgres_era/lineage/head_compiler.rb +429 -0
  34. data/lib/hecks/adapters/driven/postgres_era/lineage/mint_transaction.rb +166 -0
  35. data/lib/hecks/adapters/driven/postgres_era/lineage/provisioning.rb +286 -0
  36. data/lib/hecks/adapters/driven/postgres_era/lineage/resumable_backfill.rb +168 -0
  37. data/lib/hecks/adapters/driven/postgres_era/lineage/tail_merge.rb +163 -0
  38. data/lib/hecks/adapters/driven/postgres_era/lineage/transform_installer.rb +114 -0
  39. data/lib/hecks/adapters/driven/postgres_era/lineage.rb +137 -0
  40. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/coverage_check.rb +89 -0
  41. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/era_resolver.rb +82 -0
  42. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/merge_coordinator.rb +43 -0
  43. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/minter.rb +132 -0
  44. data/lib/hecks/adapters/driven/postgres_era/lineage_manager.rb +74 -0
  45. data/lib/hecks/adapters/driven/postgres_era.adapter +6 -0
  46. data/lib/hecks/adapters/driven/postgres_era.rb +671 -0
  47. data/lib/hecks/adapters/driven/prism.adapter +3 -0
  48. data/lib/hecks/adapters/driven/prism.rb +80 -0
  49. data/lib/hecks/adapters/driven/secure_random_identity.adapter +3 -0
  50. data/lib/hecks/adapters/driven/secure_random_identity.rb +14 -0
  51. data/lib/hecks/adapters/driven/sql_query_builder.rb +221 -0
  52. data/lib/hecks/adapters/driven/sqlite/codec.rb +63 -0
  53. data/lib/hecks/adapters/driven/sqlite/projection.rb +105 -0
  54. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +180 -0
  55. data/lib/hecks/adapters/driven/sqlite.adapter +9 -0
  56. data/lib/hecks/adapters/driven/sqlite.rb +285 -0
  57. data/lib/hecks/adapters/driven/system_clock.adapter +3 -0
  58. data/lib/hecks/adapters/driven/system_clock.rb +14 -0
  59. data/lib/hecks/adapters/driven.rb +36 -0
  60. data/lib/hecks/adapters.rb +6 -0
  61. data/lib/hecks/behaviors/dsl.rb +96 -0
  62. data/lib/hecks/behaviors/expectations.rb +280 -0
  63. data/lib/hecks/behaviors/ir.rb +31 -0
  64. data/lib/hecks/behaviors/rspec.rb +42 -0
  65. data/lib/hecks/behaviors/runner.rb +96 -0
  66. data/lib/hecks/behaviors.rb +25 -0
  67. data/lib/hecks/bluebook/aggregate.rb +108 -0
  68. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +134 -0
  69. data/lib/hecks/bluebook/assembly/build.rb +48 -0
  70. data/lib/hecks/bluebook/assembly/contract.rb +112 -0
  71. data/lib/hecks/bluebook/assembly/contracts.rb +409 -0
  72. data/lib/hecks/bluebook/assembly/marks.rb +227 -0
  73. data/lib/hecks/bluebook/assembly/specializer.rb +70 -0
  74. data/lib/hecks/bluebook/assembly.rb +78 -0
  75. data/lib/hecks/bluebook/attribute.rb +96 -0
  76. data/lib/hecks/bluebook/behaviour/aggregate.rb +83 -0
  77. data/lib/hecks/bluebook/behaviour/attribute.rb +27 -0
  78. data/lib/hecks/bluebook/behaviour/chapter.rb +72 -0
  79. data/lib/hecks/bluebook/behaviour/command.rb +116 -0
  80. data/lib/hecks/bluebook/behaviour/domain_port.rb +25 -0
  81. data/lib/hecks/bluebook/behaviour/entity.rb +59 -0
  82. data/lib/hecks/bluebook/behaviour/hexagon.rb +50 -0
  83. data/lib/hecks/bluebook/behaviour/lifecycle.rb +51 -0
  84. data/lib/hecks/bluebook/behaviour/policy.rb +52 -0
  85. data/lib/hecks/bluebook/behaviour/process_manager.rb +38 -0
  86. data/lib/hecks/bluebook/behaviour/query.rb +10 -0
  87. data/lib/hecks/bluebook/behaviour/read_model.rb +29 -0
  88. data/lib/hecks/bluebook/behaviour/traits.rb +81 -0
  89. data/lib/hecks/bluebook/behaviour/value_object.rb +33 -0
  90. data/lib/hecks/bluebook/chapter.rb +68 -0
  91. data/lib/hecks/bluebook/command.rb +124 -0
  92. data/lib/hecks/bluebook/domain_port.rb +102 -0
  93. data/lib/hecks/bluebook/dsl/adapter_builder.rb +34 -0
  94. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +906 -0
  95. data/lib/hecks/bluebook/dsl/attribute_collector.rb +327 -0
  96. data/lib/hecks/bluebook/dsl/binding_proxy.rb +71 -0
  97. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +1018 -0
  98. data/lib/hecks/bluebook/dsl/command_builder.rb +626 -0
  99. data/lib/hecks/bluebook/dsl/const_shim.rb +81 -0
  100. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +79 -0
  101. data/lib/hecks/bluebook/dsl/entity_builder.rb +305 -0
  102. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +366 -0
  103. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +163 -0
  104. data/lib/hecks/bluebook/dsl/identity_declaration.rb +191 -0
  105. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +44 -0
  106. data/lib/hecks/bluebook/dsl/malformed.rb +7 -0
  107. data/lib/hecks/bluebook/dsl/policy_builder.rb +120 -0
  108. data/lib/hecks/bluebook/dsl/port_builder.rb +30 -0
  109. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +142 -0
  110. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +207 -0
  111. data/lib/hecks/bluebook/dsl/query_builder.rb +113 -0
  112. data/lib/hecks/bluebook/dsl/read_model_builder.rb +233 -0
  113. data/lib/hecks/bluebook/dsl/rule_reference.rb +172 -0
  114. data/lib/hecks/bluebook/dsl/translation_builder.rb +243 -0
  115. data/lib/hecks/bluebook/dsl/value_object_builder.rb +178 -0
  116. data/lib/hecks/bluebook/dsl/word_gate.rb +221 -0
  117. data/lib/hecks/bluebook/dsl/world_builder.rb +77 -0
  118. data/lib/hecks/bluebook/dsl.rb +45 -0
  119. data/lib/hecks/bluebook/entity.rb +103 -0
  120. data/lib/hecks/bluebook/expression/canonical_form.rb +55 -0
  121. data/lib/hecks/bluebook/expression/evaluator.rb +261 -0
  122. data/lib/hecks/bluebook/expression/projection.json +170 -0
  123. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +233 -0
  124. data/lib/hecks/bluebook/expression/resolver.rb +630 -0
  125. data/lib/hecks/bluebook/expression.rb +13 -0
  126. data/lib/hecks/bluebook/hexagon.rb +60 -0
  127. data/lib/hecks/bluebook/lifecycle.rb +42 -0
  128. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +54 -0
  129. data/lib/hecks/bluebook/meta_validator/judge.rb +559 -0
  130. data/lib/hecks/bluebook/meta_validator/plan.rb +332 -0
  131. data/lib/hecks/bluebook/meta_validator/port_judge.rb +47 -0
  132. data/lib/hecks/bluebook/meta_validator/readings.rb +350 -0
  133. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +312 -0
  134. data/lib/hecks/bluebook/meta_validator/shapes.rb +246 -0
  135. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +255 -0
  136. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +138 -0
  137. data/lib/hecks/bluebook/meta_validator/world_judge.rb +78 -0
  138. data/lib/hecks/bluebook/meta_validator.rb +452 -0
  139. data/lib/hecks/bluebook/model_check.rb +318 -0
  140. data/lib/hecks/bluebook/pattern_subset.rb +120 -0
  141. data/lib/hecks/bluebook/policy.rb +41 -0
  142. data/lib/hecks/bluebook/process_manager.rb +86 -0
  143. data/lib/hecks/bluebook/project_discovery.rb +30 -0
  144. data/lib/hecks/bluebook/project_loader.rb +40 -0
  145. data/lib/hecks/bluebook/project_register.rb +82 -0
  146. data/lib/hecks/bluebook/query.rb +61 -0
  147. data/lib/hecks/bluebook/read_model.rb +109 -0
  148. data/lib/hecks/bluebook/reference.rb +74 -0
  149. data/lib/hecks/bluebook/smoke_test.rb +166 -0
  150. data/lib/hecks/bluebook/synthesizer.rb +95 -0
  151. data/lib/hecks/bluebook/translation.rb +92 -0
  152. data/lib/hecks/bluebook/value_object.rb +58 -0
  153. data/lib/hecks/bluebook.rb +74 -0
  154. data/lib/hecks/codemod.rb +342 -0
  155. data/lib/hecks/construct.rb +71 -0
  156. data/lib/hecks/deploy/bluebook/deploy.bluebook +219 -0
  157. data/lib/hecks/deploy/bluebook/deploy.hecksagon +4 -0
  158. data/lib/hecks/deploy/oidc.json +18 -0
  159. data/lib/hecks/doc/reference.rb +389 -0
  160. data/lib/hecks/embryonaut_bluebook.rb +75 -0
  161. data/lib/hecks/facade/cli_door.rb +116 -0
  162. data/lib/hecks/facade/cli_runner.rb +190 -0
  163. data/lib/hecks/facade/command_request.rb +105 -0
  164. data/lib/hecks/facade/handle.rb +173 -0
  165. data/lib/hecks/facade/json_door.rb +154 -0
  166. data/lib/hecks/facade/surface/aggregate_door.rb +185 -0
  167. data/lib/hecks/facade/surface/chapter.rb +107 -0
  168. data/lib/hecks/facade/surface.rb +48 -0
  169. data/lib/hecks/facade.rb +44 -0
  170. data/lib/hecks/forms/app.rb +300 -0
  171. data/lib/hecks/forms/command_form_renderer.rb +113 -0
  172. data/lib/hecks/forms/examples/banking_console.bluebook +3 -0
  173. data/lib/hecks/forms/field_renderer.rb +170 -0
  174. data/lib/hecks/forms/field_shape.rb +232 -0
  175. data/lib/hecks/forms/html.rb +53 -0
  176. data/lib/hecks/forms/index_renderer.rb +35 -0
  177. data/lib/hecks/forms/page.rb +157 -0
  178. data/lib/hecks/forms/params.rb +132 -0
  179. data/lib/hecks/forms/query_form_renderer.rb +114 -0
  180. data/lib/hecks/forms/record_renderer.rb +115 -0
  181. data/lib/hecks/forms/record_table.rb +63 -0
  182. data/lib/hecks/forms/reference_options.rb +30 -0
  183. data/lib/hecks/forms/value_object_shape.rb +46 -0
  184. data/lib/hecks/forms.rb +54 -0
  185. data/lib/hecks/fqn.rb +94 -0
  186. data/lib/hecks/framework/bluebook/compliance.bluebook +1 -0
  187. data/lib/hecks/framework/bluebook/console_settings.bluebook +489 -0
  188. data/lib/hecks/framework/bluebook/framework.hecksagon +32 -0
  189. data/lib/hecks/framework/bluebook/governance.bluebook +130 -0
  190. data/lib/hecks/framework/bluebook/identity.bluebook +90 -0
  191. data/lib/hecks/framework/oidc.json +39 -0
  192. data/lib/hecks/framework.rb +90 -0
  193. data/lib/hecks/freezer.rb +67 -0
  194. data/lib/hecks/fuzzing/invalid_value_generator.rb +86 -0
  195. data/lib/hecks/fuzzing/isolated_boot.rb +92 -0
  196. data/lib/hecks/fuzzing/properties.rb +1146 -0
  197. data/lib/hecks/fuzzing/replay.rb +635 -0
  198. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +93 -0
  199. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +54 -0
  200. data/lib/hecks/fuzzing/sequence_generator/picker.rb +96 -0
  201. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +185 -0
  202. data/lib/hecks/fuzzing/sequence_generator.rb +130 -0
  203. data/lib/hecks/fuzzing/value_generator.rb +177 -0
  204. data/lib/hecks/fuzzing.rb +12 -0
  205. data/lib/hecks/grammar/evolve.rb +291 -0
  206. data/lib/hecks/grammar/expression.bluebook +417 -0
  207. data/lib/hecks/grammar/expression_operators.json +1152 -0
  208. data/lib/hecks/grammar/grammar.hecksagon +20 -0
  209. data/lib/hecks/grammar/oidc.json +69 -0
  210. data/lib/hecks/grammar/translation.bluebook +203 -0
  211. data/lib/hecks/grammar.rb +178 -0
  212. data/lib/hecks/ir.rb +126 -0
  213. data/lib/hecks/language/adapter.bluebook +116 -0
  214. data/lib/hecks/language/bluebook/aggregate.bluebook +581 -0
  215. data/lib/hecks/language/bluebook/attaches/paging.bluebook +76 -0
  216. data/lib/hecks/language/bluebook/bluebook.bluebook +256 -0
  217. data/lib/hecks/language/bluebook/bluebook.hecksagon +24 -0
  218. data/lib/hecks/language/bluebook/command.bluebook +437 -0
  219. data/lib/hecks/language/bluebook/entity.bluebook +316 -0
  220. data/lib/hecks/language/bluebook/policy.bluebook +172 -0
  221. data/lib/hecks/language/bluebook/process_manager.bluebook +264 -0
  222. data/lib/hecks/language/bluebook/projection.bluebook +267 -0
  223. data/lib/hecks/language/bluebook/query.bluebook +245 -0
  224. data/lib/hecks/language/bluebook/shape.bluebook +292 -0
  225. data/lib/hecks/language/bluebook/syntax.bluebook +447 -0
  226. data/lib/hecks/language/bluebook/vocabulary.bluebook +364 -0
  227. data/lib/hecks/language/hecksagon/adapter_binding.bluebook +51 -0
  228. data/lib/hecks/language/hecksagon/domain_port.bluebook +76 -0
  229. data/lib/hecks/language/hecksagon/hecksagon.bluebook +131 -0
  230. data/lib/hecks/language/hecksagon/port_operation.bluebook +102 -0
  231. data/lib/hecks/language/oidc.json +313 -0
  232. data/lib/hecks/language/port.bluebook +92 -0
  233. data/lib/hecks/language/translation/translation.bluebook +110 -0
  234. data/lib/hecks/language/translation/translation_aggregate.bluebook +267 -0
  235. data/lib/hecks/language/world/wiring.bluebook +62 -0
  236. data/lib/hecks/language/world/world.bluebook +84 -0
  237. data/lib/hecks/literal.rb +125 -0
  238. data/lib/hecks/naming.rb +121 -0
  239. data/lib/hecks/ports/access_control.port +4 -0
  240. data/lib/hecks/ports/access_control.rb +62 -0
  241. data/lib/hecks/ports/agent/answers.rb +104 -0
  242. data/lib/hecks/ports/agent.port +4 -0
  243. data/lib/hecks/ports/agent.rb +167 -0
  244. data/lib/hecks/ports/authentication.port +4 -0
  245. data/lib/hecks/ports/authentication.rb +50 -0
  246. data/lib/hecks/ports/authorization.port +4 -0
  247. data/lib/hecks/ports/authorization.rb +59 -0
  248. data/lib/hecks/ports/clock.port +4 -0
  249. data/lib/hecks/ports/clock.rb +62 -0
  250. data/lib/hecks/ports/extraction.port +4 -0
  251. data/lib/hecks/ports/extraction.rb +37 -0
  252. data/lib/hecks/ports/identity_assignment.port +4 -0
  253. data/lib/hecks/ports/identity_assignment.rb +45 -0
  254. data/lib/hecks/ports/identity_generation.port +4 -0
  255. data/lib/hecks/ports/identity_generation.rb +49 -0
  256. data/lib/hecks/ports/identity_resolution.port +4 -0
  257. data/lib/hecks/ports/identity_resolution.rb +40 -0
  258. data/lib/hecks/ports/loading.port +4 -0
  259. data/lib/hecks/ports/loading.rb +13 -0
  260. data/lib/hecks/ports/persistence/append_only.rb +102 -0
  261. data/lib/hecks/ports/persistence/binding_policy.rb +56 -0
  262. data/lib/hecks/ports/persistence/execution.rb +18 -0
  263. data/lib/hecks/ports/persistence/lineage.rb +277 -0
  264. data/lib/hecks/ports/persistence/null_saga_store.rb +25 -0
  265. data/lib/hecks/ports/persistence/remote_runtime.rb +42 -0
  266. data/lib/hecks/ports/persistence/repository_factory.rb +30 -0
  267. data/lib/hecks/ports/persistence.port +4 -0
  268. data/lib/hecks/ports/persistence.rb +39 -0
  269. data/lib/hecks/ports/projection.port +4 -0
  270. data/lib/hecks/ports/projection.rb +76 -0
  271. data/lib/hecks/ports/query/in_memory.rb +60 -0
  272. data/lib/hecks/ports/query/ordering.rb +41 -0
  273. data/lib/hecks/ports/query.rb +36 -0
  274. data/lib/hecks/ports.rb +27 -0
  275. data/lib/hecks/projections/diagrams.rb +413 -0
  276. data/lib/hecks/projections/ir.rb +18 -0
  277. data/lib/hecks/projections/model/deviations.rb +98 -0
  278. data/lib/hecks/projections/model.rb +145 -0
  279. data/lib/hecks/projections/oidc.rb +110 -0
  280. data/lib/hecks/projections/parser_table.rb +159 -0
  281. data/lib/hecks/projections/reference.rb +38 -0
  282. data/lib/hecks/projections/shape.rb +31 -0
  283. data/lib/hecks/projections/statements.rb +110 -0
  284. data/lib/hecks/projections/vocabulary.rb +100 -0
  285. data/lib/hecks/projections.rb +32 -0
  286. data/lib/hecks/projector/cli_projector.rb +437 -0
  287. data/lib/hecks/projector/docs_projector.rb +321 -0
  288. data/lib/hecks/projector/exporter.rb +141 -0
  289. data/lib/hecks/projector/ir_projector.rb +18 -0
  290. data/lib/hecks/projector/narrate_projector.rb +243 -0
  291. data/lib/hecks/projector/target.rb +97 -0
  292. data/lib/hecks/projector.rb +186 -0
  293. data/lib/hecks/query_ir.rb +392 -0
  294. data/lib/hecks/query_specification/common/authorization_spec.rb +9 -0
  295. data/lib/hecks/query_specification/common/comparators.rb +25 -0
  296. data/lib/hecks/query_specification/common/comparison.rb +174 -0
  297. data/lib/hecks/query_specification/common/cursor_spec.rb +9 -0
  298. data/lib/hecks/query_specification/common/dsl.rb +58 -0
  299. data/lib/hecks/query_specification/common/inspection_spec.rb +9 -0
  300. data/lib/hecks/query_specification/common/limit_spec.rb +9 -0
  301. data/lib/hecks/query_specification/common/null_policy.rb +80 -0
  302. data/lib/hecks/query_specification/common/null_semantics.rb +11 -0
  303. data/lib/hecks/query_specification/common/offset_spec.rb +9 -0
  304. data/lib/hecks/query_specification/common/options.rb +32 -0
  305. data/lib/hecks/query_specification/common/order_by.rb +9 -0
  306. data/lib/hecks/query_specification/common/specification.rb +10 -0
  307. data/lib/hecks/query_specification/common/where_clause.rb +9 -0
  308. data/lib/hecks/query_specification/field_path.rb +89 -0
  309. data/lib/hecks/query_specification/hop_path.rb +130 -0
  310. data/lib/hecks/query_specification/read_model/specification.rb +18 -0
  311. data/lib/hecks/query_specification.rb +14 -0
  312. data/lib/hecks/rendering.rb +48 -0
  313. data/lib/hecks/router/namespace_installer.rb +157 -0
  314. data/lib/hecks/router.rb +70 -0
  315. data/lib/hecks/runtime/caller.rb +50 -0
  316. data/lib/hecks/runtime/capability_graph.rb +44 -0
  317. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +124 -0
  318. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +248 -0
  319. data/lib/hecks/runtime/command_interpreter.rb +413 -0
  320. data/lib/hecks/runtime/command_rules/admissibility.rb +307 -0
  321. data/lib/hecks/runtime/command_rules/arithmetic.rb +254 -0
  322. data/lib/hecks/runtime/command_rules/authorization.rb +64 -0
  323. data/lib/hecks/runtime/command_rules/emission.rb +34 -0
  324. data/lib/hecks/runtime/command_rules/references.rb +181 -0
  325. data/lib/hecks/runtime/command_rules.rb +28 -0
  326. data/lib/hecks/runtime/dependency_planning.rb +231 -0
  327. data/lib/hecks/runtime/dispatcher.rb +286 -0
  328. data/lib/hecks/runtime/entity_element.rb +253 -0
  329. data/lib/hecks/runtime/entity_interpreter.rb +228 -0
  330. data/lib/hecks/runtime/era_check.rb +136 -0
  331. data/lib/hecks/runtime/era_guard/shape_diff.rb +128 -0
  332. data/lib/hecks/runtime/era_guard.rb +193 -0
  333. data/lib/hecks/runtime/era_tamper.rb +61 -0
  334. data/lib/hecks/runtime/errors.rb +100 -0
  335. data/lib/hecks/runtime/event.rb +51 -0
  336. data/lib/hecks/runtime/identity.rb +128 -0
  337. data/lib/hecks/runtime/instance.rb +120 -0
  338. data/lib/hecks/runtime/interpreting.rb +69 -0
  339. data/lib/hecks/runtime/loader.rb +143 -0
  340. data/lib/hecks/runtime/policy_interpreter.rb +366 -0
  341. data/lib/hecks/runtime/port_operation_interpreter.rb +210 -0
  342. data/lib/hecks/runtime/query_interpreter.rb +254 -0
  343. data/lib/hecks/runtime/reaction_invocation.rb +245 -0
  344. data/lib/hecks/runtime/read_model_interpreter.rb +266 -0
  345. data/lib/hecks/runtime/rebuild_sweep.rb +74 -0
  346. data/lib/hecks/runtime/reference_hop.rb +99 -0
  347. data/lib/hecks/runtime/refusal_wording.rb +124 -0
  348. data/lib/hecks/runtime/registry/saga_persistence.rb +70 -0
  349. data/lib/hecks/runtime/registry/verification.rb +158 -0
  350. data/lib/hecks/runtime/registry.rb +218 -0
  351. data/lib/hecks/runtime/remote_dispatcher.rb +143 -0
  352. data/lib/hecks/runtime/routing.rb +96 -0
  353. data/lib/hecks/runtime/saga_interpreter/correlation.rb +97 -0
  354. data/lib/hecks/runtime/saga_interpreter.rb +301 -0
  355. data/lib/hecks/runtime/storage_shape.rb +120 -0
  356. data/lib/hecks/runtime/tenant_check.rb +84 -0
  357. data/lib/hecks/runtime/tenant_scope.rb +55 -0
  358. data/lib/hecks/runtime/value/admission.rb +112 -0
  359. data/lib/hecks/runtime/value/coercion.rb +500 -0
  360. data/lib/hecks/runtime/value/invariant_violation.rb +5 -0
  361. data/lib/hecks/runtime/value.rb +125 -0
  362. data/lib/hecks/runtime.rb +95 -0
  363. data/lib/hecks/translation/audit/approval_digest.rb +31 -0
  364. data/lib/hecks/translation/audit/layer_one.rb +37 -0
  365. data/lib/hecks/translation/audit/layer_two.rb +77 -0
  366. data/lib/hecks/translation/audit/unfed_report.rb +42 -0
  367. data/lib/hecks/translation/audit.rb +70 -0
  368. data/lib/hecks/translation/reattest.rb +72 -0
  369. data/lib/hecks/translation/rule_compiler.rb +120 -0
  370. data/lib/hecks/translation/scaffold/differ.rb +183 -0
  371. data/lib/hecks/translation/scaffold/renderer.rb +41 -0
  372. data/lib/hecks/translation/scaffold/writer.rb +28 -0
  373. data/lib/hecks/translation/scaffold.rb +30 -0
  374. data/lib/hecks/translation.rb +11 -0
  375. data/lib/hecks/version.rb +16 -0
  376. data/lib/hecks/vocabulary.rb +213 -0
  377. data/lib/hecks.rb +118 -6
  378. metadata +401 -222
  379. data/bin/hecks +0 -7
  380. data/bin/hecks-package +0 -65
  381. data/bin/hecks_console +0 -12
  382. data/bin/hecks_serverless +0 -6
  383. data/lib/cli/build.rb +0 -14
  384. data/lib/cli/command_runner.rb +0 -28
  385. data/lib/cli/console.rb +0 -10
  386. data/lib/cli/generate.rb +0 -37
  387. data/lib/cli/hecks-cli.rb +0 -27
  388. data/lib/cli/test.rb +0 -57
  389. data/lib/console/commands.rb +0 -8
  390. data/lib/console/hecks-console.rb +0 -1
  391. data/lib/packager/README.md +0 -0
  392. data/lib/packager/app_runner.rb +0 -21
  393. data/lib/packager/args.rb +0 -26
  394. data/lib/packager/compatibility/fixnum.rb +0 -6
  395. data/lib/packager/hecks.rb +0 -39
  396. data/lib/packager/query_runner.rb +0 -21
  397. data/lib/packager/resources/Dockerfile +0 -11
  398. data/lib/packager/resources/app_binary +0 -7
  399. data/lib/packager/resources/bundle_config +0 -3
  400. data/lib/packager/resources/traveling-ruby-20150715-2.2.2-linux-x86_64.tar.gz +0 -0
  401. data/lib/packager/resources/traveling-ruby-20150715-2.2.2-osx.tar.gz +0 -0
  402. data/lib/serverless/Domain +0 -32
  403. data/lib/serverless/cli.rb +0 -75
  404. data/lib/serverless/resources/command_name.js +0 -5
  405. data/lib/serverless/resources/environment.js +0 -7
  406. data/lib/serverless/resources/handler.js.tt +0 -28
  407. data/lib/serverless/resources/run_binary.js +0 -22
  408. data/lib/serverless/resources/serverless.yml +0 -20
@@ -0,0 +1,245 @@
1
+ Hecks.bluebook "Bluebook" do
2
+ aggregate "Query" do
3
+ description "One query declared on an aggregate — what it filters on, how it orders, and how many it returns."
4
+
5
+ reference_to Aggregate
6
+
7
+ # Which piece declared it — see Command's entity_id.
8
+ reference_to Entity, as: :entity_id, optional: true
9
+
10
+ # THE IMMEDIATE OWNER, AND ITS NAME — the same derivation Command takes
11
+ # (see the note there), because an ask sits exactly where a verb does and
12
+ # an entity's asks are its own the same way its verbs are.
13
+ identified_by :owner_id, :name
14
+
15
+ attribute :name, QueryName
16
+ attribute :description, QueryText
17
+ attribute :order_field, QueryText
18
+ attribute :order_way, QueryText
19
+ attribute :limit, QueryText
20
+ attribute :wheres, list_of(Filter)
21
+ attribute :attributes, list_of(AskArgument)
22
+ # EVERY OTHER OPTION A QUERY CAN CARRY, as an open map rather than a field
23
+ # each. `offset`, `cursor`, `nulls`, `authorize`, `consistency`, `freshness`,
24
+ # `inspect_query` and `use_index` are eight more specifications, several of them
25
+ # compound — authorize names a policy AND a tenant, freshness a mode AND a max
26
+ # age. Eleven more fields would have to be added here one at a time, and the
27
+ # ninth option would need a twelfth.
28
+ #
29
+ # So they ride as rows: the option's NAME, the KEY within it, and the value. The
30
+ # language already models an open map exactly this way twice — a member's pairs
31
+ # and a world's settings — and both are their own root for the same reason, that
32
+ # no value object can hold a map. Held here as a list because an option belongs
33
+ # to the ask rather than standing alone.
34
+ attribute :options, list_of(AskOption)
35
+
36
+ value_object "QueryName" do
37
+ attribute :value, String
38
+ invariant("a query is named") { !value.to_s.empty? }
39
+ end
40
+
41
+ value_object "QueryText" do
42
+ attribute :value, String
43
+ end
44
+
45
+ value_object "Filter" do
46
+ attribute :field, String
47
+ # THE FIRST USE OF THE WORD. The runtime maps these eight strings
48
+ # through a hand-typed comparator table ; the set it is mapping to is
49
+ # one the language DECLARES, and until the link between them was
50
+ # declared, typing it downstream
51
+ # would have been a guess. This declares it.
52
+ attribute :op, String, admits: "Vocabulary::QueryComparator"
53
+ attribute :value, String
54
+ end
55
+
56
+ value_object "AskArgument" do
57
+ attribute :name, String
58
+ attribute :type, String
59
+ attribute :list, String
60
+ attribute :optional, String, optional: true
61
+ attribute :pattern, String, optional: true
62
+ attribute :default, String
63
+ # The closed set this value must belong to — see Aggregate::Field.
64
+ attribute :admits, String, optional: true
65
+ attribute :relationship, String, optional: true
66
+ end
67
+
68
+ # One entry of one option. `option` names which specification it belongs to
69
+ # (offset, freshness, authorization), `key` the part within it (value, mode,
70
+ # max_age, policy, tenant), and `value` what was declared. A single-valued
71
+ # option is one row ; a compound is one row per part ; a repeated one — an index
72
+ # hint — is one row per occurrence, told apart by `at`.
73
+ value_object "AskOption" do
74
+ attribute :option, String
75
+ attribute :key, String
76
+ attribute :value, String
77
+ attribute :at, String
78
+ end
79
+
80
+ # The way back: everything DECLARED IN the aggregate above. The parent
81
+ # reference IS the query.
82
+ # WHERE IT SITS AMONG ITS SIBLINGS. Declaration order is a FACT ABOUT THE
83
+ # SOURCE — the IR is a contract read straight from this file,
84
+ # field for field AND INDEX FOR INDEX. So the language HOLDS it, instead of
85
+ # inheriting it from whatever order a store happens to iterate: an ask that
86
+ # does not say how it is ordered is answered in identity order, which is
87
+ # right for every other ask and fatal for the one that is the SOURCE.
88
+ value_object "Position" do
89
+ attribute :value, Integer
90
+ end
91
+
92
+ attribute :position, Position
93
+
94
+ query "DeclaredIn" do
95
+ attribute :aggregate, QueryText
96
+ where(aggregate: :aggregate)
97
+ order_by :position
98
+ end
99
+ command "Declare" do
100
+ role "Language"
101
+ goal "Open a query on an aggregate"
102
+
103
+ reference_to Aggregate
104
+ # Declared on an aggregate or on one of its entities — see Command.Declare.
105
+ reference_to Entity, as: :entity_id, optional: true
106
+ attribute :name, QueryName
107
+ attribute :description, QueryText, optional: true
108
+ attribute :order_field, QueryText, optional: true
109
+ attribute :order_way, QueryText, optional: true
110
+ attribute :limit, QueryText, optional: true
111
+
112
+ attribute :position, Position, optional: true
113
+ sets :aggregate
114
+ sets :entity_id
115
+ sets :name
116
+ sets :description
117
+ sets :order_field
118
+ sets :order_way
119
+ sets :limit
120
+ sets :position
121
+ emits "AskDeclared"
122
+ end
123
+
124
+ command "Filter" do
125
+ role "Language"
126
+ goal "Attach one where-clause to the query"
127
+
128
+ attribute :field, QueryText
129
+ # The same word at the same door — see Command.Change.op.
130
+ attribute :op, QueryText, admits: "Vocabulary::QueryComparator"
131
+ attribute :value, QueryText
132
+
133
+ sets :wheres, append: { field: :field, op: :op, value: :value }
134
+
135
+ emits "FilterAttached"
136
+ end
137
+
138
+ command "Option" do
139
+ role "Language"
140
+ goal "Attach one part of one specification option to the query"
141
+
142
+ attribute :option, QueryText
143
+ attribute :key, QueryText
144
+ # AN OPTION MAY HAVE NO VALUE. `consistency :snapshot` with no timeout is a
145
+ # complete declaration, and an option is judged one key at a time — so the
146
+ # `timeout` row arrives carrying nothing. Requiring a value here made every
147
+ # such declaration unbuildable, which is a rule about the LANGUAGE, not
148
+ # about the one spec that noticed.
149
+ attribute :value, QueryText, optional: true
150
+ attribute :at, QueryText, optional: true
151
+
152
+ given("an option is named") { !option.value.to_s.empty? }
153
+
154
+ sets :options, append: { option: :option, key: :key, value: :value, at: :at }
155
+
156
+ emits "OptionAttached"
157
+ end
158
+
159
+ command "Argument" do
160
+ role "Language"
161
+ goal "Attach one parameter to the query"
162
+
163
+ attribute :name, QueryText
164
+ attribute :type, QueryText
165
+ attribute :list, QueryText
166
+ attribute :optional, QueryText, optional: true
167
+ attribute :pattern, QueryText, optional: true
168
+ attribute :default, QueryText, optional: true
169
+ attribute :admits, QueryText, optional: true
170
+ # See Command.Argument's own :relationship (command.bluebook) — the
171
+ # same field, the same reason: an argument minted verbatim from the
172
+ # owner's own reference-typed attribute must carry that fact through
173
+ # the self-hosted round trip too, or the language cannot say it about
174
+ # itself.
175
+ attribute :relationship, QueryText, optional: true
176
+
177
+ sets :attributes, append: { name: :name, type: :type, list: :list, default: :default, optional: :optional, pattern: :pattern, admits: :admits, relationship: :relationship }
178
+
179
+ emits "AskArgumentAttached"
180
+ end
181
+
182
+
183
+ # HOW QUERY IS SPELLED. These rows live with the concept
184
+ # they describe; SyntaxBoot discovers every aggregate-local seed table.
185
+ # Contexts represented here: Query.
186
+ value_object "KeywordSeed" do
187
+ attribute :word, String
188
+ attribute :context, String, admits: "Syntax::Context"
189
+ attribute :body, String, admits: "Syntax::Body"
190
+ attribute :inner, String
191
+ attribute :opens, String
192
+ attribute :fills, String
193
+ attribute :status, String, default: "admitted", admits: "Syntax::Status"
194
+ attribute :was, String
195
+ attribute :resolves_via, String, default: "", admits: "Syntax::ResolutionScope"
196
+ attribute :disambiguator, String, default: "", admits: "Syntax::Disambiguator"
197
+
198
+ member word: "description", context: "Query", body: "none", inner: "", opens: "", fills: "description"
199
+ member word: "attribute", context: "Query", body: "none", inner: "", opens: "", fills: "attributes", calls: "attribute_impl"
200
+ member word: "reference_to", context: "Query", body: "none", inner: "", opens: "", fills: "attributes", calls: "reference_to_impl"
201
+ member word: "where", context: "Query", body: "none", inner: "", opens: "", fills: "wheres", calls: "where_impl"
202
+ member word: "order_by", context: "Query", body: "none", inner: "", opens: "", fills: "order_field", calls: "order_by_impl"
203
+ member word: "authorize", context: "Query", body: "none", inner: "", opens: "", fills: "options", calls: "authorize_impl"
204
+ member word: "inspect_query", context: "Query", body: "none", inner: "", opens: "", fills: "options"
205
+
206
+ end
207
+
208
+ value_object "ArgumentSeed" do
209
+ attribute :keyword, String
210
+ attribute :context, String, admits: "Syntax::Context"
211
+ attribute :at, String
212
+ attribute :named, String
213
+ attribute :kind, String, admits: "Syntax::ArgumentKind"
214
+ attribute :required, String
215
+ attribute :fills, String
216
+ attribute :selects, String
217
+ attribute :pair_key_fills, String
218
+ attribute :pair_value_fills, String
219
+ attribute :pairs_shape, String, admits: "Syntax::PairsShape"
220
+ attribute :status, String, default: "admitted", admits: "Syntax::Status"
221
+ attribute :variadic, String
222
+ attribute :coerce, String
223
+ attribute :blank_message, String
224
+
225
+ member keyword: "description", context: "Query", at: "1", named: "", kind: "text", required: "true", fills: "description", coerce: "false"
226
+ member keyword: "attribute", context: "Query", at: "1", named: "", kind: "symbol", required: "true", fills: "name"
227
+ member keyword: "attribute", context: "Query", at: "2", named: "", kind: "constant", required: "true", fills: "type"
228
+ member keyword: "attribute", context: "Query", at: "", named: "default", kind: "literal", required: "false", fills: "default"
229
+ member keyword: "attribute", context: "Query", at: "", named: "optional", kind: "flag", required: "false", fills: "optional"
230
+ member keyword: "attribute", context: "Query", at: "", named: "pattern", kind: "text", required: "false", fills: "pattern"
231
+ member keyword: "attribute", context: "Query", at: "", named: "admits", kind: "text", required: "false", fills: "admits"
232
+ member keyword: "attribute", context: "Query", at: "", named: "one_of", kind: "list", required: "false", fills: "one_of"
233
+ member keyword: "reference_to", context: "Query", at: "1", named: "", kind: "constant", required: "true", fills: "type"
234
+ member keyword: "reference_to", context: "Query", at: "", named: "as", kind: "symbol", required: "false", fills: "name"
235
+ member keyword: "reference_to", context: "Query", at: "", named: "optional", kind: "flag", required: "false", fills: "optional"
236
+ member keyword: "where", context: "Query", at: "1", named: "", kind: "pairs", required: "true", fills: "wheres", pair_key_fills: "field", pair_value_fills: "value", pairs_shape: "elements"
237
+ member keyword: "order_by", context: "Query", at: "1", named: "", kind: "symbol", required: "true", fills: "order_field"
238
+ member keyword: "order_by", context: "Query", at: "2", named: "", kind: "symbol", required: "false", fills: "order_way"
239
+ member keyword: "authorize", context: "Query", at: "1", named: "", kind: "symbol", required: "true", fills: "policy"
240
+ member keyword: "authorize", context: "Query", at: "", named: "tenant", kind: "symbol", required: "false", fills: "tenant"
241
+ member keyword: "inspect_query", context: "Query", at: "1", named: "", kind: "symbol", required: "false", fills: "mode"
242
+
243
+ end
244
+ end
245
+ end
@@ -0,0 +1,292 @@
1
+ Hecks.bluebook "Bluebook" do
2
+ aggregate "ValueObject" do
3
+ description "One value object declared on an aggregate — its fields and the rules they must satisfy. Its own root because a value object holds nested lists, which no list element can."
4
+
5
+ reference_to Aggregate
6
+
7
+ # THE AGGREGATE IT BELONGS TO, AND ITS NAME. A value object belongs to one
8
+ # aggregate by rule, and `Name` or `Amount` is spelled in half the chapters
9
+ # there are.
10
+ identified_by :aggregate, :name
11
+
12
+ attribute :name, ValueObjectName
13
+ attribute :attributes, list_of(ShapeField)
14
+ attribute :invariants, list_of(Assertion)
15
+ attribute :rows, RowCount, optional: true
16
+ # S17, ADR 0026 — Member NESTED here, an entity rather than its own
17
+ # root aggregate (see `entity "Member"`, below). `list_of(Member)`
18
+ # forward-references it the same way banking's own `attribute :ledger,
19
+ # list_of(LedgerEntry)` names LedgerEntry before it is declared.
20
+ attribute :members, list_of(Member)
21
+
22
+ value_object "RowCount" do
23
+ attribute :value, Integer
24
+ end
25
+
26
+ value_object "ValueObjectName" do
27
+ attribute :value, String, pattern: '[^ \t\n\r]'
28
+ invariant("a value object is named") { !value.to_s.empty? }
29
+ end
30
+
31
+ value_object "ShapeField" do
32
+ attribute :name, String, pattern: '[^ \t\n\r]'
33
+ attribute :type, String, pattern: '[^ \t\n\r]'
34
+ attribute :list, String, pattern: '[^ \t\n\r]'
35
+ attribute :optional, String, optional: true
36
+ attribute :pattern, String, optional: true
37
+ attribute :default, String
38
+ # The closed set this value must belong to — see Aggregate::Field.
39
+ attribute :admits, String, optional: true
40
+ attribute :relationship, String, optional: true
41
+ invariant("a field is named") { !name.to_s.empty? }
42
+ invariant("a field has a type") { !type.to_s.empty? }
43
+ invariant("a field's list mode is specified") { !list.to_s.empty? }
44
+ end
45
+
46
+ value_object "Assertion" do
47
+ attribute :description, String, pattern: '[^ \t\n\r]'
48
+ attribute :canonical, String, pattern: '[^ \t\n\r]'
49
+ invariant("an assertion description is present") { !description.to_s.empty? }
50
+ invariant("an assertion canonical form is present") { !canonical.to_s.empty? }
51
+ end
52
+
53
+ # S17, ADR 0026 — MemberPosition/MemberText/Pair, hoisted up from the
54
+ # old standalone `aggregate "Member"`. An entity cannot declare its own
55
+ # `value_object` (EntityBuilder has no such method — a piece borrows its
56
+ # owning aggregate's, the same way LedgerEntry borrows Account's Money),
57
+ # so these live here now, one level up, where `entity "Member"` below
58
+ # can still reach them.
59
+ #
60
+ # Named MemberPosition rather than reusing ValueObject's own `Position`
61
+ # two lines above — that one orders value objects among an AGGREGATE's
62
+ # siblings ; this one orders admitted rows within ONE value object. Same
63
+ # shape, different fact, so a shared name would have let one silently
64
+ # answer for the other.
65
+ value_object "MemberPosition" do
66
+ attribute :value, Integer
67
+ end
68
+
69
+ value_object "MemberText" do
70
+ attribute :value, String
71
+ # MemberText is free-form serialized text from member definitions,
72
+ # which can include empty strings and numeric literals — not restricted
73
+ end
74
+
75
+ value_object "Pair" do
76
+ attribute :key, String, pattern: '[^ \t\n\r]'
77
+ attribute :value, String
78
+ # Pair keys must be named, but values can be empty strings or numeric literals
79
+ invariant("a pair key is present") { !key.to_s.empty? }
80
+ end
81
+
82
+ # The way back: everything DECLARED IN the aggregate above. The parent
83
+ # reference IS the query.
84
+ # WHERE IT SITS AMONG ITS SIBLINGS. Declaration order is a FACT ABOUT THE
85
+ # SOURCE — the IR is a contract read straight from this file,
86
+ # field for field AND INDEX FOR INDEX. So the language HOLDS it, instead of
87
+ # inheriting it from whatever order a store happens to iterate: an ask that
88
+ # does not say how it is ordered is answered in identity order, which is
89
+ # right for every other ask and fatal for the one that is the SOURCE.
90
+ value_object "Position" do
91
+ attribute :value, Integer
92
+ end
93
+
94
+ attribute :position, Position
95
+
96
+ query "DeclaredIn" do
97
+ attribute :aggregate, ValueObjectText
98
+ where(aggregate: :aggregate)
99
+ order_by :position
100
+ end
101
+ command "Declare" do
102
+ role "Language"
103
+ goal "Open a value object on an aggregate"
104
+
105
+ reference_to Aggregate
106
+ attribute :name, ValueObjectName
107
+
108
+ attribute :position, Position, optional: true
109
+ sets :aggregate
110
+ sets :name
111
+ sets :position
112
+ emits "ShapeDeclared"
113
+ end
114
+
115
+ command "Field" do
116
+ role "Language"
117
+ goal "Attach one field to the value object"
118
+
119
+ attribute :name, ValueObjectName
120
+ attribute :type, ValueObjectName
121
+ attribute :list, ValueObjectName
122
+ attribute :optional, ValueObjectName, optional: true
123
+ # FREE TEXT, like `default` beside it and like the pattern every other
124
+ # element builder takes. `ValueObjectName` carries the invariant "a value
125
+ # object is named", which is not a thing a regex has to be — it happened to
126
+ # admit banking's one pattern because that pattern is not empty, and it
127
+ # said the wrong thing about why.
128
+ attribute :pattern, ValueObjectText, optional: true
129
+ attribute :default, ValueObjectText, optional: true
130
+ attribute :admits, ValueObjectText, optional: true
131
+ # See Command.Argument's own :relationship (command.bluebook) — the
132
+ # same field, the same reason.
133
+ attribute :relationship, ValueObjectText, optional: true
134
+
135
+ sets :attributes, append: { name: :name, type: :type, list: :list, default: :default, optional: :optional, pattern: :pattern, admits: :admits, relationship: :relationship }
136
+
137
+ emits "ShapeFieldAttached"
138
+ end
139
+
140
+ command "Close" do
141
+ role "Language"
142
+ goal "Declare that this value object admits a closed set of rows"
143
+
144
+ # Dispatched only when the bluebook declared a one_of — so an EMPTY closed
145
+ # set is visible where it used to be invisible : a shape that is closed
146
+ # and admits nothing. Members live in their own root (a row is a list of
147
+ # pairs inside a list of rows), so the count is offered rather than read.
148
+
149
+ given("a closed set admits a member") { rows.value > 0 }
150
+
151
+ sets :rows
152
+
153
+ emits "ShapeClosed"
154
+ end
155
+
156
+ command "Assert" do
157
+ role "Language"
158
+ goal "Attach one invariant to the value object"
159
+
160
+ attribute :description, ValueObjectText, optional: true
161
+ attribute :canonical, ValueObjectText
162
+
163
+ given("a rule says what it means") { !description.value.to_s.empty? }
164
+ given("a rule survives extraction") { !canonical.value.to_s.empty? }
165
+
166
+ sets :invariants, append: { description: :description, canonical: :canonical }
167
+
168
+ emits "AssertionAttached"
169
+ end
170
+
171
+ value_object "ValueObjectText" do
172
+ attribute :value, String
173
+ # ValueObjectText is free-form serialized text from member definitions,
174
+ # which can include empty strings and numeric literals — not restricted
175
+ end
176
+
177
+ # THE MEMBER'S OWN CREATION. S17, ADR 0026 — Member is a genuine ENTITY
178
+ # now (`entity "Member"`, below), and an entity is never created through
179
+ # its own dotted verb — banking's own LedgerEntry is created by
180
+ # `Account.LogEntry`, an ordinary append on the OWNER, never by a
181
+ # `LedgerEntry.Declare` of its own (EntityInterpreter#element_of only
182
+ # LOCATES an element already on the list — see entity_interpreter.rb —
183
+ # it has no path that creates one). So Member's creation moved here,
184
+ # onto ValueObject, mirroring `Field`/`Close`/`Assert` beside it :
185
+ # a bare, aggregate-level append. What it creates is empty — pairs fill
186
+ # in afterward, one at a time, through the entity's own `Pair`.
187
+ command "Member" do
188
+ role "Language"
189
+ goal "Open one admitted row on a value object"
190
+
191
+ attribute :position, MemberPosition
192
+
193
+ sets :members, append: { position: :position }
194
+
195
+ emits "MemberDeclared"
196
+ end
197
+
198
+ # S17, ADR 0026 — ONE ADMITTED ROW, nested rather than its own root
199
+ # aggregate. A member has no other distinguishing fact : its pairs are
200
+ # an OPEN MAP, which is the whole reason it used to need a root of its
201
+ # own, and a map cannot be a path — but that was always a reason it
202
+ # could not be a VALUE OBJECT, never a reason it could not be an
203
+ # ENTITY, which is what it structurally always was: a nested, ordered,
204
+ # separately-mutated element of ValueObject's own list. `ValueObject.
205
+ # Member` (above) creates it ; `Pair` (below) fills it in, one field
206
+ # at a time, exactly the way `Command.Rule` fills in a precondition.
207
+ entity "Member" do
208
+ description "One admitted row of a value object's one_of — a whole combination of field values, not a per-field choice. Nested under the value object because a row is a list of pairs inside a list of rows."
209
+
210
+ # Position is not a mint — it is read straight out of the source
211
+ # file, the same fact the language already holds deliberately so
212
+ # that an ask ordered any other way cannot take declaration order
213
+ # away. `ValueObject.Member` mints it as the walk index at creation
214
+ # (the same way `declare`'s own `position` field always has), and
215
+ # every later `Pair` locates the element by it.
216
+ identified_by MemberPosition, as: :position
217
+
218
+ attribute :pairs, list_of(Pair)
219
+
220
+ command "Pair" do
221
+ role "Language"
222
+ goal "Bind one field of the admitted row"
223
+
224
+ attribute :key, MemberText
225
+ attribute :value, MemberText
226
+
227
+ given("an admitted row binds a named field") { !key.value.to_s.empty? }
228
+
229
+ sets :pairs, append: { key: :key, value: :value }
230
+
231
+ emits "PairBound"
232
+ end
233
+ end
234
+
235
+ # HOW VALUEOBJECT IS SPELLED. These rows live with the concept
236
+ # they describe; SyntaxBoot discovers every aggregate-local seed table.
237
+ # Contexts represented here: ValueObject, OneOf, Type.
238
+ value_object "KeywordSeed" do
239
+ attribute :word, String
240
+ attribute :context, String, admits: "Syntax::Context"
241
+ attribute :body, String, admits: "Syntax::Body"
242
+ attribute :inner, String
243
+ attribute :opens, String
244
+ attribute :fills, String
245
+ attribute :status, String, default: "admitted", admits: "Syntax::Status"
246
+ attribute :was, String
247
+ attribute :resolves_via, String, default: "", admits: "Syntax::ResolutionScope"
248
+ attribute :disambiguator, String, default: "", admits: "Syntax::Disambiguator"
249
+
250
+ member word: "attribute", context: "ValueObject", body: "none", inner: "", opens: "", fills: "attributes", calls: "attribute_impl"
251
+ member word: "one_of", context: "ValueObject", body: "rows", inner: "OneOf", opens: "", fills: "rows", calls: "one_of_impl"
252
+ member word: "invariant", context: "ValueObject", body: "source", inner: "", opens: "", fills: "invariants", resolves_via: "sibling_scan", calls: "invariant_impl"
253
+ member word: "member", context: "ValueObject", body: "none", inner: "", opens: "Member", fills: "", calls: "member_impl"
254
+ member word: "member", context: "OneOf", body: "none", inner: "", opens: "Member", fills: "", calls: "member_impl"
255
+ member word: "list_of", context: "Type", body: "none", inner: "", opens: "", fills: "", calls: "list_of_impl"
256
+ member word: "one_of", context: "Type", body: "none", inner: "", opens: "", fills: "", calls: "one_of_impl"
257
+
258
+ end
259
+
260
+ value_object "ArgumentSeed" do
261
+ attribute :keyword, String
262
+ attribute :context, String, admits: "Syntax::Context"
263
+ attribute :at, String
264
+ attribute :named, String
265
+ attribute :kind, String, admits: "Syntax::ArgumentKind"
266
+ attribute :required, String
267
+ attribute :fills, String
268
+ attribute :selects, String
269
+ attribute :pair_key_fills, String
270
+ attribute :pair_value_fills, String
271
+ attribute :pairs_shape, String, admits: "Syntax::PairsShape"
272
+ attribute :status, String, default: "admitted", admits: "Syntax::Status"
273
+ attribute :variadic, String
274
+ attribute :coerce, String
275
+ attribute :blank_message, String
276
+
277
+ member keyword: "attribute", context: "ValueObject", at: "1", named: "", kind: "symbol", required: "true", fills: "name"
278
+ member keyword: "attribute", context: "ValueObject", at: "2", named: "", kind: "constant", required: "true", fills: "type"
279
+ member keyword: "attribute", context: "ValueObject", at: "", named: "default", kind: "literal", required: "false", fills: "default"
280
+ member keyword: "attribute", context: "ValueObject", at: "", named: "optional", kind: "flag", required: "false", fills: "optional"
281
+ member keyword: "attribute", context: "ValueObject", at: "", named: "pattern", kind: "text", required: "false", fills: "pattern"
282
+ member keyword: "attribute", context: "ValueObject", at: "", named: "admits", kind: "text", required: "false", fills: "admits"
283
+ member keyword: "attribute", context: "ValueObject", at: "", named: "one_of", kind: "list", required: "false", fills: "one_of"
284
+ member keyword: "invariant", context: "ValueObject", at: "1", named: "", kind: "text", required: "true", fills: "description"
285
+ member keyword: "member", context: "ValueObject", at: "1", named: "", kind: "pairs", required: "true", fills: "members", pairs_shape: "verbatim"
286
+ member keyword: "member", context: "OneOf", at: "1", named: "", kind: "pairs", required: "true", fills: "members", pairs_shape: "verbatim"
287
+ member keyword: "list_of", context: "Type", at: "1", named: "", kind: "constant", required: "true", fills: ""
288
+ member keyword: "one_of", context: "Type", at: "1", named: "", kind: "literal", required: "true", fills: ""
289
+
290
+ end
291
+ end
292
+ end