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
data/lib/hecks/codemod.rb CHANGED
@@ -1,49 +1,58 @@
1
1
  require_relative "bluebook/meta_validator"
2
+ require_relative "corpus"
2
3
 
3
4
  module Hecks
4
- # SHARED MACHINERY for a codemod that migrates real `.bluebook` source
5
- # once a DSL builder change makes some previously-required declaration
6
- # optional/redundant — pulled out of `bin/codemod_implicit_append_fields`
7
- # (the first one built), which needed three real, hard-won fixes before
8
- # it could be trusted: a process-lifetime AST cache with no
9
- # invalidation, a batch-revert granularity that let one unsafe
10
- # candidate sink every other safe one sharing its boot, and (in the
11
- # SPINE the codemod migrates FOR, not here) an append-at-end insertion
12
- # that only round-tripped correctly for whichever field happened to be
13
- # last. None of those are guessable in advance; they only surface by
14
- # actually running a real edit against real self-hosted code. This
15
- # module is that lesson, kept — the NEXT codemod plugs in two rule-
16
- # specific procs (`find_candidates`, `apply_candidate`) and inherits
17
- # the boot/safety-net machinery rather than rediscovering it.
5
+ # Shared machinery for a codemod that migrates real `.bluebook` source.
18
6
  #
19
- # A CODEMOD IS NOT PATTERN-MATCHING ALONE. Deciding "is this line safe
20
- # to delete" means knowing what the RUNTIME would resolve it to — so
7
+ # ## Why this module exists
8
+ #
9
+ # For migrating source once a DSL builder change turns a required
10
+ # declaration into an optional, redundant one — pulled out of
11
+ # `bin/codemod_implicit_append_fields` (the first one built), which
12
+ # needed three real, hard-won fixes before it could be trusted: a
13
+ # process-lifetime AST cache with no invalidation, a batch-revert
14
+ # granularity that let one unsafe candidate sink every other safe one
15
+ # sharing its boot, and (in the spine the codemod migrates for, not
16
+ # here) an append-at-end insertion that only round-tripped correctly
17
+ # for whichever field happened to be last. None of those are guessable
18
+ # in advance; they only surface by actually running a real edit
19
+ # against real self-hosted code. This module is that lesson, kept —
20
+ # the next codemod plugs in two rule-specific procs (`find_candidates`,
21
+ # `apply_candidate`) and inherits the boot/safety-net machinery rather
22
+ # than rediscovering it.
23
+ #
24
+ # ## The three-step contract
25
+ #
26
+ # **A codemod is not pattern-matching alone**. Deciding "is this line safe
27
+ # to delete" means knowing what the runtime would resolve it to — so
21
28
  # every codemod built on this module follows the same three steps:
22
29
  # 1. Boot the real domain (or the self-hosted meta-domain) and read
23
- # its IR to find CANDIDATES — provided by the caller's own
30
+ # its IR to find candidates — provided by the caller's own
24
31
  # `find_candidates`, since the actual redundancy rule is specific
25
32
  # to whichever spine change this migration serves.
26
33
  # 2. Locate and remove each candidate's own source text — the
27
34
  # caller's own `apply_candidate`.
28
35
  # 3. Re-boot from the edited text and diff the full IR export
29
36
  # against the pre-edit export. Byte-identical -> keep. Anything
30
- # else (including a RAISED exception — the self-hosted
31
- # meta-domain DISPATCHES itself into being, S14, so a bad edit
37
+ # else (including a raised exception — the self-hosted
38
+ # meta-domain dispatches itself into being, S14, so a bad edit
32
39
  # can surface as a runtime refusal, not just a differing export)
33
- # -> revert and report SKIPPED, never silently guessed past.
40
+ # -> revert and report skipped, never silently guessed past.
41
+ #
42
+ # ## Design-time checklist for a future codemod
34
43
  #
