hecks 1.3.0 → 1.5.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 (373) hide show
  1. checksums.yaml +4 -4
  2. data/lib/hecks/adapters/driven/claude_code.rb +72 -7
  3. data/lib/hecks/adapters/driven/d1.rb +187 -23
  4. data/lib/hecks/adapters/driven/folder.rb +83 -10
  5. data/lib/hecks/adapters/driven/google_authentication.rb +33 -12
  6. data/lib/hecks/adapters/driven/governance_authorization.rb +87 -18
  7. data/lib/hecks/adapters/driven/heki/journal.rb +13 -4
  8. data/lib/hecks/adapters/driven/heki/saga_store.rb +56 -10
  9. data/lib/hecks/adapters/driven/heki/snapshot.rb +1 -1
  10. data/lib/hecks/adapters/driven/heki.rb +106 -9
  11. data/lib/hecks/adapters/driven/identity_registry.rb +12 -2
  12. data/lib/hecks/adapters/driven/in_memory_ordering.rb +25 -3
  13. data/lib/hecks/adapters/driven/in_process_key_vault.adapter +3 -0
  14. data/lib/hecks/adapters/driven/in_process_key_vault.rb +53 -0
  15. data/lib/hecks/adapters/driven/lambda/client.rb +67 -14
  16. data/lib/hecks/adapters/driven/lambda.rb +82 -35
  17. data/lib/hecks/adapters/driven/local_storage.rb +83 -10
  18. data/lib/hecks/adapters/driven/memory.rb +205 -9
  19. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +21 -1
  20. data/lib/hecks/adapters/driven/postgres/codec.rb +27 -11
  21. data/lib/hecks/adapters/driven/postgres/outbox.rb +40 -2
  22. data/lib/hecks/adapters/driven/postgres/reconnect.rb +23 -7
  23. data/lib/hecks/adapters/driven/postgres/schema_builder.rb +14 -14
  24. data/lib/hecks/adapters/driven/postgres.rb +175 -28
  25. data/lib/hecks/adapters/driven/prism.rb +50 -11
  26. data/lib/hecks/adapters/driven/secure_random_identity.rb +3 -0
  27. data/lib/hecks/adapters/driven/sql_query_builder.rb +34 -22
  28. data/lib/hecks/adapters/driven/sqlite/codec.rb +38 -10
  29. data/lib/hecks/adapters/driven/sqlite/projection.rb +60 -32
  30. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +12 -12
  31. data/lib/hecks/adapters/driven/sqlite.rb +181 -21
  32. data/lib/hecks/adapters/driven/system_clock.rb +3 -0
  33. data/lib/hecks/adapters/driven/tenant_provisioner.adapter +3 -0
  34. data/lib/hecks/adapters/driven/tenant_provisioner.rb +66 -0
  35. data/lib/hecks/adapters/driven.rb +6 -4
  36. data/lib/hecks/adapters/driving/github_webhook.rb +31 -18
  37. data/lib/hecks/behaviors/dsl.rb +60 -2
  38. data/lib/hecks/behaviors/expectations.rb +190 -29
  39. data/lib/hecks/behaviors/ir.rb +12 -1
  40. data/lib/hecks/behaviors/rspec.rb +9 -1
  41. data/lib/hecks/behaviors/runner.rb +21 -2
  42. data/lib/hecks/behaviors.rb +9 -1
  43. data/lib/hecks/bluebook/aggregate.rb +43 -13
  44. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +17 -10
  45. data/lib/hecks/bluebook/assembly/build.rb +26 -5
  46. data/lib/hecks/bluebook/assembly/contract.rb +98 -23
  47. data/lib/hecks/bluebook/assembly/contracts.rb +59 -52
  48. data/lib/hecks/bluebook/assembly/marks.rb +159 -30
  49. data/lib/hecks/bluebook/assembly/specializer.rb +38 -21
  50. data/lib/hecks/bluebook/assembly.rb +32 -14
  51. data/lib/hecks/bluebook/attribute.rb +26 -12
  52. data/lib/hecks/bluebook/behaviour/aggregate.rb +43 -11
  53. data/lib/hecks/bluebook/behaviour/attribute.rb +18 -5
  54. data/lib/hecks/bluebook/behaviour/chapter.rb +76 -5
  55. data/lib/hecks/bluebook/behaviour/command.rb +55 -25
  56. data/lib/hecks/bluebook/behaviour/domain_port.rb +27 -7
  57. data/lib/hecks/bluebook/behaviour/entity.rb +20 -8
  58. data/lib/hecks/bluebook/behaviour/hexagon.rb +30 -4
  59. data/lib/hecks/bluebook/behaviour/lifecycle.rb +27 -6
  60. data/lib/hecks/bluebook/behaviour/policy.rb +42 -17
  61. data/lib/hecks/bluebook/behaviour/process_manager.rb +39 -8
  62. data/lib/hecks/bluebook/behaviour/query.rb +6 -1
  63. data/lib/hecks/bluebook/behaviour/read_model.rb +29 -8
  64. data/lib/hecks/bluebook/behaviour/traits.rb +48 -12
  65. data/lib/hecks/bluebook/behaviour/value_object.rb +21 -9
  66. data/lib/hecks/bluebook/capabilities.rb +27 -0
  67. data/lib/hecks/bluebook/chapter.rb +51 -9
  68. data/lib/hecks/bluebook/command.rb +62 -17
  69. data/lib/hecks/bluebook/domain_port.rb +34 -9
  70. data/lib/hecks/bluebook/dsl/adapter_builder.rb +24 -0
  71. data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +49 -49
  72. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +282 -123
  73. data/lib/hecks/bluebook/dsl/attribute_collector.rb +112 -75
  74. data/lib/hecks/bluebook/dsl/binding_proxy.rb +81 -2
  75. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +486 -117
  76. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +179 -47
  77. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +116 -0
  78. data/lib/hecks/bluebook/dsl/command_builder.rb +284 -122
  79. data/lib/hecks/bluebook/dsl/const_shim.rb +46 -15
  80. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +90 -25
  81. data/lib/hecks/bluebook/dsl/entity_builder.rb +191 -61
  82. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +148 -132
  83. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +130 -30
  84. data/lib/hecks/bluebook/dsl/identity_declaration.rb +38 -21
  85. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +27 -4
  86. data/lib/hecks/bluebook/dsl/policy_builder.rb +86 -36
  87. data/lib/hecks/bluebook/dsl/port_builder.rb +38 -7
  88. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +56 -22
  89. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +111 -47
  90. data/lib/hecks/bluebook/dsl/query_builder.rb +37 -8
  91. data/lib/hecks/bluebook/dsl/read_model_builder.rb +127 -52
  92. data/lib/hecks/bluebook/dsl/rule_reference.rb +97 -43
  93. data/lib/hecks/bluebook/dsl/translation_builder.rb +150 -44
  94. data/lib/hecks/bluebook/dsl/value_object_builder.rb +68 -20
  95. data/lib/hecks/bluebook/dsl/word_gate.rb +59 -53
  96. data/lib/hecks/bluebook/dsl/world_builder.rb +51 -8
  97. data/lib/hecks/bluebook/entity.rb +40 -11
  98. data/lib/hecks/bluebook/expression/ast_json.rb +128 -36
  99. data/lib/hecks/bluebook/expression/ast_reader.rb +32 -3
  100. data/lib/hecks/bluebook/expression/canonical_form.rb +55 -16
  101. data/lib/hecks/bluebook/expression/evaluator.rb +221 -43
  102. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +54 -18
  103. data/lib/hecks/bluebook/expression/resolver.rb +369 -128
  104. data/lib/hecks/bluebook/hexagon.rb +35 -1
  105. data/lib/hecks/bluebook/lifecycle.rb +12 -1
  106. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +2 -1
  107. data/lib/hecks/bluebook/meta_validator/judge.rb +126 -108
  108. data/lib/hecks/bluebook/meta_validator/plan.rb +81 -46
  109. data/lib/hecks/bluebook/meta_validator/port_judge.rb +3 -2
  110. data/lib/hecks/bluebook/meta_validator/readings.rb +200 -50
  111. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +68 -41
  112. data/lib/hecks/bluebook/meta_validator/shapes.rb +166 -21
  113. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +286 -46
  114. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +11 -10
  115. data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -5
  116. data/lib/hecks/bluebook/meta_validator.rb +235 -139
  117. data/lib/hecks/bluebook/model_check.rb +434 -104
  118. data/lib/hecks/bluebook/pattern_subset.rb +32 -10
  119. data/lib/hecks/bluebook/policy.rb +15 -13
  120. data/lib/hecks/bluebook/process_manager.rb +27 -14
  121. data/lib/hecks/bluebook/project_discovery.rb +5 -0
  122. data/lib/hecks/bluebook/project_loader.rb +40 -0
  123. data/lib/hecks/bluebook/project_register.rb +50 -6
  124. data/lib/hecks/bluebook/query.rb +31 -4
  125. data/lib/hecks/bluebook/read_model.rb +35 -15
  126. data/lib/hecks/bluebook/reference.rb +26 -13
  127. data/lib/hecks/bluebook/smoke_test.rb +46 -23
  128. data/lib/hecks/bluebook/synthesizer.rb +46 -12
  129. data/lib/hecks/bluebook/translation.rb +34 -5
  130. data/lib/hecks/bluebook/value_object.rb +29 -11
  131. data/lib/hecks/bluebook.rb +5 -6
  132. data/lib/hecks/codemod.rb +138 -50
  133. data/lib/hecks/construct.rb +21 -7
  134. data/lib/hecks/corpus.rb +438 -0
  135. data/lib/hecks/deploy/bluebook/deploy.hecksagon +19 -0
  136. data/lib/hecks/doc/reference.rb +200 -31
  137. data/lib/hecks/embryonaut_bluebook.rb +38 -15
  138. data/lib/hecks/facade/cli_door.rb +69 -10
  139. data/lib/hecks/facade/cli_runner.rb +105 -24
  140. data/lib/hecks/facade/command_request.rb +23 -0
  141. data/lib/hecks/facade/handle.rb +155 -35
  142. data/lib/hecks/facade/json_door.rb +106 -25
  143. data/lib/hecks/facade/surface/aggregate_door.rb +50 -27
  144. data/lib/hecks/facade/surface/chapter.rb +26 -17
  145. data/lib/hecks/facade/surface.rb +16 -3
  146. data/lib/hecks/facade.rb +15 -4
  147. data/lib/hecks/forms/app.rb +46 -30
  148. data/lib/hecks/forms/command_form_renderer.rb +70 -9
  149. data/lib/hecks/forms/field_renderer.rb +142 -6
  150. data/lib/hecks/forms/field_shape.rb +183 -19
  151. data/lib/hecks/forms/html.rb +51 -7
  152. data/lib/hecks/forms/index_renderer.rb +14 -2
  153. data/lib/hecks/forms/page.rb +14 -0
  154. data/lib/hecks/forms/params.rb +120 -23
  155. data/lib/hecks/forms/port_argument.rb +14 -2
  156. data/lib/hecks/forms/query_form_renderer.rb +65 -2
  157. data/lib/hecks/forms/record_renderer.rb +60 -2
  158. data/lib/hecks/forms/record_table.rb +28 -1
  159. data/lib/hecks/forms/reference_options.rb +24 -0
  160. data/lib/hecks/forms/value_object_shape.rb +13 -3
  161. data/lib/hecks/forms.rb +24 -4
  162. data/lib/hecks/fqn.rb +59 -1
  163. data/lib/hecks/framework/bluebook/governance.bluebook +9 -0
  164. data/lib/hecks/framework/bluebook/privacy.bluebook +155 -0
  165. data/lib/hecks/framework/oidc.json +15 -0
  166. data/lib/hecks/framework.rb +79 -25
  167. data/lib/hecks/freezer.rb +27 -11
  168. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +241 -106
  169. data/lib/hecks/fuzzing/combination_miner.rb +178 -0
  170. data/lib/hecks/fuzzing/concurrent_dispatch.rb +241 -45
  171. data/lib/hecks/fuzzing/coverage_campaign.rb +161 -0
  172. data/lib/hecks/fuzzing/differential.rb +192 -0
  173. data/lib/hecks/fuzzing/domain_generator.rb +871 -0
  174. data/lib/hecks/fuzzing/era_boundary.rb +68 -19
  175. data/lib/hecks/fuzzing/form_census.rb +121 -20
  176. data/lib/hecks/fuzzing/generated_domain_check.rb +171 -0
  177. data/lib/hecks/fuzzing/invalid_value_generator.rb +45 -6
  178. data/lib/hecks/fuzzing/isolated_boot.rb +137 -80
  179. data/lib/hecks/fuzzing/nondeterministic.rb +79 -0
  180. data/lib/hecks/fuzzing/persistence_parity.rb +111 -21
  181. data/lib/hecks/fuzzing/properties/corrections.rb +34 -9
  182. data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +300 -51
  183. data/lib/hecks/fuzzing/properties/guards.rb +86 -42
  184. data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +80 -32
  185. data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +40 -35
  186. data/lib/hecks/fuzzing/properties/outbox.rb +70 -32
  187. data/lib/hecks/fuzzing/properties/querying.rb +82 -28
  188. data/lib/hecks/fuzzing/properties.rb +84 -51
  189. data/lib/hecks/fuzzing/qa_settings.rb +164 -0
  190. data/lib/hecks/fuzzing/replay.rb +241 -133
  191. data/lib/hecks/fuzzing/rotation_priority.rb +48 -28
  192. data/lib/hecks/fuzzing/rust_gap_manifest.rb +139 -0
  193. data/lib/hecks/fuzzing/self_consistency.rb +315 -137
  194. data/lib/hecks/fuzzing/sequence_generator/adversary.rb +46 -40
  195. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +18 -11
  196. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +13 -12
  197. data/lib/hecks/fuzzing/sequence_generator/picker.rb +21 -12
  198. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +59 -32
  199. data/lib/hecks/fuzzing/sequence_generator.rb +158 -23
  200. data/lib/hecks/fuzzing/shrinker.rb +309 -0
  201. data/lib/hecks/fuzzing/structural_skips.rb +37 -130
  202. data/lib/hecks/fuzzing/sweep_depth.rb +12 -4
  203. data/lib/hecks/fuzzing/target_capabilities.rb +107 -29
  204. data/lib/hecks/fuzzing/value_generator.rb +110 -22
  205. data/lib/hecks/fuzzing.rb +5 -0
  206. data/lib/hecks/grammar/evolve.rb +188 -12
  207. data/lib/hecks/grammar.rb +53 -7
  208. data/lib/hecks/ir.rb +51 -20
  209. data/lib/hecks/language/bluebook/bluebook.bluebook +41 -0
  210. data/lib/hecks/language/bluebook/policy.bluebook +11 -1
  211. data/lib/hecks/language/bluebook/vocabulary.bluebook +348 -13
  212. data/lib/hecks/language/hecksagon/hecksagon.bluebook +11 -0
  213. data/lib/hecks/language/oidc.json +5 -0
  214. data/lib/hecks/literal.rb +41 -9
  215. data/lib/hecks/naming.rb +112 -31
  216. data/lib/hecks/ports/access_control.rb +53 -2
  217. data/lib/hecks/ports/agent/answers.rb +83 -6
  218. data/lib/hecks/ports/agent.rb +119 -35
  219. data/lib/hecks/ports/authentication.rb +44 -4
  220. data/lib/hecks/ports/authorization.rb +50 -11
  221. data/lib/hecks/ports/clock.rb +42 -23
  222. data/lib/hecks/ports/extraction.rb +16 -0
  223. data/lib/hecks/ports/identity_assignment.rb +23 -2
  224. data/lib/hecks/ports/identity_generation.rb +17 -3
  225. data/lib/hecks/ports/identity_resolution.rb +17 -1
  226. data/lib/hecks/ports/key_vault.port +6 -0
  227. data/lib/hecks/ports/key_vault.rb +58 -0
  228. data/lib/hecks/ports/loading.rb +4 -0
  229. data/lib/hecks/ports/persistence/append_only.rb +172 -8
  230. data/lib/hecks/ports/persistence/binding_policy.rb +34 -0
  231. data/lib/hecks/ports/persistence/codec_boundary.rb +178 -0
  232. data/lib/hecks/ports/persistence/execution.rb +4 -0
  233. data/lib/hecks/ports/persistence/null_saga_store.rb +12 -1
  234. data/lib/hecks/ports/persistence/plugin.rb +42 -4
  235. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +218 -25
  236. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +77 -9
  237. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +81 -24
  238. data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +29 -18
  239. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +144 -60
  240. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +103 -8
  241. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +98 -23
  242. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +282 -109
  243. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +63 -25
  244. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +118 -66
  245. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +51 -28
  246. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +34 -5
  247. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +25 -12
  248. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +129 -34
  249. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +51 -6
  250. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +33 -9
  251. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +16 -0
  252. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +95 -6
  253. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +25 -2
  254. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +314 -90
  255. data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +68 -10
  256. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +9 -3
  257. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +9 -2
  258. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +48 -8
  259. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +16 -1
  260. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +36 -5
  261. data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +23 -3
  262. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +58 -19
  263. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +96 -5
  264. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +15 -0
  265. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +9 -1
  266. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -2
  267. data/lib/hecks/ports/persistence/plugins/era.rb +12 -2
  268. data/lib/hecks/ports/persistence/remote_runtime.rb +9 -2
  269. data/lib/hecks/ports/persistence/repository_factory.rb +23 -3
  270. data/lib/hecks/ports/persistence/state_codec.rb +319 -0
  271. data/lib/hecks/ports/persistence.rb +36 -1
  272. data/lib/hecks/ports/projection.rb +61 -7
  273. data/lib/hecks/ports/query/in_memory.rb +41 -8
  274. data/lib/hecks/ports/query/ordering.rb +21 -6
  275. data/lib/hecks/ports/query.rb +35 -0
  276. data/lib/hecks/ports.rb +1 -0
  277. data/lib/hecks/projections/bootstrap_table.rb +147 -0
  278. data/lib/hecks/projections/diagrams.rb +315 -79
  279. data/lib/hecks/projections/glossary/html.rb +91 -3
  280. data/lib/hecks/projections/glossary/markdown.rb +50 -3
  281. data/lib/hecks/projections/glossary/mermaid.rb +49 -1
  282. data/lib/hecks/projections/glossary/sections.rb +1 -1
  283. data/lib/hecks/projections/glossary/sentences.rb +110 -5
  284. data/lib/hecks/projections/glossary.rb +173 -31
  285. data/lib/hecks/projections/ir.rb +1 -1
  286. data/lib/hecks/projections/model/deviations.rb +62 -17
  287. data/lib/hecks/projections/model.rb +75 -21
  288. data/lib/hecks/projections/oidc.rb +45 -8
  289. data/lib/hecks/projections/parser_table.rb +53 -12
  290. data/lib/hecks/projections/reference.rb +15 -3
  291. data/lib/hecks/projections/rust_vocabulary.rb +646 -0
  292. data/lib/hecks/projections/shape.rb +10 -2
  293. data/lib/hecks/projections/statements.rb +69 -22
  294. data/lib/hecks/projections/vocabulary.rb +26 -9
  295. data/lib/hecks/projections.rb +5 -3
  296. data/lib/hecks/projector/cli_projector.rb +245 -37
  297. data/lib/hecks/projector/docs_projector.rb +154 -28
  298. data/lib/hecks/projector/exporter.rb +104 -29
  299. data/lib/hecks/projector/ir_projector.rb +7 -1
  300. data/lib/hecks/projector/narrate_projector.rb +144 -23
  301. data/lib/hecks/projector/target.rb +42 -18
  302. data/lib/hecks/projector.rb +86 -18
  303. data/lib/hecks/query_ir.rb +94 -47
  304. data/lib/hecks/query_specification/common/comparators.rb +19 -3
  305. data/lib/hecks/query_specification/common/comparison.rb +109 -27
  306. data/lib/hecks/query_specification/common/dsl.rb +65 -9
  307. data/lib/hecks/query_specification/common/null_policy.rb +61 -15
  308. data/lib/hecks/query_specification/common/null_semantics.rb +4 -0
  309. data/lib/hecks/query_specification/common/options.rb +25 -0
  310. data/lib/hecks/query_specification/field_path.rb +69 -15
  311. data/lib/hecks/query_specification/hop_path.rb +57 -20
  312. data/lib/hecks/query_specification/read_model/specification.rb +4 -0
  313. data/lib/hecks/rendering.rb +9 -3
  314. data/lib/hecks/router/namespace_installer.rb +16 -3
  315. data/lib/hecks/router.rb +56 -1
  316. data/lib/hecks/runtime/aggregate_lock.rb +20 -11
  317. data/lib/hecks/runtime/boot_gates.rb +21 -3
  318. data/lib/hecks/runtime/caller.rb +40 -8
  319. data/lib/hecks/runtime/capability_graph.rb +13 -2
  320. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +40 -41
  321. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +45 -67
  322. data/lib/hecks/runtime/command_interpreter.rb +195 -113
  323. data/lib/hecks/runtime/command_rules/admissibility.rb +231 -80
  324. data/lib/hecks/runtime/command_rules/arithmetic.rb +154 -96
  325. data/lib/hecks/runtime/command_rules/authorization.rb +38 -17
  326. data/lib/hecks/runtime/command_rules/emission.rb +18 -1
  327. data/lib/hecks/runtime/command_rules/references.rb +145 -55
  328. data/lib/hecks/runtime/command_rules.rb +3 -0
  329. data/lib/hecks/runtime/dependency_planning.rb +56 -11
  330. data/lib/hecks/runtime/dispatcher.rb +263 -92
  331. data/lib/hecks/runtime/entity_element.rb +304 -67
  332. data/lib/hecks/runtime/entity_interpreter.rb +149 -88
  333. data/lib/hecks/runtime/errors.rb +37 -23
  334. data/lib/hecks/runtime/event.rb +15 -10
  335. data/lib/hecks/runtime/identity.rb +91 -23
  336. data/lib/hecks/runtime/instance.rb +103 -18
  337. data/lib/hecks/runtime/interpreting.rb +24 -16
  338. data/lib/hecks/runtime/invocation.rb +358 -0
  339. data/lib/hecks/runtime/loader.rb +105 -19
  340. data/lib/hecks/runtime/outbox.rb +164 -26
  341. data/lib/hecks/runtime/policy_interpreter.rb +73 -60
  342. data/lib/hecks/runtime/port_operation_interpreter.rb +42 -19
  343. data/lib/hecks/runtime/query_interpreter.rb +93 -74
  344. data/lib/hecks/runtime/reaction_invocation.rb +73 -28
  345. data/lib/hecks/runtime/read_model_interpreter.rb +60 -44
  346. data/lib/hecks/runtime/rebuild_sweep.rb +32 -4
  347. data/lib/hecks/runtime/reference_hop.rb +48 -6
  348. data/lib/hecks/runtime/refusal_wording.rb +142 -115
  349. data/lib/hecks/runtime/registry/saga_persistence.rb +32 -21
  350. data/lib/hecks/runtime/registry/verification.rb +153 -28
  351. data/lib/hecks/runtime/registry.rb +202 -32
  352. data/lib/hecks/runtime/remote_dispatcher.rb +125 -24
  353. data/lib/hecks/runtime/routing.rb +36 -154
  354. data/lib/hecks/runtime/saga_interpreter/correlation.rb +25 -27
  355. data/lib/hecks/runtime/saga_interpreter.rb +90 -76
  356. data/lib/hecks/runtime/saga_pending_dispatch.rb +12 -12
  357. data/lib/hecks/runtime/tenant_check.rb +33 -13
  358. data/lib/hecks/runtime/tenant_scope.rb +23 -5
  359. data/lib/hecks/runtime/value/admission.rb +75 -30
  360. data/lib/hecks/runtime/value/coercion.rb +555 -142
  361. data/lib/hecks/runtime/value/entity_list_coercion.rb +132 -60
  362. data/lib/hecks/runtime/value.rb +71 -21
  363. data/lib/hecks/runtime.rb +39 -7
  364. data/lib/hecks/storehouse.rb +368 -72
  365. data/lib/hecks/tenancy/bluebook/tenancy.bluebook +130 -0
  366. data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +32 -0
  367. data/lib/hecks/version.rb +3 -3
  368. data/lib/hecks/vocabulary.rb +205 -4
  369. data/lib/hecks.rb +91 -11
  370. data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +19 -11
  371. data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +24 -12
  372. data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +38 -14
  373. metadata +28 -2
