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,489 @@
1
+ Hecks.bluebook "ConsoleSettings" do
2
+ vision "A generic admin console's own curated UI facts — nav, columns, state tones, which rows a detail panel shows — as real dispatched data instead of a hand-rewritten YAML file. A UI opinion the DOMAIN it's pointed at has no way to answer, never a business record; see embryonaut_console's own presentation_config.rb for the fuller story."
3
+ supporting
4
+
5
+ # A FRAMEWORK MEMBER LIKE IDENTITY/GOVERNANCE — attach with
6
+ # `uses_framework "ConsoleSettings"` in the consuming app's own
7
+ # `.hecksagon`, plus a `Hecks.hecksagon "ConsoleSettings" do ... end`
8
+ # persistence binding (Heki is the common case — a small, local,
9
+ # per-app settings store, no shared database needed). This used to
10
+ # boot in a SECOND, independent registry (embryonaut_console's own
11
+ # console_settings_domain.rb) specifically so no consuming app needed
12
+ # any change at all — that property is real and now given up on
13
+ # purpose, in favor of the one binding mechanism every other
14
+ # framework member already uses, rather than this being the one
15
+ # exception with its own private boot path.
16
+ #
17
+ # NOT named "Forms" — Hecks::Forms (lib/hecks/forms/) already
18
+ # names a different, real thing: a dormant prototype (the working half
19
+ # of command_form.bluebook/query_form.bluebook, see docs/command-form-
20
+ # and-query-form-bluebook.md) that renders raw forms/query views
21
+ # straight off any IR, zero config. This chapter is the opposite kind
22
+ # of surface — a CURATED, hand-authored dashboard's own settings — and
23
+ # picks a name that doesn't read as the same one.
24
+ #
25
+ # SCOPE: everything presentation.yml carries EXCEPT a collection's own
26
+ # `after_create` (a dispatch chain with a literal-or-$field-or-
27
+ # count_query arg shape — a harder design problem that shouldn't gate
28
+ # everything else; Ruby-side PresentationConfig keeps validating it,
29
+ # same as always, with nowhere yet to persist it). `overview.stats`
30
+ # (Overview, below) and every `extra_json`/`identity_extra_json`
31
+ # field throughout this chapter were BOTH originally scoped out on an
32
+ # "confirmed unused in any real presentation.yml" basis that turned
33
+ # out to be checked against the wrong file — embryonaut_console's own
34
+ # fixture, never this app's actual, live one. Migrating the real file
35
+ # found both very much in use.
36
+
37
+ aggregate "StateStyle" do
38
+ description "One aggregate's one lifecycle state, styled — a tone and whether it needs attention. Every real state gets a row, even a bare one (PresentationConfig's own missing_state_entries! check), so Declare and the two Set commands are separate: a bare row is a real, valid thing to have."
39
+
40
+ # `agg`, not `aggregate` — the bluebook DSL's own word for what's being
41
+ # declared right now; naming an attribute that would shadow it invites
42
+ # exactly the confusion ui_schema.rb's own identity-collision fix
43
+ # (see [[project_generic_founder_app]]) already had to work around
44
+ # once for `id`.
45
+ attribute :agg, StateStyleText
46
+ attribute :state, StateStyleText
47
+ attribute :tone, one_of("good", "warn", "danger", "muted", "accent"), optional: true
48
+
49
+ identified_by :agg, :state
50
+ # `Flag`, wrapping "true"/"false" — not a bare `String` and not
51
+ # `TrueClass`. Two confirmed-by-trying reasons neither works directly
52
+ # on an aggregate/command attribute:
53
+ # - `TrueClass`/`FalseClass` are real, pre-existing Ruby constants,
54
+ # so writing them here resolves through NORMAL Ruby constant
55
+ # lookup rather than ever reaching the DSL's own ConstShim (unlike
56
+ # a bareword like `Flag`, which has no such constant and so DOES
57
+ # reach it) — the meta-validator has no separate case for the
58
+ # literal class objects, so it goes looking for a declared value
59
+ # object named "TrueClass" and fails. `Attribute::PRIMITIVES`
60
+ # lists them, but no real bluebook in this codebase spells one.
61
+ # - A bare primitive (`String`, `Integer`) directly on an
62
+ # AGGREGATE or COMMAND attribute fails the identical way — every
63
+ # real example in this codebase only ever uses `String`/`Integer`
64
+ # INSIDE a `value_object do...end` block, never as a top-level
65
+ # attribute's own type; reproduced with a 4-line isolated bluebook
66
+ # before trusting it as a real rule, not a guess.
67
+ # PresentationConfig's own Ruby glue converts "true"/"false" at the
68
+ # boundary.
69
+ attribute :attention, Flag, optional: true
70
+
71
+ # WHATEVER A STATE ENTRY CARRIES THAT ISN'T tone/attention — a
72
+ # display `label` (e.g. Client's own "active" reading "Active
73
+ # client", not the raw state name) or a `note`, confirmed live as
74
+ # real, in-use fields this schema didn't model. Serialized, not
75
+ # decomposed — the same verified-then-opaque reasoning Overview's
76
+ # own `where_json` already documents: PresentationConfig's own
77
+ # reshape/write is where the real key set is enumerated and
78
+ # subtracted from, in Ruby, not here.
79
+ attribute :extra_json, StateStyleExtra, optional: true
80
+
81
+ value_object "StateStyleText" do
82
+ attribute :value, String
83
+ invariant("names something") { !value.to_s.empty? }
84
+ end
85
+
86
+ value_object "Flag" do
87
+ attribute :value, String
88
+ end
89
+
90
+ # A bare `String` fails directly on an aggregate/command attribute
91
+ # (StateStyleText's own comment gives the confirmed-by-trying
92
+ # reason) — this wraps extra_json's own opaque JSON text the same
93
+ # way every other scalar field in this chapter already wraps one.
94
+ value_object "StateStyleExtra" do
95
+ attribute :value, String
96
+ end
97
+
98
+ command "Declare" do
99
+ role "Console"
100
+ goal "Give one aggregate's one state a presentation row, styled or bare"
101
+
102
+ attribute :agg, StateStyleText
103
+ attribute :state, StateStyleText
104
+
105
+ given("a style names its own aggregate") { !agg.value.to_s.empty? }
106
+ given("a style names its own state") { !state.value.to_s.empty? }
107
+
108
+ emits "StateStyleDeclared"
109
+ end
110
+
111
+ command "SetTone" do
112
+ role "Console"
113
+ goal "Color one state"
114
+
115
+ reference_to StateStyle
116
+ attribute :tone, one_of("good", "warn", "danger", "muted", "accent")
117
+
118
+ sets :tone
119
+ emits "ToneSet"
120
+ end
121
+
122
+ command "SetAttention" do
123
+ role "Console"
124
+ goal "Mark whether one state needs a person's attention"
125
+
126
+ reference_to StateStyle
127
+ attribute :attention, Flag
128
+
129
+ sets :attention
130
+ emits "AttentionSet"
131
+ end
132
+
133
+ command "SetExtra" do
134
+ role "Console"
135
+ goal "Carry whatever per-state fields aren't individually modeled yet (label, note, ...)"
136
+
137
+ reference_to StateStyle
138
+ attribute :extra_json, StateStyleExtra
139
+
140
+ sets :extra_json
141
+ emits "StateStyleExtraSet"
142
+ end
143
+ end
144
+
145
+ aggregate "Collection" do
146
+ description "One app aggregate's own console presentation — nav label, curated columns, detail-panel fields (with an optional entity state_filter and a row_columns subset), identity-assignment strategy, field formats, preconditions, and which query lists it. Every list-shaped piece is rows on this root, never a nested list inside a value object — the same 'an open map is rows on a head' shape Wiring::Setting and Query::AskOption already use, and the same reason: no value object here can hold a map, and this sidesteps ever needing to find out whether one can hold a plain list either."
147
+
148
+ attribute :agg, SettingsText
149
+
150
+ identified_by :agg
151
+
152
+ attribute :label, SettingsText, optional: true
153
+ attribute :key, SettingsText, optional: true
154
+ attribute :nav_order, SettingsNumber, optional: true
155
+ attribute :primary_field, SettingsText, optional: true
156
+ attribute :list_query, SettingsText, optional: true
157
+ attribute :identity_field, SettingsText, optional: true
158
+ attribute :identity_strategy, one_of("slug", "sequence", "port"), optional: true
159
+ attribute :identity_source, SettingsText, optional: true
160
+ attribute :identity_prefix, SettingsText, optional: true
161
+ # `pad` (a sequence strategy's own zero-padding width, e.g. "C-004"
162
+ # vs "C-4") confirmed live as real, in-use — not modeled as its own
163
+ # attribute for the same reason `identity_source`/`identity_prefix`
164
+ # aren't a closed set either: whatever a real identity rule carries
165
+ # beyond field/strategy/source/prefix, opaque, same as extra_json
166
+ # below.
167
+ attribute :identity_extra_json, CollectionExtra, optional: true
168
+ attribute :columns, list_of(Column)
169
+ attribute :detail_fields, list_of(DetailField)
170
+ attribute :detail_field_columns, list_of(DetailFieldColumn)
171
+ attribute :preconditions, list_of(Precondition)
172
+ attribute :field_formats, list_of(FieldFormat)
173
+ # WHATEVER A COLLECTION ENTRY CARRIES beyond the fields above —
174
+ # `noun_sing`, `create_label`, `nav_group` confirmed live as real,
175
+ # in-use fields this schema didn't model (10/8/2 real occurrences
176
+ # respectively). Same verified-then-opaque reasoning as StateStyle's
177
+ # own extra_json.
178
+ attribute :extra_json, CollectionExtra, optional: true
179
+
180
+ value_object "SettingsText" do
181
+ attribute :value, String
182
+ invariant("names something") { !value.to_s.empty? }
183
+ end
184
+
185
+ value_object "SettingsNumber" do
186
+ attribute :value, Integer
187
+ end
188
+
189
+ # A bare `String` fails directly on an aggregate/command attribute —
190
+ # see StateStyleExtra's own comment. Shared by both extra_json and
191
+ # identity_extra_json; both are opaque JSON text, no reason for two
192
+ # separate wrapper types.
193
+ value_object "CollectionExtra" do
194
+ attribute :value, String
195
+ end
196
+
197
+ # A list/table column. `sortable`/`sort_default` are optional — most
198
+ # columns take the frontend's own default (sortable, no forced order).
199
+ # `sort_default` stays a plain String, not a closed set — narrow
200
+ # enough (and PresentationConfig.validate! already checks it in
201
+ # Ruby) that a dedicated `one_of: [...]` (S3, ADR 0025 — the field's
202
+ # own keyword now, no sibling value object or `admits:` indirection
203
+ # needed) still isn't worth it for this one field.
204
+ value_object "Column" do
205
+ attribute :field, String
206
+ attribute :sortable, String, optional: true # "true"/"false" — see StateStyle.attention's own comment
207
+ attribute :sort_default, String, optional: true
208
+ # `head`/`as`/`hop` confirmed live as real, in-use column-level
209
+ # overrides this schema didn't model — verified-then-opaque, same
210
+ # reasoning as StateStyle's own extra_json.
211
+ attribute :extra_json, String, optional: true
212
+ end
213
+
214
+ # One field the detail panel shows. `state_filter` only means anything
215
+ # on an entity-backed rows field (ui_schema.rb's own apply_row_state_
216
+ # filter checks this at read time, same as it does today) — nothing
217
+ # here refuses a state_filter on the wrong shape of field, since that
218
+ # check needs the APP's own live IR, which this domain can't see; it
219
+ # stays a Ruby-side PresentationConfig.validate! check, same as always.
220
+ # `display` is a plain String for the same nested-`one_of` collision
221
+ # reason `sort_default` is, above.
222
+ value_object "DetailField" do
223
+ attribute :field, String
224
+ attribute :display, String, optional: true
225
+ attribute :state_filter, String, optional: true
226
+ # `head`/`as`/`hop` confirmed live as real, in-use detail-field
227
+ # overrides this schema didn't model — verified-then-opaque, same
228
+ # reasoning as StateStyle's own extra_json.
229
+ attribute :extra_json, String, optional: true
230
+ end
231
+
232
+ # A rows-shaped detail field's own sub-column filter, FLATTENED to one
233
+ # row per (field, column) pair rather than nested inside DetailField —
234
+ # grouped back by `field` on the way out. The same flattening
235
+ # Query::AskOption already uses for a compound option's own parts.
236
+ value_object "DetailFieldColumn" do
237
+ attribute :field, String
238
+ attribute :column, String
239
+ end
240
+
241
+ value_object "Precondition" do
242
+ attribute :field, String
243
+ attribute :state, String
244
+ # `message` (a custom refusal message override) confirmed live as
245
+ # real, in-use — verified-then-opaque, same reasoning as
246
+ # StateStyle's own extra_json.
247
+ attribute :extra_json, String, optional: true
248
+ end
249
+
250
+ # `format` stays a plain String too — same nested-`one_of` collision.
251
+ value_object "FieldFormat" do
252
+ attribute :field, String
253
+ attribute :format, String
254
+ end
255
+
256
+ command "Declare" do
257
+ role "Console"
258
+ goal "Give one app aggregate a presentation row, before anything is curated on it yet"
259
+
260
+ attribute :agg, SettingsText
261
+
262
+ given("a collection names its own aggregate") { !agg.value.to_s.empty? }
263
+
264
+ emits "CollectionDeclared"
265
+ end
266
+
267
+ command "SetLabel" do
268
+ role "Console"
269
+ goal "Name a collection's own nav label"
270
+
271
+ reference_to Collection
272
+ attribute :label, SettingsText
273
+
274
+ sets :label
275
+ emits "LabelSet"
276
+ end
277
+
278
+ command "SetKey" do
279
+ role "Console"
280
+ goal "Override a collection's own nav/route key"
281
+
282
+ reference_to Collection
283
+ attribute :key, SettingsText
284
+
285
+ sets :key
286
+ emits "KeySet"
287
+ end
288
+
289
+ command "SetNavOrder" do
290
+ role "Console"
291
+ goal "Place a collection in the nav"
292
+
293
+ reference_to Collection
294
+ attribute :nav_order, SettingsNumber
295
+
296
+ sets :nav_order
297
+ emits "NavOrderSet"
298
+ end
299
+
300
+ command "SetPrimaryField" do
301
+ role "Console"
302
+ goal "Name which field stands in for a whole record"
303
+
304
+ reference_to Collection
305
+ attribute :primary_field, SettingsText
306
+
307
+ sets :primary_field
308
+ emits "PrimaryFieldSet"
309
+ end
310
+
311
+ command "SetListQuery" do
312
+ role "Console"
313
+ goal "Name which of an aggregate's own queries lists its records"
314
+
315
+ reference_to Collection
316
+ attribute :list_query, SettingsText
317
+
318
+ sets :list_query
319
+ emits "ListQuerySet"
320
+ end
321
+
322
+ command "SetIdentity" do
323
+ role "Console"
324
+ goal "Name how a collection assigns its own new records' identity"
325
+
326
+ reference_to Collection
327
+ attribute :identity_field, SettingsText
328
+ attribute :identity_strategy, one_of("slug", "sequence", "port")
329
+
330
+ sets :identity_field
331
+ sets :identity_strategy
332
+ sets :identity_source
333
+ sets :identity_prefix
334
+ sets :identity_extra_json
335
+ emits "IdentitySet"
336
+ end
337
+
338
+ command "SetExtra" do
339
+ role "Console"
340
+ goal "Carry whatever per-collection fields aren't individually modeled yet (noun_sing, create_label, nav_group, ...)"
341
+
342
+ reference_to Collection
343
+ attribute :extra_json, CollectionExtra
344
+
345
+ sets :extra_json
346
+ emits "CollectionExtraSet"
347
+ end
348
+
349
+ command "ReplaceColumns" do
350
+ role "Console"
351
+ goal "Replace a collection's own whole list of table columns"
352
+
353
+ reference_to Collection
354
+
355
+ sets :columns
356
+ emits "ColumnsReplaced"
357
+ end
358
+
359
+ command "ReplaceDetailFields" do
360
+ role "Console"
361
+ goal "Replace a collection's own whole list of detail-panel fields"
362
+
363
+ reference_to Collection
364
+
365
+ sets :detail_fields
366
+ emits "DetailFieldsReplaced"
367
+ end
368
+
369
+ command "ReplaceDetailFieldColumns" do
370
+ role "Console"
371
+ goal "Replace every rows-field's own sub-column filter, whole"
372
+
373
+ reference_to Collection
374
+
375
+ sets :detail_field_columns
376
+ emits "DetailFieldColumnsReplaced"
377
+ end
378
+
379
+ command "ReplacePreconditions" do
380
+ role "Console"
381
+ goal "Replace a collection's own whole list of dispatch preconditions"
382
+
383
+ reference_to Collection
384
+
385
+ sets :preconditions
386
+ emits "PreconditionsReplaced"
387
+ end
388
+
389
+ command "ReplaceFieldFormats" do
390
+ role "Console"
391
+ goal "Replace a collection's own whole list of field display formats"
392
+
393
+ reference_to Collection
394
+
395
+ sets :field_formats
396
+ emits "FieldFormatsReplaced"
397
+ end
398
+ end
399
+
400
+ # THE DASHBOARD'S OWN STAT CARDS — domain-WIDE, not per-aggregate the
401
+ # way Collection is (a stat can name any collection, or none in
402
+ # particular), so this is a SINGLETON: exactly one row, ever, for the
403
+ # whole console. `attribute :key, OverviewKey` holds a literal constant
404
+ # ("overview") rather than anything a person chooses — the same reason
405
+ # a creating command needs SOME identity to hydrate against (hydrate's
406
+ # own "an identity that is invented is neither derived from the record
407
+ # nor permanently associated with it" comment), just with the value
408
+ # fixed instead of derived from what's being declared.
409
+ aggregate "Overview" do
410
+ description "The console's own dashboard stat cards, whole. One row, ever — `key` is always the literal 'overview', never chosen. Every stat gets replaced as a whole list on save, the same 'replace whole, never patch one' convention Collection's own columns/detail_fields/preconditions/field_formats already use."
411
+
412
+ attribute :key, OverviewKey
413
+
414
+ identified_by :key
415
+
416
+ attribute :stats, list_of(Stat)
417
+
418
+ value_object "OverviewKey" do
419
+ attribute :value, String
420
+ invariant("is the one true singleton key") { value == "overview" }
421
+ end
422
+
423
+ # `where_json` carries the stat's own recursive filter expression
424
+ # (`not:` wrapping another whole where clause, `state:`/
425
+ # `has_related:`/`not_has_related:` combined by implicit AND) —
426
+ # serialized, not decomposed into the bluebook's own closed
427
+ # attribute grammar. That tree is genuinely open-ended (arbitrary
428
+ # nesting depth via `not:`, an arbitrary literal attribute name as
429
+ # a where key for anything that isn't `state`), and hecks's
430
+ # attribute types have no way to express "arbitrary nested map" at
431
+ # all — the same reason `sort_default`/`display`/`format` above stay
432
+ # plain Strings rather than a nested `one_of`. PresentationConfig's
433
+ # own `validate_where!`/`validate_has_related!` still walk and check
434
+ # the REAL structure, in Ruby, against the app's own live IR, before
435
+ # this is ever serialized and dispatched — this field is the
436
+ # verified-then-opaque storage, not an unchecked one.
437
+ value_object "Stat" do
438
+ attribute :label, String
439
+ attribute :collection, String
440
+ attribute :as, String, optional: true
441
+ attribute :field, String, optional: true
442
+ attribute :where_json, String, optional: true
443
+ end
444
+
445
+ command "Declare" do
446
+ role "Console"
447
+ goal "Create the one console-wide overview row, before any stat is curated"
448
+
449
+ attribute :key, OverviewKey
450
+
451
+ given("only the one true singleton key is ever declared") { key.value == "overview" }
452
+
453
+ emits "OverviewDeclared"
454
+ end
455
+
456
+ command "ReplaceStats" do
457
+ role "Console"
458
+ goal "Replace the dashboard's whole list of stat cards"
459
+
460
+ reference_to Overview
461
+
462
+ sets :stats
463
+ emits "StatsReplaced"
464
+ end
465
+ end
466
+
467
+ # BOTH ROOTLESS — bulk, no root record, no id argument at dispatch —
468
+ # and grouped by an aggregate's own full identity, which is what makes
469
+ # each leaf exactly one row rather than an arbitrary collision (see
470
+ # `group_by`'s own reference doc). PresentationConfig.rb's own read
471
+ # side (`reshape_states`/`reshape_collections`) dispatches these
472
+ # instead of hand-rolling the unwrap/grouping in Ruby — see its own
473
+ # header for what's still Ruby (the detail_field_columns/detail_fields
474
+ # join, which isn't a report concern at all — two list attributes on
475
+ # the SAME record, not two aggregates — and Overview's own stat cards,
476
+ # which are read straight off Overview.find, a singleton needing
477
+ # neither grouping nor unwrapping either).
478
+ read_model "Styles" do
479
+ description "Every StateStyle row, nested by the aggregate and state it styles."
480
+ include StateStyle
481
+ group_by :agg, :state
482
+ end
483
+
484
+ read_model "Curated" do
485
+ description "Every Collection row, nested by the app aggregate it curates."
486
+ include Collection
487
+ group_by :agg
488
+ end
489
+ end
@@ -0,0 +1,32 @@
1
+ # The framework members, bound so they can boot standing alone —
2
+ # `Hecks.boot("lib/hecks/framework")` rather than only as something
3
+ # another domain attached with `uses_framework`.
4
+ #
5
+ # `uses_framework` does NOT read this file (Framework.load! loads a
6
+ # member's bluebook and nothing else, deliberately — see framework.rb),
7
+ # so an attaching domain still declares its own binding for these
8
+ # aggregates, exactly as before. This only answers the case where the
9
+ # framework is the domain being booted.
10
+ Hecks.hecksagon "Compliance" do
11
+ # Every command here declares `role "Compliance officer"` — only real
12
+ # access control once Governance can check it against something (S8).
13
+ uses_framework "Governance"
14
+ persisted_by "Memory"
15
+ end
16
+
17
+ Hecks.hecksagon "ConsoleSettings" do
18
+ # Same reason as Compliance, above — S8.
19
+ uses_framework "Governance"
20
+ persisted_by "Memory"
21
+ end
22
+
23
+ Hecks.hecksagon "Governance" do
24
+ persisted_by "Memory"
25
+ end
26
+
27
+ Hecks.hecksagon "Identity" do
28
+ # `Identity::Identity.Register` declares `role "Identity registrar"` —
29
+ # same reason as Compliance/ConsoleSettings, above — S8.
30
+ uses_framework "Governance"
31
+ persisted_by "Memory"
32
+ end
@@ -0,0 +1,130 @@
1
+ Hecks.bluebook "Governance" do
2
+ vision "Organizational authority is explicit, reviewable, and historically explainable."
3
+ supporting
4
+
5
+ aggregate "RoleAssignment" do
6
+ description "One actor holding one role, over one scope, from one point in time — revoked by setting when it ended, never deleted."
7
+
8
+ # THE IDENTITY IS THE EVENT, not the (actor, role) pair — an actor can
9
+ # hold the same role again later, after a prior assignment ended, and
10
+ # that is a SECOND real assignment, not a state to overwrite. No UUID
11
+ # adapter exists yet in this codebase to mint a synthetic id, and none
12
+ # is needed: `starts_at` already makes "this actor started holding this
13
+ # role at this time" unique on its own.
14
+ attribute :actor_id, IdentityId
15
+ attribute :role_name, RoleName
16
+ attribute :scope, Scope
17
+ attribute :starts_at, Timestamp
18
+ attribute :ends_at, Timestamp, optional: true
19
+
20
+ identified_by :actor_id, :role_name, :starts_at
21
+
22
+ value_object "IdentityId" do
23
+ attribute :value, String
24
+ invariant("an identity id is present") { !value.to_s.empty? }
25
+ end
26
+
27
+ value_object "RoleName" do
28
+ attribute :value, String
29
+ invariant("a role is named") { !value.to_s.empty? }
30
+ end
31
+
32
+ value_object "Scope" do
33
+ attribute :value, String
34
+ invariant("a scope is named") { !value.to_s.empty? }
35
+ end
36
+
37
+ value_object "Timestamp" do
38
+ attribute :value, String
39
+ invariant("a timestamp is present") { !value.to_s.empty? }
40
+ end
41
+
42
+ command "Assign" do
43
+ role "Governance administrator"
44
+ goal "Authorize an actor to perform a responsibility"
45
+
46
+ attribute :actor_id, IdentityId
47
+ attribute :role_name, RoleName
48
+ attribute :scope, Scope
49
+ attribute :starts_at, Timestamp
50
+
51
+ emits "RoleAssigned"
52
+ end
53
+
54
+ command "Revoke" do
55
+ role "Governance administrator"
56
+ goal "Remove organizational authority"
57
+
58
+ reference_to RoleAssignment
59
+ attribute :ends_at, Timestamp
60
+
61
+ sets :ends_at
62
+ emits "RoleRevoked"
63
+ end
64
+
65
+ query "AssignmentsForActor" do
66
+ description "Every role an actor currently or historically holds."
67
+ attribute :actor_id, IdentityId
68
+ where(actor_id: :actor_id)
69
+ end
70
+ end
71
+
72
+ # WHO HOLDS A ROLE is `RoleAssignment`'s question. This is a different one:
73
+ # may role X ACT AS role Y — the fact `act_as` (the plan's §2) needs before
74
+ # a caller is allowed to dispatch under a role it does not itself hold.
75
+ # Same event-log shape as RoleAssignment : a natural key, `ends_at` for
76
+ # revocation, no delete.
77
+ aggregate "RoleTransition" do
78
+ description "Role X is authorized to act as role Y — until revoked."
79
+
80
+ attribute :from_role, RoleName
81
+ attribute :to_role, RoleName
82
+ attribute :ends_at, Timestamp, optional: true
83
+
84
+ identified_by :from_role, :to_role
85
+
86
+ value_object "RoleName" do
87
+ attribute :value, String
88
+ invariant("a role is named") { !value.to_s.empty? }
89
+ end
90
+
91
+ value_object "Timestamp" do
92
+ attribute :value, String
93
+ invariant("a timestamp is present") { !value.to_s.empty? }
94
+ end
95
+
96
+ command "Grant" do
97
+ role "Governance administrator"
98
+ goal "Authorize one role to act as another"
99
+
100
+ attribute :from_role, RoleName
101
+ attribute :to_role, RoleName
102
+
103
+ emits "RoleTransitionGranted"
104
+ end
105
+
106
+ command "Revoke" do
107
+ role "Governance administrator"
108
+ goal "Remove an authorized role transition"
109
+
110
+ reference_to RoleTransition
111
+ attribute :ends_at, Timestamp
112
+
113
+ sets :ends_at
114
+ emits "RoleTransitionRevoked"
115
+ end
116
+
117
+ # THE RECORD FOR THIS PAIR, granted or revoked — same deferral
118
+ # `AssignmentsForActor` already makes for RoleAssignment: the where
119
+ # clause has no way to ask "and ends_at is absent", so the query
120
+ # answers with the row and the CALLER reads `ends_at` to tell a
121
+ # live grant from a revoked one, exactly as it already must for
122
+ # every assignment.
123
+ query "Allowed" do
124
+ description "The role transition granted for this exact pair, if any — revoked or not."
125
+ attribute :from_role, RoleName
126
+ attribute :to_role, RoleName
127
+ where(from_role: :from_role, to_role: :to_role)
128
+ end
129
+ end
130
+ end