35
- # DESIGN-TIME CHECKLIST for the SPINE change a future codemod migrates
36
- # corpus text for — both items below are real bugs THIS module's own
37
- # first use found, not hypothetical:
38
- # - Does the resolved value get inserted into an ORDER-SENSITIVE
44
+ # For the spine change a future codemod migrates corpus text for —
45
+ # both items below are real bugs this module's own first use found,
46
+ # not hypothetical:
47
+ # - Does the resolved value get inserted into an order-sensitive
39
48
  # list (the exported IR is array-order-sensitive throughout)? If
40
- # so, the spine's own insertion must preserve the ORIGINAL
49
+ # so, the spine's own insertion must preserve the original
41
50
  # position, not just append — an append-at-end insertion only
42
51
  # round-trips correctly for a value that already happened to be
43
52
  # last.
44
- # - Does resolution depend on ANOTHER construct already being
53
+ # - Does resolution depend on another construct already being
45
54
  # declared (the aggregate/entity a `sets`/`append:` field resolves
46
- # against)? If a creator command can be declared BEFORE the
55
+ # against)? If a creator command can be declared before the
47
56
  # construct it creates (real, live: `command "Handler"` before
48
57
  # `entity "Handler"`, one file down), one-pass resolution
49
58
  # genuinely cannot see it yet — not a codemod bug, a structural
@@ -51,16 +60,16 @@ module Hecks
51
60
  module Codemod
52
61
  ROOT = File.expand_path("../..", __dir__)
53
62
 
54
- EXAMPLE_ROOTS = Dir.glob(File.join(ROOT, "examples", "*")).select { |p| File.directory?(p) }.sort
63
+ EXAMPLE_ROOTS = Corpus.members(:example, root: ROOT).map(&:path)
55
64
  META_FILES = (Dir.glob(File.join(ROOT, "lib/hecks/grammar/*.bluebook")) +
56
65
  Dir.glob(File.join(ROOT, "lib/hecks/framework/bluebook/*.bluebook")) +
57
66
  Dir.glob(File.join(ROOT, "lib/hecks/language/bluebook/**/*.bluebook"))).sort
58
67
 
59
- # THE SAME LIGHTWEIGHT PATH `spec/spec_helper.rb`'s own
68
+ # The same lightweight path `spec/spec_helper.rb`'s own
60
69
  # `boot_in_memory` uses — `Hecks.with_registry` satisfies
61
70
  # `Hecks.bluebook`'s own `collect`'s "loaded outside a boot" check
62
71
  # without `Hecks.boot`'s full era-check/adapter-wiring path, which
63
- # needs a LIVE Postgres connection for `compliance` and would make
72
+ # needs a live Postgres connection for `compliance` and would make
64
73
  # every codemod depend on a database it has no reason to touch — a
65
74
  # codemod only ever reads a chapter's own declared IR, never a
66
75
  # stored record.
@@ -69,19 +78,27 @@ module Hecks
69
78
  MEMORY_ADAPTER = File.join(ROOT, "lib/hecks/adapters/driven/memory.adapter")
70
79
  PRISM_ADAPTER = File.join(ROOT, "lib/hecks/adapters/driven/prism.adapter")
71
80
 
81
+ # Exports a booted registry's canonical IR as JSON, for a before/after diff.
82
+ #
83
+ # @param registry [Runtime::Registry] the booted registry to export
84
+ # @return [String] the pretty-printed JSON IR export
72
85
  def self.export_json(registry) = Hecks::Projector::Exporter.json(registry)
73
86
 
74
87
  # `Hecks::Adapters::Prism` caches a file's parsed AST for the
75
- # life of the PROCESS, keyed by path — fine for every existing
88
+ # life of the process, keyed by path — fine for every existing
76
89
  # caller (a file loads once per process: one `bin/ir` run, one
77
- # rspec worker), but a codemod legitimately reloads the SAME path
90
+ # rspec worker), but a codemod legitimately reloads the same path
78
91
  # after editing it, and a stale cached tree reports a
79
- # `given`/`ensures` block at its OLD line number, which no longer
92
+ # `given`/`ensures` block at its old line number, which no longer
80
93
  # matches the freshly re-executed file's own `block.source_location`
81
94
  # — surfacing as "did not survive extraction" on a perfectly valid