@@ -14,6 +14,14 @@ module Hecks
14
14
  module Shapes
15
15
  # The type came in as the id of what it names, so it goes back out as the
16
16
  # name — or, for another aggregate's head, as the encoding the IR spells.
17
+ #
18
+ # @param field [Hash{Symbol => Object}] one dispatched attribute row
19
+ # @param aggregate_id [String] the owning aggregate's own id, to
20
+ # strip from an owned value-object type
21
+ # @return [Hash{Symbol => Object}] `:name` (`Symbol`, `nil`),
22
+ # `:type` (`String`), `:list`/`:optional` (`Boolean`), `:default`
23
+ # (decoded literal, `nil` when absent), `:pattern`/`:admits`/
24
+ # `:relationship` (`String`, `nil` when absent)
17
25
  def attribute(field, aggregate_id)
18
26
  type = text(field[:type]).to_s
19
27
 
@@ -27,8 +35,8 @@ module Hecks
27
35
  # bluebook that no longer says what it said.
28
36
  optional: text(field[:optional]).to_s == "true",
29
37
  pattern: presence(text(field[:pattern])),
30
- # THE ROUND TRIP IS THE ONLY WAY IN. The grammar registry keeps the
31
- # ASSEMBLED graph — the language as its own judge read it back — so a
38
+ # The round trip is the only way in. The grammar registry keeps the
39
+ # assembled graph — the language as its own judge read it back — so a
32
40
  # fact dropped here is a fact no downstream projection ever sees, no
33
41
  # matter how plainly the .bluebook file declares it.
34
42
  admits: presence(text(field[:admits])),
@@ -36,9 +44,15 @@ module Hecks
36
44
  }
37
45
  end
38
46
 
39
- # A TYPE THIS AGGREGATE OWNS, offered as its id and read back as its name.
40
- # Prefixed with the owner and the identity join, because that IS the value
47
+ # A type this aggregate owns, offered as its id and read back as its name.
48
+ # Prefixed with the owner and the identity join, because that is the value
41
49
  # object's identity — the aggregate it belongs to, then its name.
50
+ #
51
+ # @param type [String] the attribute's own dispatched `type` cell
52
+ # @param aggregate_id [String] the owning aggregate's own id
53
+ # @return [String, nil] `type` with the owner's own identity prefix
54
+ # stripped, or `nil` if `type` does not carry that prefix (an
55
+ # ordinary type name, or a cross-aggregate reference)
42
56
  def owned_type(type, aggregate_id)
43
57
  prefix = Naming.identity([aggregate_id, ""])
44
58
  return nil unless type.start_with?(prefix)
@@ -46,15 +60,18 @@ module Hecks
46
60
  type.delete_prefix(prefix)
47
61
  end
48
62
 
49
- # ONE PART OF AN IDENTITY, read back as the path it went in as. The inverse
63
+ # One part of an identity, read back as the path it went in as. The inverse
50
64
  # of `Marks#identity_path`, and named the same so the two directions read