82
95
  # file. `Prism.forget` is the real invalidation API this module's
83
96
  # own first use motivated (found here, fixed at the source rather
84
97
  # than left as a private `TREES.clear` poke from outside).
98
+ #
99
+ # @param path [String, Array<String>] a single `.bluebook` file, a directory
100
+ # to glob every `.bluebook` file from, or an explicit list of file paths
101
+ # @return [Runtime::Registry] a fresh registry with every file loaded and judged
85
102
  def self.load_bluebook(path)
86
103
  paths = if path.is_a?(Array)
87
104
  path
@@ -104,16 +121,21 @@ module Hecks
104
121
  registry
105
122
  end
106
123
 
107
- # `forget_all`, not a single `forget` — the meta-domain is NINE
124
+ # `forget_all`, not a single `forget` — the meta-domain is nine
108
125
  # files (`MetaValidator::GRAMMAR_FILES`) merged into one registry,
109
126
  # and a caller here (the codemod runner) doesn't generally know in
110
- # advance which ONE it just edited.
127
+ # advance which one it just edited.
128
+ # @return [String] the freshly re-derived meta-domain's canonical IR, as JSON
111
129
  def self.boot_meta
112
130
  Hecks::Adapters::Prism.forget_all
113
131
  Hecks::Bluebook::MetaValidator.instance_variable_set(:@grammar_registry, nil)
114
132
  export_json(Hecks::Bluebook::MetaValidator.grammar_registry)
115
133
  end
116
134
 
135
+ # Forces the self-hosted meta-domain to re-derive from its current source,
136
+ # discarding any cached parse trees or memoized registry.
137
+ #
138
+ # @return [Runtime::Registry] the freshly re-derived meta-domain's registry
117
139
  def self.meta_registry
118
140
  Hecks::Adapters::Prism.forget_all
119
141
  Hecks::Bluebook::MetaValidator.instance_variable_set(:@grammar_registry, nil)
@@ -123,10 +145,18 @@ module Hecks
123
145
  # Walks every aggregate (and every nested entity, recursively)
124
146
  # across every chapter in a booted registry, yielding [owning
125
147
  # construct, command] pairs — `construct` is whichever
126
- # Aggregate/Entity actually OWNS the command, the same distinction
148
+ # Aggregate/Entity actually owns the command, the same distinction
127
149
  # `AggregateBuilder#command` vs `EntityBuilder#command` already
128
150
  # draws. Generic enough for any rule that needs to walk real
129
151
  # commands, not specific to the attribute-redundancy rule.
152
+ #
153
+ # @param registry [Runtime::Registry] a booted registry
154
+ # @yield [construct, command] every command in the registry, once per aggregate
155
+ # and once per nested entity
156
+ # @yieldparam construct [Bluebook::Aggregate, Bluebook::Entity] whichever
157
+ # aggregate or entity actually owns `command`
158
+ # @yieldparam command [Bluebook::Command] the command
159
+ # @return [Hash{String => Bluebook::Chapter}] `registry.bluebooks`, unchanged
130
160
  def self.each_command(registry)
131
161
  registry.bluebooks.each_value do |chapter|
132
162
  chapter.aggregates.each do |aggregate|
@@ -139,38 +169,74 @@ module Hecks
139
169
  end
140
170
  end
141
171
 
172
+ # Finds one construct's own attribute by name.
173
+ #
174
+ # @param construct [Bluebook::Aggregate, Bluebook::Entity] the construct to search
175
+ # @param name [String, Symbol, #to_s] the attribute's declared name
176
+ # @return [Bluebook::Attribute, nil] the matching attribute, or nil if `construct`
177
+ # declares no attribute named `name`
142
178
  def self.owner_attribute(construct, name)
143
179
  construct.attributes.find { |attr| attr.name.to_s == name.to_s }
144
180
  end
145
181
 
146
- # A LIST attribute's own element construct — the value object or
182
+ # A list attribute's own element construct — the value object or
147
183
  # entity `list_of(...)` names, resolved by `hecks_name` the same way