51
65
  # as one table.
66
+ #
67
+ # @param part [Hash{Symbol => Object}] one dispatched identity-part row
68
+ # @return [String] the identity part's own path text
52
69
  def identity_path(part) = text(part[:value]).to_s
53
70
 
54
71
  # An argument, a parameter, a piece's attribute — the three places an
55
72
  # attribute is written that carry no owner id to strip... except a
56
73
  # piece's own attribute now does : an entity is its own root (repeating
57
- # the aggregate's whole shape one level down), so ITS attributes name a
74
+ # the aggregate's whole shape one level down), so its attributes name a
58
75
  # value object exactly the way an aggregate's own do (`Judge#cell`'s own
59
76
  # comment), and reconstruction has to undo the same owned-vs-reference
60
77
  # split `attribute`, below, already undoes for an aggregate — not the
@@ -66,16 +83,25 @@ module Hecks
66
83
  # argument or a parameter carries no value-object type at all — see
67
84
  # entity.bluebook's/command.bluebook's own comments on why — so the
68
85
  # generic reader path calls this with one argument and gets the
69
- # OLD reading unchanged), is the piece's OWNING aggregate — the same
86
+ # old reading unchanged), is the piece's owning aggregate — the same
70
87
  # one its own attribute types were resolved against on the way in
71
88
  # (`Judge#owning_aggregate_ref`).
72
89
  #
73
- # A REFERENCE among the other two came in as the head's ID, because
90
+ # A reference among the other two came in as the head's ID, because
74
91
  # that is what Command/Query.Reference offer, so it goes back out as
75
92
  # the encoding the IR spells. A qualified name is the tell : an
76
93
  # ordinary type names something declared beside it (`Money`,
77
94
  # `AccountNumber`) and never carries a chapter, while a head's id
78
95
  # always does.
96
+ #
97
+ # @param field [Hash{Symbol => Object}] one dispatched attribute,
98
+ # argument, or parameter row
99
+ # @param aggregate_id [String, nil] the piece's own owning
100
+ # aggregate id, passed only for a piece's own attribute
101
+ # @return [Hash{Symbol => Object}] `:name` (`Symbol`, `nil`),
102
+ # `:type` (`String`), `:list`/`:optional` (`Boolean`), `:default`
103
+ # (decoded literal, `nil` when absent), `:pattern`/`:admits`/
104
+ # `:relationship` (`String`, `nil` when absent)
79
105
  def shape_field(field, aggregate_id = nil)
80
106
  return attribute(field, aggregate_id) if aggregate_id
81
107
 
@@ -83,7 +109,7 @@ module Hecks
83
109
 