148
184
  # `AttributeCollector#resolve_identity_field!` already does. Shared
149
185
  # because "what does this list actually hold" is a question any
150
186
  # append-shaped rule needs answered, not just this one.
187
+ #
188
+ # Nothing in the DSL stops a value object and an entity nested under
189
+ # the same aggregate from sharing a `hecks_name` — they are declared
190
+ # through two separate collections with no cross-kind uniqueness
191
+ # check between them. A silent value-objects-before-entities pick
192
+ # would resolve such a pair the same way every time regardless of
193
+ # which one `list_field` actually names, so a genuine collision is
194
+ # refused instead, the same "never first-wins silently" call
195
+ # `EntityBuilder#install_closed_sets!` already makes for a same-named
196
+ # closed set.
197
+ #
198
+ # @param construct [Bluebook::Aggregate, Bluebook::Entity] the construct
199
+ # declaring `list_field`
200
+ # @param list_field [String, Symbol, #to_s] the name of the `list_of(...)` attribute
201
+ # @return [Bluebook::Entity, Bluebook::ValueObject, nil] the construct
202
+ # `list_field` holds a list of, or nil if `list_field` names no attribute,
203
+ # isn't a list, or names no known value object or entity
204
+ # @raise [RuntimeError] if a value object and an entity both match `list_field`'s type
151
205
  def self.element_construct_for(construct, list_field)
152
206
  list_attr = owner_attribute(construct, list_field)
153
207
  return nil unless list_attr&.list?
154
208
 
155
- pool = construct.respond_to?(:value_objects) ? construct.value_objects.dup : []
156
- pool.concat(construct.entities) if construct.respond_to?(:entities)
157
- pool.find { |c| c.hecks_name.to_s == list_attr.type.to_s }
209
+ value_objects = construct.respond_to?(:value_objects) ? construct.value_objects : []
210
+ entities = construct.respond_to?(:entities) ? construct.entities : []
211
+ matches = (value_objects + entities).select { |c| c.hecks_name.to_s == list_attr.type.to_s }
212
+
213
+ if matches.size > 1
214
+ raise "#{construct.hecks_name}##{list_field} names #{list_attr.type}, held by both a value " \
215
+ "object and an entity — ambiguous, cannot resolve which one the list holds"
216
+ end
217
+
218
+ matches.first
158
219
  end
159
220
 
160
- # Either a raised exception OR a differing export counts as unsafe
221
+ # Either a raised exception or a differing export counts as unsafe
161
222
  # — see the module header on why the meta-domain specifically can
162
223
  # raise. Returns [value_or_nil, error_message_or_nil].
224
+ #
225
+ # @yield the risky boot/export step to run
226
+ # @return [Array(Object, nil), Array(nil, String)] `[the block's result, nil]`
227
+ # on success, or `[nil, "ExceptionClass: message"]` if the block raises
228
+ # any StandardError
163
229
  def self.safely
164
230
  [yield, nil]
165
231
  rescue StandardError => e
166
232
  [nil, "#{e.class}: #{e.message}"]
167
233
  end
168
234
 
169
- # THE REUSABLE RUNNER — every real bug fix this module carries lives
235
+ # **The reusable runner** — every real bug fix this module carries lives
170
236
  # here, not in a caller's own script. A caller supplies:
171
237
  #
172
238
  # find_candidates: ->(registry) { [...] }
173
- # Given a booted registry, return every CANDIDATE this rule
239
+ # Given a booted registry, return every candidate this rule
174
240
  # could migrate. A candidate is whatever shape the caller wants
175
241
  # — `apply_candidate` is the only other thing that reads it.
176
242
  #
@@ -178,19 +244,36 @@ module Hecks
178
244
  # Given one file's current text and one candidate, return the
179
245
  # edited text and whether a match was actually found/removed —
180
246
  # `false` (text unchanged) when the candidate doesn't apply to
181
- # THIS file, which is how the meta-domain's multi-file search
247
+ # this file, which is how the meta-domain's multi-file search
182
248
  # below finds the right one without the caller needing to know