84
110
  {
85
111
  name: text(field[:name])&.to_sym,
86
- # A QUALIFIED name is the tell : an ordinary type names something
112
+ # A qualified name is the tell : an ordinary type names something
87
113
  # declared beside it (`Money`, `AccountNumber`) and carries no join at
88
114
  # all, where a head's id always does (chapter + name, joined the way
89
115
  # every derived id is).
@@ -97,11 +123,16 @@ module Hecks
97
123
  }
98
124
  end
99
125
 
100
- # An ABSENT pattern is nil, not "". The language holds every field as
126
+ # An absent pattern is nil, not "". The language holds every field as
101
127
  # text, so a field nobody set comes back as the empty string — and ""
102
128
  # is a real regex (it matches everything), so keeping it would turn
103
129
  # "no pattern" into "a pattern that always passes" and quietly cost the
104
130
  # IR its round trip.
131
+ #
132
+ # @param text [String, nil] a dispatched cell's own already-unwrapped
133
+ # text
134
+ # @return [String, nil] `text`, or `nil` when `text` is `nil` or
135
+ # empty
105
136
  def presence(text)
106
137
  value = text.to_s
107
138
  value.empty? ? nil : value
@@ -113,13 +144,29 @@ module Hecks
113
144
  # String, Integer, Float, TrueClass, FalseClass — plus a symbol, and an
114
145
  # object literal, which is what `to: { value: "good" }` is: a value object's
115
146
  # fields written inline.
147
+ #
148
+ # @param text [String, nil] the self-describing wire spelling
149
+ # `Readings#encode_literal` wrote
150
+ # @return [Object] `nil`, `true`, `false`, `Integer`, `Float`,
151
+ # `Symbol`, `Hecks::StateRef`, `String`, `Hash`, or `Array` — or
152
+ # `text` itself, stripped, when it matches no known spelling
116
153
  def decode_literal(text) = Literal.read(text)
117
154
 
155
+ # Reads a rule's plain description/canonical pair, for a
156
+ # `given`/`invariant`/`ensures`.
157
+ #
158
+ # @param row [Hash{Symbol => Object}] one dispatched rule row
159
+ # @return [Hash{Symbol => String}] `:description` and `:canonical`
118
160
  def rule(row) = { description: text(row[:description]), canonical: text(row[:canonical]) }
119
161
 
120
162
  # S12, ADR 0025 — `projects :name, from: :"reference.remote_field"`,
121
163
  # read back the same three plain identifiers `rule` above reads
122
164
  # description/canonical as.
165
+ #
166
+ # @param row [Hash{Symbol => Object}] one dispatched projected-field
167
+ # row
168
+ # @return [Hash{Symbol => String}] `:name`, `:reference`, and
169
+ # `:remote_field`
123
170
  def projected_field(row)
124
171
  { name: text(row[:name]), reference: text(row[:reference]), remote_field: text(row[:remote_field]) }
125
172
  end
@@ -128,26 +175,57 @@ module Hecks
128
175
  # does — an object literal, self-describing via Hecks::Literal — one
129
176
  # level up: a whole keyword's argument rather than an attribute's
130
177
  # `default:`.
178
+ #
179
+ # @param row [Hash{Symbol => Object}] a dispatched row carrying a
180
+ # `:provenance` cell
181
+ # @return [Object] the decoded `from:` object literal, or `nil` when
182
+ # absent
131
183
  def provenance(row) = decode_literal(text(row[:provenance]))
132
184
 
133
- # `command "Debit", from: "open"` — the SAME literal encoding
185
+ # `command "Debit", from: "open"` — the same literal encoding
134
186
  # `provenance`/`default:` already ride (S10, ADR 0025), one
135
187
  # state or an array of them, or nil for a command with no
136
188
  # lifecycle guard.
189
+ #
190
+ # @param row [Hash{Symbol => Object}] a dispatched row carrying a
191
+ # `:from` cell
192
+ # @return [String, Array<String>, nil] the decoded lifecycle guard
193
+ # state(s), or `nil` for a command with no lifecycle guard
137
194
  def from(row) = decode_literal(text(row[:from]))
138
195
 
139
- # THE OPTION ROWS, GATHERED BACK into the shapes `extra_options_to_h` spells.
196
+ # A flag is held as text ("true"/"false") and emitted as a boolean —
197
+ # `Policy#expect_undelivered` on the wire.
198
+ #
199
+ # @param row [Hash{Symbol => Object}] a dispatched row carrying an
200
+ # `:expect_undelivered` cell
201
+ # @return [Boolean] whether the flag reads `"true"`
202
+ def expect_undelivered?(row) = text(row[:expect_undelivered]).to_s == "true"
203
+
204
+ # The option rows, gathered back into the shapes `extra_options_to_h` spells.
140
205
  #
141
206
  # One row per part, so a compound option is several rows and a repeated one is
142
207
  # several groups told apart by `at`. Grouping by option name and then by `at`
143
208
  # rebuilds both without either knowing which options exist — the whole point
144
209
  # of holding them as an open map.
210
+ #
211
+ # @param row [Hash{Symbol => Object}] a dispatched row carrying an
212
+ # `:options` list
213
+ # @return [Hash{Symbol => Object}] one entry per option name; each
214
+ # value is `gathered`'s own return for that option's own parts
145
215
  def options_of(row)
146
216
  Array(row[:options])
147
217
  .group_by { |part| text(part[:option]) }
148
218
  .to_h { |option, parts| [option.to_sym, gathered(parts)] }
149
219
  end
150
220
 
221
+ # Groups one option's own dispatched parts back into a single
222
+ # binding, or several `at`-keyed groups for a repeated option.
223
+ #
224
+ # @param parts [Array<Hash{Symbol => Object}>] one option's own
225
+ # dispatched key/value/at rows
226
+ # @return [Hash{Symbol => String}, Array<Hash{Symbol => String}>]
227
+ # a single `key => value` hash when no part carries `at`;
228
+ # otherwise an array of such hashes, one per distinct `at`
151
229
  def gathered(parts)
152
230
  repeated, single = parts.partition { |part| !text(part[:at]).to_s.empty? }
153
231
  return single.to_h { |part| [text(part[:key]).to_sym, text(part[:value])] } if repeated.empty?
@@ -157,8 +235,8 @@ module Hecks
157
235
  .map { |group| group.to_h { |part| [text(part[:key]).to_sym, text(part[:value])] } }
158
236
  end
159
237
 
160
- # The IR keeps a where's field as a STRING, not a symbol — it is read back
161
- # out, never called. The value stays RAW TEXT here on purpose : this
238
+ # The IR keeps a where's field as a string, not a symbol — it is read back
239
+ # out, never called. The value stays raw text here on purpose : this
162
240
  # feeds the declaration hash Assembly::Marks#where_clause decodes
163
241
  # from (via `read`), and decoding twice is worse than once — a
164
242
  # kwarg reference (":ceiling") decoded here into the Symbol :ceiling
@@ -166,11 +244,20 @@ module Hecks
166
244
  # back out as the plain string "ceiling", indistinguishable from a
167
245
  # literal of the same name. One decode, at the one place that builds
168
246
  # the object every comparator actually reads.
247
+ #
248
+ # @param row [Hash{Symbol => Object}] one dispatched where-clause row
249
+ # @return [Hash{Symbol => String}] `:field`, `:op`, and `:value`
250
+ # (raw text, undecoded)
169
251
  def where_clause(row)
170
252
  { field: text(row[:field]), op: text(row[:op]), value: text(row[:value]) }
171
253
  end
172
254
 
173
255
  # One object in the IR, two fields in the language.
256
+ #
257
+ # @param row [Hash{Symbol => Object}] a dispatched row carrying
258
+ # `:order_field`/`:order_way` cells
259
+ # @return [Hash{Symbol => String}, nil] `:field` and `:direction`,
260
+ # or `nil` when no `order_field` was declared
174
261
  def order_by(row)
175
262
  field = text(row[:order_field])
176
263
  return nil if field.to_s.empty?
@@ -178,6 +265,12 @@ module Hecks
178
265
  { field: field, direction: text(row[:order_way]) }
179
266
  end
180
267
 
268
+ # Reads a read model's own declared row limit.
269
+ #
270
+ # @param row [Hash{Symbol => Object}] a dispatched row carrying a
271
+ # `:limit` cell
272
+ # @return [Hash{Symbol => String}, nil] `{value: ceiling}`, or `nil`
273
+ # when no limit was declared
181
274
  def limit(row)
182
275
  ceiling = text(row[:limit])
183
276
  return nil if ceiling.to_s.empty?
@@ -185,6 +278,12 @@ module Hecks
185
278
  { value: ceiling }
186
279
  end
187
280
 
281
+ # Reads one lifecycle transition row.
282
+ #
283
+ # @param row [Hash{Symbol => Object}] one dispatched lifecycle
284
+ # transition row
285
+ # @return [Hash{Symbol => String}] `:command`, `:from_state`, and
286
+ # `:to_state`
188
287
  def transition(row)
189
288
  {
190
289
  command: text(row[:command]),
@@ -193,6 +292,13 @@ module Hecks
193
292
  }
194
293
  end
195
294
 
295
+ # Reads one reference head — a process manager handler's own
296
+ # aggregate binding.
297
+ #
298
+ # @param row [Hash{Symbol => Object}] one dispatched reference-head
299
+ # row
300
+ # @return [Hash{Symbol => Object}] `:aggregate`/`:as` (`String`) and
301
+ # `:many` (`Boolean`)
196
302
  def head(row)