183
249
  # which file a candidate lives in ahead of time.
184
250
  #
185
251
  # label: ->(candidate) { "..." }
186
252
  # One-line description for the results report.
187
253
  class Runner
254
+ # @param find_candidates [Proc] `->(registry) { [...] }` — given a booted
255
+ # registry, returns every candidate this rule could migrate; a candidate's
256
+ # shape is the caller's own, read back only by `apply_candidate`
257
+ # @param apply_candidate [Proc] `->(text, candidate) { [new_text, changed_bool] }`
258
+ # — given one file's current text and one candidate, returns the edited text
259
+ # and whether a match was found; `false` means the candidate doesn't apply to
260
+ # this file
261
+ # @param label [Proc] `->(candidate) { "..." }` — a one-line description of a
262
+ # candidate, for the results report
188
263
  def initialize(find_candidates:, apply_candidate:, label:)
189
264
  @find_candidates = find_candidates
190
265
  @apply_candidate = apply_candidate
191
266
  @label = label
192
267
  end
193
268
 
269
+ # Runs this rule's codemod across every example domain and the meta-domain.
270
+ #
271
+ # @param dry_run [Boolean] when true, every safe edit is still written and
272
+ # reverified, then reverted rather than kept
273
+ # @return [Hash{Symbol => Array}] `:applied` (`Array<Hash{file: String,
274
+ # candidates: Array<String>}>`), `:skipped` (`Array<Hash{file: String,
275
+ # reason: String, candidates: Array<String>}>`), and `:clean`
276
+ # (`Array<String>` of domain directories or `"meta-domain"` with no candidates)
194
277
  def run(dry_run: false)
195
278
  results = { applied: [], skipped: [], clean: [] }
196
279
  run_example_domains(results, dry_run)
@@ -198,6 +281,11 @@ module Hecks
198
281
  results
199
282
  end
200
283
 
284
+ # Prints `run`'s results to stdout.
285
+ #
286
+ # @param results [Hash{Symbol => Array}] a `run` result
287
+ # @param dry_run [Boolean] whether this was a dry run, for the report's own heading
288
+ # @return [void]
201
289
  def report(results, dry_run:)
202
290
  puts "== results (#{dry_run ? 'DRY RUN — nothing written' : 'applied'}) =="
203
291
  puts "clean (no candidates): #{results[:clean].join(', ')}" unless results[:clean].empty?
@@ -279,10 +367,10 @@ module Hecks
279
367
  end
280
368
  end
281
369
 
282
- # PER-CANDIDATE, not one batched write-then-verify — the
283
- # meta-domain is ONE shared registry (SyntaxBoot DISPATCHES it
370
+ # Per-candidate, not one batched write-then-verify — the
371
+ # meta-domain is one shared registry (SyntaxBoot dispatches it
284
372
  # into itself, S14), so a single unsafe candidate among many would
285
- # otherwise sink every OTHER, genuinely safe candidate in the same
373
+ # otherwise sink every other, genuinely safe candidate in the same
286
374
  # run: this module's first real run found exactly that (25
287
375
  # candidates, one dispatch-time break, all 25 reverted as a batch
288
376
  # before this per-candidate loop existed). `before_meta` stays the
@@ -291,8 +379,8 @@ module Hecks
291
379
  # still equal the pristine original after each kept edit, by
292
380
  # definition, no moving target needed.
293
381
  # Same shape and same reason as run_example_domains just above (see
294
- # its own comment) — the write/verify/revert sequence, PER
295
- # CANDIDATE (this method's own comment explains why it cannot
382
+ # its own comment) — the write/verify/revert sequence, per
383
+ # candidate (this method's own comment explains why it cannot
296
384
  # batch), is one coherent unit; splitting it would scatter
297
385
  # before_meta/live_meta/applied_by_file state across methods for
298
386
  # no gain.
@@ -323,7 +411,7 @@ module Hecks
323
411
  live_meta[target_file] = text
324
412
  Codemod::META_FILES.each { |f| File.write(f, live_meta[f]) }
325
413
 