197
303
  {
198
304
  aggregate: text(row[:aggregate]),
@@ -203,33 +309,48 @@ module Hecks
203
309
  }
204
310
  end
205
311
 
312
+ # Reads a read model's own `group_by` field name.
313
+ #
314
+ # @param row [Hash{Symbol => Object}] a dispatched row carrying a
315
+ # `:field` cell
316
+ # @return [Hash{Symbol => String}] `{field: ...}`
206
317
  def group_by_field(row) = { field: text(row[:field]) }
207
318
 
208
- # `count`'s own boolean, read back the SAME way `head`'s own
319
+ # `count`'s own boolean, read back the same way `head`'s own
209
320
  # `many` is (`text(row[:many]).to_s == "true"`) — except a
210
- # `ReadModel.Count` command is dispatched AT ALL only when
321
+ # `ReadModel.Count` command is dispatched at all only when
211
322
  # `@count` was truthy (`MetaValidator::Judge#setters` skips a
212
323
  # setter whose every source is absent), so an undeclared read
213
324
  # model's own `count` field never gets written and comes back
214
325
  # `nil` here, never `"false"` — matching `ReadModel#to_h`'s own
215
326
  # `true`/`nil` pair (never `false`) exactly, rather than the
216
327
  # unconditional `true`/`false` `head`'s own `many` needs (every
217
- # head DOES get a `Gather` dispatch, declared or derived).
328
+ # head does get a `Gather` dispatch, declared or derived).
329
+ #
330
+ # @param row [Hash{Symbol => Object}] a dispatched row carrying a
331
+ # `:count` cell
332
+ # @return [Boolean, nil] `true` when the flag reads `"true"`, `nil`
333
+ # for an undeclared read model's own `count`
218
334
  def read_model_count(row) = (true if text(row[:count]).to_s == "true")
219
335
 
220
- # THE APPEND FLATTENING, IN REVERSE.
336
+ # The append flattening, in reverse.
221
337
  #
222
338
  # An append binds several fields at once and the language's Change holds one
223
- # field/kind/source triple, so the walk offers an append once PER BINDING.
339
+ # field/kind/source triple, so the walk offers an append once per binding.
224
340
  # Rebuilding groups those rows back into the single mutation the IR keeps —
225
341
  # the only place here that undoes something rather than simply reading it.
342
+ #
343
+ # @param row [Hash{Symbol => Object}] a dispatched row carrying a
344
+ # `:mutations` list
345
+ # @return [Array<Hash{Symbol => Object}>] one hash per distinct
346
+ # `target`/`op` pair, each `mutation`'s own return
226
347
  def mutations(row)
227
348
  Array(row[:mutations])
228
349
  .group_by { |change| [text(change[:target]), text(change[:op])] }
229
350
  .map { |(target, op), bindings| mutation(target, op, bindings) }
230
351
  end
231
352
 
232
- # `sign:` — read the SAME way the declared side computes it
353
+ # `sign:` — read the same way the declared side computes it
233
354
  # (`Bluebook::Mutation.sign_for`, item #5 of the whole-project
234
355
  # table-unification survey), not stored on any row here — the
235
356
  # meta-domain's own Change entity carries no `sign` field of its
@@ -238,20 +359,44 @@ module Hecks
238
359
  # Mutation's own `to_h` lambda does, rather than leaving the key
239
360
  # silently absent (spec/round_trip_spec's whole point: a field the
240
361
  # language does not hold is a named gap, not a byte-for-byte one).
362
+ #
363
+ # @param target [String] the mutated field's own name
364
+ # @param oper [String] the mutation's operation name, such as
365
+ # `"set"`, `"append"`, `"delegate"`, or `"corrects"`
366
+ # @param bindings [Array<Hash{Symbol => Object}>] this target/op
367
+ # pair's own dispatched binding rows
368
+ # @return [Hash{Symbol => Object}] `:target`/`:op` (`Symbol`),
369
+ # `:sign` (`String`), plus `:fields` (`appended`'s own return) for
370
+ # `"append"`/`"delegate"`/`"corrects"`, or `:source`
371
+ # (`classified`'s own return) for anything else
241
372
  def mutation(target, oper, bindings)
242
373
  base = { target: target.to_sym, op: oper.to_sym, sign: Hecks::Bluebook::Mutation.sign_for(oper) }
243
374
  # `:delegate`/`:corrects` (CommandBuilder#delegates_to's and
244
- # #corrects_impl's own comments) ride the SAME multi-binding
375
+ # #corrects_impl's own comments) ride the same multi-binding
245
376
  # shape `:append` does.
246
377
  return base.merge(fields: appended(bindings)) if ["append", "delegate", "corrects"].include?(oper)
247
378
 
248
379
  base.merge(source: classified(bindings.first))
249
380
  end
250
381
 
382
+ # Rebuilds an append's own field -> source map from its flattened
383
+ # per-binding rows.
384
+ #
385
+ # @param bindings [Array<Hash{Symbol => Object}>] one append's own
386
+ # dispatched binding rows
387
+ # @return [Hash{Symbol => String}] each bound field name mapped to
388
+ # its own source text
251
389
  def appended(bindings)
252
390
  bindings.to_h { |binding| [text(binding[:field]).to_sym, text(binding[:source])] }
253
391
  end
254
392
 
393
+ # Classifies a single-binding mutation's own source.
394
+ #
395
+ # @param binding [Hash{Symbol => Object}] one dispatched binding row
396
+ # @return [Hash{Symbol => Object}] `{kind: "argument"|"state",
397
+ # name: String}` for an argument or state reference, or
398
+ # `{kind: "literal", value: Object}` (the decoded literal) for
399
+ # anything else
255
400
  def classified(binding)
256
401
  kind = text(binding[:kind])
257
402
  value = text(binding[:source])