326
- # DRY RUN STILL VERIFIES — see run_example_domains' own
414
+ # **Dry run still verifies** — see run_example_domains' own
327
415
  # comment; the edit is always written and rebooted for real,
328
416
  # then always reverted afterward when dry-run (whether or not
329
417
  # it was safe) so the next candidate is judged against the
@@ -1,14 +1,16 @@
1
1
  module Hecks
2
2
  # The invisible field a built construct carries.
3
3
  #
4
- # A construct is a RECORD WITH AN OWNER CHAIN — the chapter (Bluebook)
4
+ # ## Identity
5
+ #
6
+ # A construct is a record with an owner chain — the chapter (Bluebook)
5
7
  # owns its aggregates, an aggregate owns everything declared on it — and the
6
8
  # bluebook identity is carried in its own field, under a `hecks_` prefix that
7
9
  # no domain attribute can collide with. Invisible means exactly that: not an
8
10
  # attribute, not a key in `to_h`, not a reader on instances. Framework
9
11
  # metadata about the construct, not part of the domain it describes.
10
12
  #
11
- # The identity is COMPUTED by walking owners rather than stamped, so nothing
13
+ # The identity is computed by walking owners rather than stamped, so nothing
12
14
  # has to be re-stamped when a chapter is assembled after its aggregates:
13
15
  #
14
16
  # Pizzas the chapter — no owner
@@ -17,10 +19,10 @@ module Hecks
17
19
  #
18
20
  # That spelling is not invented here. It is the id `MetaValidator::Judge`
19
21
  # already mints in `#identify`, so a construct and the meta-domain's
20
- # record OF that construct carry the same identity, and there is no
22
+ # record of that construct carry the same identity, and there is no
21
23
  # translation table between them to be quietly wrong in.
22
24
  #
23
- # Usage:
25
+ # ## Usage
24
26
  #
25
27
  # price = Class.new(ValueObject) # a declaration holder
26
28
  # price.hecks_name = "Price"
@@ -37,25 +39,37 @@ module Hecks
37
39
  attr_writer :hecks_name
38
40
 
39
41
  # A chapter is the only construct that legitimately has no owner. Everything
40
- # else is DECLARED IN something, so a missing owner is an unstamped construct
42
+ # else is declared in something, so a missing owner is an unstamped construct
41
43
  # rather than a top — see hecks_fqn.
42
44
  attr_writer :hecks_root
43
45
 
46
+ # Whether this construct is the top of its own owner chain.
47
+ #
48
+ # @return [Boolean] true for a chapter, which sets `hecks_root`; false otherwise
44
49
  def hecks_root? = @hecks_root ? true : false
45
50
 
46
51
  # The name as the bluebook declares it, never the constant path.
52
+ #
53
+ # @return [String] the construct's own name, without any owner prefix
47
54
  def hecks_name = @hecks_name
48
55
 
49
56
  # How this construct joins its owner. An aggregate is a member of its
50
- # chapter's namespace (`::`) ; everything else is declared ON its owner
57
+ # chapter's namespace (`::`) ; everything else is declared on its owner
51
58
  # (`.`). Overridden by Aggregate, defaulted here for every other construct.
59
+ #
60
+ # @return [String] `"."`, the separator this construct uses in `hecks_fqn`
52
61
  def hecks_separator = "."
53
62
 
54
- # REFUSES rather than guesses. A construct with no owner and no claim to be a
63
+ # Refuses rather than guesses. A construct with no owner and no claim to be a
55
64
  # chapter has simply not been stamped yet — entity commands are in that state
56
65
  # while entities are still IR objects — and answering the bare name would be a
57
66
  # plausible half-truth that no test would notice. That shape of falsehood is
58
67
  # what this repo keeps finding, so it goes red instead.
68
+ #
69
+ # @return [String] the fully-qualified name, joining every owner from the
70
+ # chapter down to this construct
71
+ # @raise [Construct::Unowned] if this construct has no owner and is not itself
72
+ # a chapter (root)
59
73
  def hecks_fqn
60
74
  return hecks_name.to_s if hecks_root?
61
75