hecks 2.8.0 → 2.9.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 (404) hide show
  1. checksums.yaml +4 -4
  2. data/exe/hecks +4 -6
  3. data/lib/hecks/adapters/driven/claude_code.rb +4 -104
  4. data/lib/hecks/adapters/driven/d1.rb +44 -237
  5. data/lib/hecks/adapters/driven/folder.rb +17 -76
  6. data/lib/hecks/adapters/driven/google_authentication.rb +15 -49
  7. data/lib/hecks/adapters/driven/governance_authorization.rb +23 -70
  8. data/lib/hecks/adapters/driven/heki/journal.rb +8 -41
  9. data/lib/hecks/adapters/driven/heki/saga_store.rb +12 -54
  10. data/lib/hecks/adapters/driven/heki/snapshot.rb +4 -12
  11. data/lib/hecks/adapters/driven/heki.rb +13 -42
  12. data/lib/hecks/adapters/driven/identity_registry.rb +3 -14
  13. data/lib/hecks/adapters/driven/in_memory_ordering.rb +9 -26
  14. data/lib/hecks/adapters/driven/in_process_key_vault.rb +2 -14
  15. data/lib/hecks/adapters/driven/lambda/client.rb +10 -51
  16. data/lib/hecks/adapters/driven/lambda.rb +10 -84
  17. data/lib/hecks/adapters/driven/local_storage.rb +5 -40
  18. data/lib/hecks/adapters/driven/memory.rb +17 -98
  19. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +5 -21
  20. data/lib/hecks/adapters/driven/postgres/codec.rb +6 -28
  21. data/lib/hecks/adapters/driven/postgres/outbox.rb +3 -12
  22. data/lib/hecks/adapters/driven/postgres/reconnect.rb +4 -30
  23. data/lib/hecks/adapters/driven/postgres/schema_builder.rb +34 -108
  24. data/lib/hecks/adapters/driven/postgres.rb +145 -134
  25. data/lib/hecks/adapters/driven/postgres_era.adapter +4 -15
  26. data/lib/hecks/adapters/driven/prism.rb +7 -30
  27. data/lib/hecks/adapters/driven/sql_query_builder.rb +21 -121
  28. data/lib/hecks/adapters/driven/sqlite/codec.rb +8 -40
  29. data/lib/hecks/adapters/driven/sqlite/projection.rb +26 -82
  30. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +40 -84
  31. data/lib/hecks/adapters/driven/sqlite.rb +128 -65
  32. data/lib/hecks/adapters/driven/tenant_provisioner.rb +5 -48
  33. data/lib/hecks/adapters/driven.rb +5 -36
  34. data/lib/hecks/adapters/driving/github_webhook.rb +8 -76
  35. data/lib/hecks/behaviors/dsl.rb +7 -25
  36. data/lib/hecks/behaviors/expectations.rb +31 -141
  37. data/lib/hecks/behaviors/ir.rb +7 -20
  38. data/lib/hecks/behaviors/rspec.rb +6 -17
  39. data/lib/hecks/behaviors/runner.rb +10 -34
  40. data/lib/hecks/behaviors.rb +4 -8
  41. data/lib/hecks/bluebook/aggregate.rb +9 -75
  42. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +9 -38
  43. data/lib/hecks/bluebook/assembly/build.rb +4 -15
  44. data/lib/hecks/bluebook/assembly/contract.rb +15 -136
  45. data/lib/hecks/bluebook/assembly/contracts.rb +54 -174
  46. data/lib/hecks/bluebook/assembly/marks.rb +31 -223
  47. data/lib/hecks/bluebook/assembly/specializer.rb +6 -52
  48. data/lib/hecks/bluebook/assembly.rb +6 -45
  49. data/lib/hecks/bluebook/attribute.rb +12 -61
  50. data/lib/hecks/bluebook/behaviour/aggregate.rb +10 -39
  51. data/lib/hecks/bluebook/behaviour/attribute.rb +3 -14
  52. data/lib/hecks/bluebook/behaviour/chapter.rb +14 -42
  53. data/lib/hecks/bluebook/behaviour/command.rb +14 -66
  54. data/lib/hecks/bluebook/behaviour/domain_port.rb +4 -20
  55. data/lib/hecks/bluebook/behaviour/entity.rb +7 -27
  56. data/lib/hecks/bluebook/behaviour/hexagon.rb +23 -41
  57. data/lib/hecks/bluebook/behaviour/lifecycle.rb +15 -40
  58. data/lib/hecks/bluebook/behaviour/policy.rb +23 -52
  59. data/lib/hecks/bluebook/behaviour/process_manager.rb +30 -57
  60. data/lib/hecks/bluebook/behaviour/read_model.rb +25 -31
  61. data/lib/hecks/bluebook/behaviour/traits.rb +27 -64
  62. data/lib/hecks/bluebook/behaviour/value_object.rb +5 -24
  63. data/lib/hecks/bluebook/capabilities.rb +17 -49
  64. data/lib/hecks/bluebook/chapter.rb +10 -48
  65. data/lib/hecks/bluebook/command.rb +23 -81
  66. data/lib/hecks/bluebook/domain_port.rb +14 -63
  67. data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +50 -229
  68. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +50 -377
  69. data/lib/hecks/bluebook/dsl/attribute_collector.rb +33 -204
  70. data/lib/hecks/bluebook/dsl/binding_proxy.rb +16 -69
  71. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +86 -708
  72. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +56 -170
  73. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +1 -0
  74. data/lib/hecks/bluebook/dsl/command_builder.rb +74 -546
  75. data/lib/hecks/bluebook/dsl/const_shim.rb +8 -41
  76. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +12 -87
  77. data/lib/hecks/bluebook/dsl/entity_builder.rb +44 -330
  78. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +20 -269
  79. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +26 -194
  80. data/lib/hecks/bluebook/dsl/identity_declaration.rb +13 -88
  81. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +6 -20
  82. data/lib/hecks/bluebook/dsl/policy_builder.rb +16 -88
  83. data/lib/hecks/bluebook/dsl/port_builder.rb +2 -6
  84. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +22 -96
  85. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +31 -184
  86. data/lib/hecks/bluebook/dsl/query_builder.rb +11 -42
  87. data/lib/hecks/bluebook/dsl/read_model_builder.rb +75 -201
  88. data/lib/hecks/bluebook/dsl/rule_reference.rb +22 -163
  89. data/lib/hecks/bluebook/dsl/translation_builder.rb +28 -114
  90. data/lib/hecks/bluebook/dsl/value_object_builder.rb +10 -124
  91. data/lib/hecks/bluebook/dsl/word_gate.rb +16 -162
  92. data/lib/hecks/bluebook/dsl/world_builder.rb +19 -111
  93. data/lib/hecks/bluebook/entity.rb +13 -71
  94. data/lib/hecks/bluebook/expression/ast_json.rb +24 -190
  95. data/lib/hecks/bluebook/expression/ast_reader.rb +12 -54
  96. data/lib/hecks/bluebook/expression/canonical_form.rb +11 -88
  97. data/lib/hecks/bluebook/expression/evaluator.rb +47 -295
  98. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +30 -147
  99. data/lib/hecks/bluebook/expression/resolver.rb +37 -660
  100. data/lib/hecks/bluebook/hexagon.rb +5 -28
  101. data/lib/hecks/bluebook/lifecycle.rb +5 -16
  102. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -7
  103. data/lib/hecks/bluebook/meta_validator/judge.rb +111 -361
  104. data/lib/hecks/bluebook/meta_validator/plan.rb +33 -162
  105. data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -7
  106. data/lib/hecks/bluebook/meta_validator/readings.rb +56 -342
  107. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +24 -176
  108. data/lib/hecks/bluebook/meta_validator/shapes.rb +53 -267
  109. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +43 -305
  110. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +7 -43
  111. data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -18
  112. data/lib/hecks/bluebook/meta_validator.rb +79 -349
  113. data/lib/hecks/bluebook/model_check/client_profile.rb +6 -21
  114. data/lib/hecks/bluebook/model_check.rb +100 -597
  115. data/lib/hecks/bluebook/pattern_subset.rb +11 -69
  116. data/lib/hecks/bluebook/process_manager.rb +13 -83
  117. data/lib/hecks/bluebook/project_loader.rb +3 -39
  118. data/lib/hecks/bluebook/project_register.rb +12 -60
  119. data/lib/hecks/bluebook/query.rb +9 -48
  120. data/lib/hecks/bluebook/read_model.rb +57 -81
  121. data/lib/hecks/bluebook/reference.rb +7 -41
  122. data/lib/hecks/bluebook/smoke_test.rb +8 -98
  123. data/lib/hecks/bluebook/synthesizer.rb +13 -62
  124. data/lib/hecks/bluebook/translation.rb +26 -62
  125. data/lib/hecks/bluebook/value_object.rb +11 -36
  126. data/lib/hecks/bluebook.rb +5 -22
  127. data/lib/hecks/cache_dir.rb +4 -23
  128. data/lib/hecks/cli/document.rb +3 -21
  129. data/lib/hecks/cli/ir.rb +3 -5
  130. data/lib/hecks/cli/mcp.rb +2 -3
  131. data/lib/hecks/cli/mcp_door.rb +19 -114
  132. data/lib/hecks/cli/model_check.rb +18 -85
  133. data/lib/hecks/cli/project_cli.rb +7 -40
  134. data/lib/hecks/cli/project_diagrams.rb +0 -7
  135. data/lib/hecks/cli/run.rb +12 -58
  136. data/lib/hecks/cli/smoke_test.rb +2 -16
  137. data/lib/hecks/cli/stores.rb +1 -2
  138. data/lib/hecks/cli.rb +18 -24
  139. data/lib/hecks/construct.rb +8 -34
  140. data/lib/hecks/deploy/bluebook/deploy.bluebook +33 -142
  141. data/lib/hecks/deploy/bluebook/deploy.hecksagon +2 -9
  142. data/lib/hecks/embryonaut_bluebook/lock.rb +3 -35
  143. data/lib/hecks/embryonaut_bluebook/shape.rb +1 -17
  144. data/lib/hecks/embryonaut_bluebook/vendor.rb +8 -53
  145. data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +4 -19
  146. data/lib/hecks/embryonaut_bluebook.rb +4 -71
  147. data/lib/hecks/facade/cli_door.rb +24 -106
  148. data/lib/hecks/facade/cli_runner.rb +28 -172
  149. data/lib/hecks/facade/command_request.rb +13 -33
  150. data/lib/hecks/facade/handle.rb +34 -121
  151. data/lib/hecks/facade/json_door.rb +31 -146
  152. data/lib/hecks/facade/surface/aggregate_door.rb +39 -104
  153. data/lib/hecks/facade/surface/chapter.rb +10 -54
  154. data/lib/hecks/facade/surface.rb +8 -23
  155. data/lib/hecks/facade.rb +10 -25
  156. data/lib/hecks/forms/app.rb +15 -70
  157. data/lib/hecks/forms/command_form_renderer.rb +10 -29
  158. data/lib/hecks/forms/field_renderer.rb +17 -156
  159. data/lib/hecks/forms/field_shape.rb +30 -222
  160. data/lib/hecks/forms/html.rb +12 -47
  161. data/lib/hecks/forms/index_renderer.rb +1 -4
  162. data/lib/hecks/forms/page.rb +3 -9
  163. data/lib/hecks/forms/params.rb +14 -60
  164. data/lib/hecks/forms/port_argument.rb +2 -19
  165. data/lib/hecks/forms/query_form_renderer.rb +4 -79
  166. data/lib/hecks/forms/record_renderer.rb +8 -75
  167. data/lib/hecks/forms/record_table.rb +7 -50
  168. data/lib/hecks/forms/reference_options.rb +3 -30
  169. data/lib/hecks/forms/value_object_shape.rb +8 -35
  170. data/lib/hecks/forms.rb +5 -33
  171. data/lib/hecks/fqn.rb +5 -12
  172. data/lib/hecks/framework/bluebook/compliance.bluebook +16 -65
  173. data/lib/hecks/framework/bluebook/console_settings.bluebook +47 -134
  174. data/lib/hecks/framework/bluebook/framework.hecksagon +5 -14
  175. data/lib/hecks/framework/bluebook/governance.bluebook +13 -34
  176. data/lib/hecks/framework/bluebook/identity.bluebook +11 -26
  177. data/lib/hecks/framework/bluebook/privacy.bluebook +8 -33
  178. data/lib/hecks/framework.rb +11 -80
  179. data/lib/hecks/freezer.rb +5 -39
  180. data/lib/hecks/grammar/expression.bluebook +15 -40
  181. data/lib/hecks/grammar/translation.bluebook +3 -6
  182. data/lib/hecks/grammar.rb +16 -41
  183. data/lib/hecks/ir.rb +14 -83
  184. data/lib/hecks/language/adapter.bluebook +2 -7
  185. data/lib/hecks/language/bluebook/aggregate.bluebook +56 -221
  186. data/lib/hecks/language/bluebook/attaches/paging.bluebook +6 -15
  187. data/lib/hecks/language/bluebook/bluebook.bluebook +15 -83
  188. data/lib/hecks/language/bluebook/bluebook.hecksagon +3 -15
  189. data/lib/hecks/language/bluebook/command.bluebook +27 -144
  190. data/lib/hecks/language/bluebook/entity.bluebook +24 -97
  191. data/lib/hecks/language/bluebook/policy.bluebook +16 -67
  192. data/lib/hecks/language/bluebook/process_manager.bluebook +28 -151
  193. data/lib/hecks/language/bluebook/projection.bluebook +126 -60
  194. data/lib/hecks/language/bluebook/query.bluebook +12 -43
  195. data/lib/hecks/language/bluebook/shape.bluebook +23 -73
  196. data/lib/hecks/language/bluebook/syntax.bluebook +51 -262
  197. data/lib/hecks/language/bluebook/vocabulary.bluebook +82 -197
  198. data/lib/hecks/language/hecksagon/adapter_binding.bluebook +3 -10
  199. data/lib/hecks/language/hecksagon/domain_port.bluebook +4 -19
  200. data/lib/hecks/language/hecksagon/hecksagon.bluebook +6 -25
  201. data/lib/hecks/language/hecksagon/port_operation.bluebook +3 -14
  202. data/lib/hecks/language/oidc.json +35 -0
  203. data/lib/hecks/language/port.bluebook +4 -17
  204. data/lib/hecks/language/translation/translation.bluebook +3 -9
  205. data/lib/hecks/language/translation/translation_aggregate.bluebook +5 -24
  206. data/lib/hecks/language/world/wiring.bluebook +1 -3
  207. data/lib/hecks/language/world/world.bluebook +5 -7
  208. data/lib/hecks/literal.rb +8 -50
  209. data/lib/hecks/mcp_door_scope.rb +9 -90
  210. data/lib/hecks/mcp_stdio_guard.rb +4 -41
  211. data/lib/hecks/naming.rb +29 -137
  212. data/lib/hecks/ports/access_control.rb +7 -23
  213. data/lib/hecks/ports/agent/answers.rb +5 -23
  214. data/lib/hecks/ports/agent.rb +47 -172
  215. data/lib/hecks/ports/authentication.rb +12 -39
  216. data/lib/hecks/ports/authorization.rb +16 -43
  217. data/lib/hecks/ports/clock.rb +5 -45
  218. data/lib/hecks/ports/extraction.rb +7 -12
  219. data/lib/hecks/ports/identity_assignment.rb +8 -29
  220. data/lib/hecks/ports/identity_generation.rb +6 -29
  221. data/lib/hecks/ports/identity_resolution.rb +2 -10
  222. data/lib/hecks/ports/key_vault.rb +9 -45
  223. data/lib/hecks/ports/persistence/append_only.rb +61 -64
  224. data/lib/hecks/ports/persistence/binding_policy.rb +4 -14
  225. data/lib/hecks/ports/persistence/codec_boundary.rb +20 -80
  226. data/lib/hecks/ports/persistence/null_saga_store.rb +4 -20
  227. data/lib/hecks/ports/persistence/plugin.rb +13 -42
  228. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +38 -141
  229. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +15 -115
  230. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +16 -84
  231. data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +6 -25
  232. data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +3 -22
  233. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +55 -181
  234. data/lib/hecks/ports/persistence/plugins/era/postgres_era/events.rb +77 -0
  235. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +12 -122
  236. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +28 -128
  237. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +73 -474
  238. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +31 -124
  239. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +45 -219
  240. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +13 -108
  241. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +18 -75
  242. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +9 -49
  243. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +6 -123
  244. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +23 -55
  245. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +14 -72
  246. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +7 -16
  247. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +14 -115
  248. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +13 -45
  249. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +127 -554
  250. data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +13 -63
  251. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +2 -17
  252. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +3 -14
  253. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +13 -58
  254. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -17
  255. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +9 -26
  256. data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +9 -25
  257. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +18 -124
  258. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +34 -123
  259. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +5 -12
  260. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +3 -9
  261. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -14
  262. data/lib/hecks/ports/persistence/plugins/era.rb +4 -23
  263. data/lib/hecks/ports/persistence/postgres_dump/connection.rb +7 -23
  264. data/lib/hecks/ports/persistence/postgres_dump.rb +4 -35
  265. data/lib/hecks/ports/persistence/remote_runtime.rb +2 -24
  266. data/lib/hecks/ports/persistence/repository_factory.rb +8 -27
  267. data/lib/hecks/ports/persistence/state_codec.rb +23 -103
  268. data/lib/hecks/ports/persistence.rb +7 -14
  269. data/lib/hecks/ports/projection.rb +42 -84
  270. data/lib/hecks/ports/query/in_memory.rb +10 -58
  271. data/lib/hecks/ports/query/ordering.rb +11 -32
  272. data/lib/hecks/ports/query.rb +14 -37
  273. data/lib/hecks/ports.rb +2 -8
  274. data/lib/hecks/projections/bootstrap_table.rb +11 -43
  275. data/lib/hecks/projections/deploy/fargate/assembly.rb +2 -15
  276. data/lib/hecks/projections/deploy/fargate/cdn.rb +1 -48
  277. data/lib/hecks/projections/deploy/fargate/cdn_default.rb +2 -11
  278. data/lib/hecks/projections/deploy/fargate/check.rb +5 -14
  279. data/lib/hecks/projections/deploy/fargate/containers.rb +3 -78
  280. data/lib/hecks/projections/deploy/fargate/extras.rb +3 -44
  281. data/lib/hecks/projections/deploy/fargate/monitoring.rb +0 -44
  282. data/lib/hecks/projections/deploy/fargate/settings.rb +2 -54
  283. data/lib/hecks/projections/deploy/fargate/yaml.rb +13 -58
  284. data/lib/hecks/projections/deploy/fargate.rb +35 -202
  285. data/lib/hecks/projections/deploy/lambda.rb +150 -678
  286. data/lib/hecks/projections/deploy/preview/access_yaml.rb +1 -33
  287. data/lib/hecks/projections/deploy/preview/containers.rb +6 -111
  288. data/lib/hecks/projections/deploy/preview/routing_yaml.rb +4 -56
  289. data/lib/hecks/projections/deploy/preview/script.rb +2 -14
  290. data/lib/hecks/projections/deploy/preview/settings.rb +3 -33
  291. data/lib/hecks/projections/deploy/preview/task_yaml.rb +2 -38
  292. data/lib/hecks/projections/deploy/preview/template.rb +2 -58
  293. data/lib/hecks/projections/deploy/preview.rb +2 -67
  294. data/lib/hecks/projections/deploy/scripts/settings.rb +3 -25
  295. data/lib/hecks/projections/deploy/scripts.rb +4 -57
  296. data/lib/hecks/projections/deploy/shared.rb +47 -146
  297. data/lib/hecks/projections/deploy/smoke.rb +4 -61
  298. data/lib/hecks/projections/deploy/template_diff/comparer.rb +3 -25
  299. data/lib/hecks/projections/deploy/template_diff/loader.rb +2 -11
  300. data/lib/hecks/projections/deploy/template_diff.rb +5 -57
  301. data/lib/hecks/projections/diagrams.rb +20 -582
  302. data/lib/hecks/projections/glossary/html.rb +14 -130
  303. data/lib/hecks/projections/glossary/markdown.rb +8 -69
  304. data/lib/hecks/projections/glossary/mermaid.rb +9 -66
  305. data/lib/hecks/projections/glossary/sensitivity.rb +5 -34
  306. data/lib/hecks/projections/glossary/sentences.rb +14 -159
  307. data/lib/hecks/projections/glossary.rb +30 -222
  308. data/lib/hecks/projections/ir.rb +3 -10
  309. data/lib/hecks/projections/model/deviations.rb +15 -42
  310. data/lib/hecks/projections/model.rb +12 -51
  311. data/lib/hecks/projections/oidc.rb +12 -56
  312. data/lib/hecks/projections/parser_table.rb +9 -28
  313. data/lib/hecks/projections/reference.rb +2 -15
  314. data/lib/hecks/projections/rust_vocabulary.rb +12 -250
  315. data/lib/hecks/projections/shape.rb +3 -29
  316. data/lib/hecks/projections/statements.rb +7 -86
  317. data/lib/hecks/projections/vocabulary.rb +6 -22
  318. data/lib/hecks/projections.rb +2 -16
  319. data/lib/hecks/projector/cli_projector.rb +60 -375
  320. data/lib/hecks/projector/docs_projector.rb +10 -201
  321. data/lib/hecks/projector/exporter.rb +42 -134
  322. data/lib/hecks/projector/ir_projector.rb +2 -9
  323. data/lib/hecks/projector/narrate_projector.rb +15 -189
  324. data/lib/hecks/projector/target.rb +13 -76
  325. data/lib/hecks/projector.rb +30 -121
  326. data/lib/hecks/query_specification/common/comparators.rb +5 -26
  327. data/lib/hecks/query_specification/common/comparison.rb +35 -143
  328. data/lib/hecks/query_specification/common/dsl.rb +8 -24
  329. data/lib/hecks/query_specification/common/null_policy.rb +20 -70
  330. data/lib/hecks/query_specification/common/options.rb +2 -6
  331. data/lib/hecks/query_specification/common/where_clause.rb +2 -10
  332. data/lib/hecks/query_specification/field_path.rb +37 -77
  333. data/lib/hecks/query_specification/hop_path.rb +12 -76
  334. data/lib/hecks/release/gem_pin.rb +2 -26
  335. data/lib/hecks/release/runner/ci_publisher.rb +3 -6
  336. data/lib/hecks/release/runner/commands.rb +2 -4
  337. data/lib/hecks/release/runner/gem_publisher.rb +2 -3
  338. data/lib/hecks/release/runner/npm_publisher.rb +6 -20
  339. data/lib/hecks/release/runner/preflight.rb +4 -19
  340. data/lib/hecks/release/runner/tagger.rb +2 -9
  341. data/lib/hecks/release/runner.rb +3 -32
  342. data/lib/hecks/rendering.rb +4 -26
  343. data/lib/hecks/router/namespace_installer.rb +12 -36
  344. data/lib/hecks/router.rb +4 -8
  345. data/lib/hecks/runtime/aggregate_lock.rb +8 -33
  346. data/lib/hecks/runtime/boot_gates.rb +3 -18
  347. data/lib/hecks/runtime/caller.rb +19 -59
  348. data/lib/hecks/runtime/capability_graph.rb +5 -21
  349. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +16 -78
  350. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +23 -160
  351. data/lib/hecks/runtime/command_interpreter.rb +124 -306
  352. data/lib/hecks/runtime/command_rules/admissibility.rb +95 -366
  353. data/lib/hecks/runtime/command_rules/arithmetic.rb +66 -196
  354. data/lib/hecks/runtime/command_rules/authorization.rb +13 -45
  355. data/lib/hecks/runtime/command_rules/emission.rb +8 -21
  356. data/lib/hecks/runtime/command_rules/references.rb +23 -202
  357. data/lib/hecks/runtime/dependency_planning.rb +30 -102
  358. data/lib/hecks/runtime/dispatcher.rb +82 -241
  359. data/lib/hecks/runtime/entity_element.rb +40 -462
  360. data/lib/hecks/runtime/entity_interpreter.rb +64 -219
  361. data/lib/hecks/runtime/errors.rb +32 -115
  362. data/lib/hecks/runtime/event.rb +3 -25
  363. data/lib/hecks/runtime/identity.rb +18 -154
  364. data/lib/hecks/runtime/instance.rb +18 -150
  365. data/lib/hecks/runtime/interpreting.rb +11 -70
  366. data/lib/hecks/runtime/invocation.rb +28 -164
  367. data/lib/hecks/runtime/loader.rb +48 -186
  368. data/lib/hecks/runtime/outbox.rb +38 -261
  369. data/lib/hecks/runtime/policy_interpreter.rb +38 -200
  370. data/lib/hecks/runtime/port_operation_interpreter.rb +26 -87
  371. data/lib/hecks/runtime/query_interpreter.rb +45 -187
  372. data/lib/hecks/runtime/reaction_invocation.rb +36 -138
  373. data/lib/hecks/runtime/read_model_interpreter.rb +117 -208
  374. data/lib/hecks/runtime/rebuild_sweep.rb +8 -54
  375. data/lib/hecks/runtime/reference_hop.rb +8 -81
  376. data/lib/hecks/runtime/refusal_wording.rb +8 -89
  377. data/lib/hecks/runtime/registry/saga_persistence.rb +10 -102
  378. data/lib/hecks/runtime/registry/verification.rb +52 -225
  379. data/lib/hecks/runtime/registry/world_defaults.rb +4 -53
  380. data/lib/hecks/runtime/registry.rb +99 -244
  381. data/lib/hecks/runtime/remote_dispatcher.rb +37 -152
  382. data/lib/hecks/runtime/routing.rb +4 -15
  383. data/lib/hecks/runtime/saga_interpreter/correlation.rb +14 -61
  384. data/lib/hecks/runtime/saga_interpreter.rb +79 -263
  385. data/lib/hecks/runtime/saga_pending_dispatch.rb +2 -43
  386. data/lib/hecks/runtime/tenant_check.rb +6 -68
  387. data/lib/hecks/runtime/tenant_scope.rb +3 -28
  388. data/lib/hecks/runtime/value/admission.rb +16 -67
  389. data/lib/hecks/runtime/value/coercion.rb +155 -641
  390. data/lib/hecks/runtime/value/entity_list_coercion.rb +26 -219
  391. data/lib/hecks/runtime/value.rb +12 -84
  392. data/lib/hecks/runtime.rb +17 -65
  393. data/lib/hecks/storehouse.rb +141 -568
  394. data/lib/hecks/tenancy/bluebook/tenancy.bluebook +8 -32
  395. data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +6 -23
  396. data/lib/hecks/vendoring/git_environment.rb +2 -8
  397. data/lib/hecks/vendoring/git_source.rb +4 -10
  398. data/lib/hecks/vendoring.rb +7 -46
  399. data/lib/hecks/version.rb +3 -14
  400. data/lib/hecks.rb +26 -81
  401. data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +8 -46
  402. data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +11 -80
  403. data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +10 -99
  404. metadata +3 -2
@@ -3,45 +3,8 @@ require "digest"
3
3
 
4
4
  module Hecks
5
5
  module Runtime
6
- # The storage-shape projection of a bluebook: exactly the parts of
7
- # the IR that decide what persisted data looks like — aggregates,
8
- # their attributes (with full value-object/entity structure and
9
- # cardinality), references, the lifecycle field, and the identity
10
- # paths. Everything behavioral — commands, invariants, queries,
11
- # policies, lifecycle transitions, defaults, descriptions, comments,
12
- # the declared routing `version:` — is excluded, so editing behavior
13
- # never bumps an era and editing shape always does.
14
- #
15
- # ## Constraints left out on purpose
16
- #
17
- # Three attribute facts on the wire are constraints on persisted
18
- # values, not behavior, and are still excluded — each decided, not
19
- # overlooked:
20
- #
21
- # `optional` — required-ness is enforced at dispatch; stored rows
22
- # are never re-validated on read, so flipping it
23
- # strands nothing already written. Excluded.
24
- # `pattern` — same argument: a fact about what may be written
25
- # next, not about what was stored. Excluded.
26
- # `admits` — the sharpest of the three: narrowing a closed set
27
- # can strand stored rows outside it, and the wire
28
- # carries only the set's name, so a set whose members
29
- # changed under a stable name is invisible even to a
30
- # projection that included the fact (the same lesson
31
- # recursive value-object drift taught). Excluded, and
32
- # named as a gap: constraint tightening has no
33
- # translation-rule vocabulary to acknowledge it yet,
34
- # so including it would mint era bumps nothing can
35
- # explain. When the translation language grows a
36
- # constraint-acknowledgment rule, `admits` (by member
37
- # list, not by name) is first in line, and that
38
- # change bumps `FORM_VERSION`.
39
- #
40
- # ## Structural comparison over the dump form
41
- #
42
- # Projection runs over the canonical dump form (`to_h`, JSON
43
- # round-tripped), so a verdict depends only on the IR — never on live
44
- # object graphs. Structural comparison only, never a hash comparison.
6
+ # The storage-shape projection of a bluebook: only the IR parts that decide how persisted
7
+ # data looks, so behavior edits never bump an era and shape edits always do.
45
8
  module StorageShape
46
9
  module_function
47
10
 
@@ -67,10 +30,7 @@ module Hecks
67
30
  # @return [Boolean] true when both project to an equal structure
68
31
  def same?(held, current) = project(held) == project(current)
69
32
 
70
- # The canonical serialization the Ruby scaffold hashes at mint time
71
- # — the one moment identity is computed. Nothing ever recomputes a
72
- # stored era name to verify it, so this form can evolve freely.
73
- #
33
+ # The canonical serialization hashed at mint time; stored era names are never recomputed.
74
34
  # @param bluebook [Bluebook::Chapter] the bluebook to serialize
75
35
  # @return [String] compact JSON text of `project(bluebook)`
76
36
  def canonical(bluebook) = JSON.generate(project(bluebook))
@@ -89,12 +49,8 @@ module Hecks
89
49
  # @return [String] the first `LABEL_LENGTH` hex characters of `mint_hash(bluebook)`
90
50
  def mint_label(bluebook) = mint_hash(bluebook)[0, LABEL_LENGTH]
91
51
 
92
- # The version of the canonical serialization above. Minted-once
93
- # means a stored name stays valid across form changes — but only
94
- # if each name records which form minted it, so v1-named and
95
- # v2-named eras coexist legibly. Stored beside every minted hash
96
- # (names.tsv fourth field / hecks_eras.canon_form); bump this in
97
- # the same change that alters project/canonical output.
52
+ # Version of the canonical form, stored beside each minted hash; bump it with any
53
+ # change to project/canonical output.
98
54
  FORM_VERSION = 1
99
55
 
100
56
  # Projects one dumped aggregate down to its identity, lifecycle field and attributes.
@@ -108,11 +64,7 @@ module Hecks
108
64
  def project_aggregate(aggregate)
109
65
  {
110
66
  "name" => aggregate["name"],
111
- # The declared identity paths, as a list, in declaration order —
112
- # order is semantic (the paths join in order to form the id).
113
- # No "id" fallback: an aggregate that declares nothing has [],
114
- # and that is a real declared state, distinct from an aggregate
115
- # identified by a field named "id".
67
+ # Declaration order is semantic (paths join in order to form the id); no "id" fallback.
116
68
  "identity" => Array(aggregate["identified_by"]).map(&:to_s),
117
69
  "lifecycle_field" => aggregate.dig("lifecycle", "field"),
118
70
  "attributes" => (aggregate["attributes"] || [])
@@ -121,12 +73,13 @@ module Hecks
121
73
  }
122
74
  end
123
75
 
76
+ # `optional`, `pattern` and `admits` are left out: they constrain future writes, not
77
+ # stored rows. Including `admits` needs a translation rule to acknowledge it first.
78
+ #
124
79
  # Projects one dumped attribute to its name, cardinality and full type signature.
125
80
  #
126
- # @param aggregate [Hash{String => Object}] the dumped aggregate that owns the attribute,
127
- # searched for the value objects and entities its type may name
128
- # @param attribute [Hash{String => Object}] the dumped attribute, read for `"name"`,
129
- # `"list"` and `"type"`
81
+ # @param aggregate [Hash{String => Object}] the dumped aggregate that owns the attribute
82
+ # @param attribute [Hash{String => Object}] the dumped attribute
130
83
  # @param seen [Array<String>] type names already being expanded, which stops a
131
84
  # self-referencing type from recursing forever
132
85
  # @return [Hash{String => Object}] `"name"` (String), `"list"` (Boolean) and `"type"`
@@ -139,11 +92,8 @@ module Hecks
139
92
  }
140
93
  end
141
94
 
142
- # A plain type name for a primitive; the type name plus its
143
- # members' full signatures for a value object or entity — so two
144
- # attributes with the same declared type name but different
145
- # internals are never mistaken for unchanged.
146
- #
95
+ # A primitive's type name, or for a value object or entity the name plus its members'
96
+ # signatures, so same-named types with different internals never look unchanged.
147
97
  # @param aggregate [Hash{String => Object}] the dumped aggregate whose value objects and
148
98
  # entities are searched for `type_name`
149
99
  # @param type_name [String] the attribute's declared type name
@@ -4,23 +4,8 @@ require_relative "../../../../../../projector/exporter"
4
4
  module Hecks
5
5
  module Translation
6
6
  module Audit
7
- # ── the human gate, made real ──────────────────────────────────
8
- #
9
- # For the five portable rule kinds the mint verifies the edge
10
- # mechanically (Layer 2 is the cross-execution equivalence gate).
11
- # A compute has no mechanical verification — the Layer-3 sample a
12
- # human reads is the only one there is — so a compute edge cannot
13
- # mint until someone has run `bin/translation_audit … --approve`.
14
- #
15
- # The approval binds to what was actually reviewed, on both axes:
16
- # a content digest of the parsed edge (change the edge's meaning
17
- # and the approval lapses; a comment does not), and the journal's
18
- # high-water ordinal at review time, recorded in the target
19
- # database — a token in the repo could not bind to the data, and
20
- # samples reviewed against staging or against production-as-of-T
21
- # say nothing about a database that has moved on. Mint stays
22
- # non-interactive and its lock stays short; the human decision
23
- # happens in the audit tool, where the samples are.
7
+ # The human gate: a compute edge cannot mint until `bin/translation_audit --approve`
8
+ # binds an approval to the edge's content digest and the journal's ordinal at review.
24
9
  module ApprovalDigest
25
10
  # Fingerprints a parsed translation edge, so an approval lapses when the edge's
26
11
  # meaning changes but not when only a comment does.
@@ -6,12 +6,8 @@ require_relative "../../../../../../bluebook/model_check"
6
6
  module Hecks
7
7
  module Translation
8
8
  module Audit
9
- # Layer 1 — from the bluebook alone: every translated state must
10
- # pass the new era's types, value-object invariants, and lifecycle.
11
- # This is also where a new, stricter invariant that old records
12
- # violate surfaces — there is no "grandfather old records"
13
- # construct, and the remedy is relaxing the invariant or explicit
14
- # remediation, never a translation rule.
9
+ # Layer 1: every translated state must pass the new era's types, invariants and lifecycle.
10
+ # Old records that violate a stricter invariant surface here; no translation rule fixes them.
15
11
  module LayerOne
16
12
  # Hydrates every translated state as a current-era instance and records each one
17
13
  # the era's types, invariants or lifecycle refuse.
@@ -28,14 +24,7 @@ module Hecks
28
24
  next unless lifecycle
29
25
 
30
26
  held = instance[lifecycle.field]
31
- # `Lifecycle#states` answers default+targets only — a state
32
- # legitimately declared just as a `from:` (a terminal
33
- # transition's source, never anyone's target) is real and
34
- # reachable but invisible to it. `ModelCheck.full_states`
35
- # is the full declared set (default, every target, and
36
- # every from) that `fuzzing/properties.rb`'s own replay
37
- # check already uses for this identical question — see its
38
- # comment on this same hole.
27
+ # `Lifecycle#states` omits states declared only as a `from:`; `full_states` has them.
39
28
  allowed = Bluebook::ModelCheck.full_states(lifecycle)
40
29
  unless held.nil? || allowed.include?(held.to_s)
41
30
  violations << "#{aggregate.name}##{id}: #{lifecycle.field} is #{held.inspect}, " \
@@ -4,48 +4,27 @@ require_relative "../../lineage"
4
4
  module Hecks
5
5
  module Translation
6
6
  module Audit
7
- # Layer 2 — from the edge alone: per-rule value preservation, no
8
- # leftover source keys, and id-set conservation across the edge.
7
+ # Layer 2: from the edge alone, per-rule value preservation and id-set conservation.
9
8
  module LayerTwo
10
9
  # Checks one aggregate's records across the edge for id conservation and, where a
11
10
  # per-record comparison is possible, agreement with the reference transform.
12
11
  #
13
- # Per-rule value preservation and leftover source keys are checked
14
- # against the reference transform in full — never rule by rule in
15
- # isolation, because rules interact (a rename whose value a later
16
- # move partially consumes preserves exactly what the transform
17
- # says it preserves, no more). This makes every mint a run of the
18
- # cross-execution equivalence gate for the five portable rule
19
- # kinds: the compiled SQL produced `after`; the port's entry-JSON
20
- # transform produces `expected`; they must agree byte-for-byte on
21
- # every path a compute doesn't own. Compute paths are exempt — the
22
- # SQL is their only implementation, and the Layer-3 sample is
23
- # their only review. A rekeyed aggregate is exempt from this whole
24
- # per-record check, for the same reason and one more: there is no
25
- # old-id → new-id correspondence to look `after` up by once the id
26
- # itself is what changed.
12
+ # Compute paths and rekeyed aggregates are exempt from the comparison.
27
13
  #
28
14
  # @param violations [Array<String>] collector this method appends messages to
29
15
  # @param aggregate [Bluebook::Aggregate] the current era's IR for the aggregate
30
- # @param declared [Bluebook::TranslationAggregate, nil] this edge's rules for the
31
- # aggregate; nil limits the check to id conservation
16
+ # @param declared [Bluebook::TranslationAggregate, nil] nil limits the check to ids
32
17
  # @param before [Hash{String => Hash}] source state per record id, as parsed JSON
33
18
  # @param after [Hash{String => Hash}] translated state per record id, as parsed JSON
34
19
  # @return [void]
35
- # @raise [Runtime::WiringError] if the reference transform cannot translate a `before`
36
- # state: a convert meets an unmapped value, or a move nests under a non-Hash
20
+ # @raise [Runtime::WiringError] if the reference transform cannot translate `before`
37
21
  def layer_two!(violations, aggregate, declared, before, after)
38
22
  rekeyed = declared && !declared.rekeys.empty?
39
23
 
40
24
  check_id_conservation!(violations, aggregate, before, after, rekeyed: rekeyed)
41
25
 
42
26
  return unless declared
43
- # No correspondence between an old id and its rekeyed row exists
44
- # in Ruby (the rekey's SQL is its only implementation, same as
45
- # compute's) — exempt from the per-record equivalence gate for
46
- # the same reason compute paths already are, extended to the
47
- # whole record since an old-id lookup into `after` can never
48
- # succeed once the id itself has changed.
27
+ # A rekey's SQL is its only implementation and `after` cannot be looked up by old id.
49
28
  return if rekeyed
50
29
 
51
30
  check_value_preservation!(violations, aggregate, declared, before, after)
@@ -53,12 +32,6 @@ module Hecks
53
32
 
54
33
  # Records a violation when the edge loses, gains or collides record ids.
55
34
  #
56
- # Record-count / id-set conservation — one of the two properties
57
- # this module's own header names, and independent of the other
58
- # (per-rule value preservation, below): it needs only `before`,
59
- # `after`, and whether the edge rekeyed, never the declared rules
60
- # themselves.
61
- #
62
35
  # @param violations [Array<String>] collector this method appends at most one message to
63
36
  # @param aggregate [Bluebook::Aggregate] the aggregate, named in the message
64
37
  # @param before [Hash{String => Hash}] source state per record id
@@ -67,13 +40,7 @@ module Hecks
67
40
  # counts instead of id sets
68
41
  # @return [void]
69
42
  def check_id_conservation!(violations, aggregate, before, after, rekeyed:)
70
- # A rekey legitimately changes the id set (that's the entire
71
- # point) — set-equality would flag every honest rekey as data
72
- # loss. What must still hold is record count: a botched rekey
73
- # colliding two distinct old ids onto one new id, or dropping one
74
- # (its SQL returning NULL), shows up as the count going down —
75
- # caught here without needing to track the old→new mapping
76
- # itself.
43
+ # A rekey changes the id set, so compare counts: a collision or a NULL id lowers it.
77
44
  if rekeyed
78
45
  unless before.keys.size == after.keys.size
79
46
  violations << "#{aggregate.name}: the record count changed across a rekeying edge " \
@@ -88,15 +55,14 @@ module Hecks
88
55
  end
89
56
  end
90
57
 
91
- # Per-rule value preservation — the other property this module's
92
- # header names. Only reached once `layer_two!` has already ruled
93
- # out "no declared edge" and "rekeyed" (see its own comment on
94
- # that second guard); this method assumes both are false.
58
+ # Records a violation for each record whose translated state diverges from the reference.
59
+ # Assumes the edge is declared and does not rekey.
60
+ #
95
61
  # @param violations [Array<String>] mutated in place with one message per divergent id
96
62
  # @param aggregate [Bluebook::Aggregate] the aggregate being audited
97
63
  # @param declared [Bluebook::Translation] the declared translation to check against
98
- # @param before [Hash{String => Hash}] the old world's own records, keyed by id
99
- # @param after [Hash{String => Hash}] the new world's own records, keyed by id
64
+ # @param before [Hash{String => Hash}] source records, keyed by id
65
+ # @param after [Hash{String => Hash}] translated records, keyed by id
100
66
  # @return [void]
101
67
  def check_value_preservation!(violations, aggregate, declared, before, after)
102
68
  rules = Ports::Persistence::Lineage.from_declared(declared, aggregate.name)
@@ -124,19 +90,8 @@ module Hecks
124
90
 
125
91
  # Removes the paths a compute owns from a normalized state, in place.
126
92
  #
127
- # Exempts exactly the paths a compute owns, not the whole
128
- # top-level attribute it happens to live under. A bare path
129
- # ("price_cents") is itself the compute's entire value — dropping
130
- # the whole top-level key is correct, there's nothing else there
131
- # to check. A dotted path ("price.cents") only owns that one
132
- # member of the value object it reaches into; every sibling
133
- # member (e.g. "price.currency") is untouched by the compute and
134
- # must stay subject to the equivalence check below. Blanket-
135
- # dropping the whole top-level key for a dotted compute would
136
- # exempt the entire attribute — silent data loss elsewhere in the
137
- # same value object (a migration that nulls or drops a sibling
138
- # field) would produce zero violations, defeating the one gate
139
- # whose entire purpose is to catch exactly that.
93
+ # A dotted path removes only its own member, never the whole top-level key, so sibling
94
+ # members stay under the equivalence check and silent loss there is still caught.
140
95
  #
141
96
  # @param state [Hash{String => Object}] a normalized state; mutated
142
97
  # @param paths [Array<String>] bare (`"price_cents"`) or dotted (`"price.cents"`)
@@ -1,22 +1,11 @@
1
1
  module Hecks
2
2
  module Translation
3
3
  module Audit
4
- # New-era attributes that nothing feeds: absent from every
5
- # translated state, produced by no rule, and carrying no default.
6
- # A report, not a violation — the remedy is a `default:` on the
7
- # attribute, and the loud refusal for a required one comes from
8
- # Layer 1 the moment an invariant reads it.
4
+ # New-era attributes that nothing feeds: no translated state, rule or default supplies them.
5
+ # A report, not a violation; a required one is refused by Layer 1 once an invariant reads it.
9
6
  module UnfedReport
10
7
  # Lists the current era's attributes that no rule, default or translated record feeds.
11
8
  #
12
- # `fed` build-up plus one ordered guard chain per attribute
13
- # (already fed, has a default, actually present in some record, no
14
- # records to check at all) answering a single question — "is
15
- # anything, ever, going to feed this field" — where each `next`
16
- # rules out one way the answer is "not unfed after all" before the
17
- # next is even worth asking. Splitting the guards out would just
18
- # turn each into a same-shaped one-line predicate call.
19
- #
20
9
  # @param aggregate [Bluebook::Aggregate] the current era's IR for the aggregate
21
10
  # @param declared [Bluebook::TranslationAggregate, nil] this edge's rules; the
22
11
  # destinations of its renames, moves, converts and computes count as fed
@@ -57,10 +46,7 @@ module Hecks
57
46
  path.to_s.split(".").reduce(state) do |node, segment|
58
47
  break nil unless node.is_a?(Hash)
59
48
 
60
- # `key?` decides which spelling answers, never `||` — a
61
- # `false` genuinely held at this path must not fall through
62
- # to the other spelling (usually absent) and read as `nil`,
63
- # which would wrongly mark a `false`-valued attribute "unfed".
49
+ # `key?`, not `||`: a held `false` must not fall through and read as nil (unfed).
64
50
  node.key?(segment) ? node[segment] : node[segment.to_sym]
65
51
  end
66
52
  end
@@ -7,13 +7,8 @@ require_relative "audit/approval_digest"
7
7
 
8
8
  module Hecks
9
9
  module Translation
10
- # The audit derives its assertions; nobody hand-lists them. One file
11
- # per layer beside this one: audit/layer_one.rb (the bluebook's own
12
- # rules), audit/layer_two.rb (the edge against the reference
13
- # transform), audit/unfed_report.rb (what nothing feeds), and
14
- # audit/approval_digest.rb (the human gate's binding). Layer 3 — the
15
- # before/after sample a human approves, intent not being derivable —
16
- # is assembled right here in `check`.
10
+ # Derives the audit's assertions per layer (audit/layer_one, layer_two, unfed_report,
11
+ # approval_digest); Layer 3, the human-approved sample, is assembled in `check`.
17
12
  module Audit
18
13
  Verdict = Struct.new(:violations, :dropped, :unfed, :samples, keyword_init: true) do
19
14
  # Reports whether the mechanical layers found nothing to refuse.
@@ -38,14 +33,12 @@ module Hecks
38
33
  # @param aggregate [Bluebook::Aggregate] the current era's IR for the aggregate
39
34
  # @param declared [Bluebook::TranslationAggregate, nil] this edge's rules for the
40
35
  # aggregate; nil when the edge declares none
41
- # @param before [Hash{String => Hash}] the source era's latest state per record id, as
42
- # parsed JSON
43
- # @param after [Hash{String => Hash}] the translated state per record id, as parsed JSON
44
- # @return [Translation::Audit::Verdict] `violations` (Layer 1 and 2 messages), `dropped`
45
- # (declared drop paths as Strings), `unfed` (attribute names nothing feeds) and
46
- # `samples` (the Layer 3 before/after pairs)
36
+ # @param before [Hash{String => Hash}] source state per record id, as parsed JSON
37
+ # @param after [Hash{String => Hash}] translated state per record id, as parsed JSON
38
+ # @return [Translation::Audit::Verdict] Layer 1 and 2 `violations`, `dropped` paths,
39
+ # `unfed` attribute names and Layer 3 `samples`
47
40
  # @raise [Runtime::WiringError] if Layer 2's reference transform cannot translate a
48
- # `before` state: a convert meets an unmapped value, or a move nests under a non-Hash
41
+ # `before` state
49
42
  def check(aggregate:, declared:, before:, after:)
50
43
  violations = []
51
44
 
@@ -74,19 +67,9 @@ module Hecks
74
67
  before.keys.sort.first(SAMPLE_SIZE).map { |id| { id: id, before: before[id], after: after[id] } }
75
68
  end
76
69
 
77
- # Samples both sides of a rekeying edge separately instead of pairing them by id.
78
- #
79
- # A rekey changes the id itself, so `before`'s and `after`'s
80
- # keyspaces share nothing — pairing by matching id (the ordinary
81
- # path above) would show every `after` as nil, telling a human
82
- # nothing. Nothing in-process can compute the old→new
83
- # correspondence either (the rekey's SQL is its only
84
- # implementation, same as compute's own). Shown side by side
85
- # instead, each labelled by its own id: real records going in,
86
- # real records coming out — not claimed to correspond one-to-one,
87
- # but enough for the human this rule's only verification depends
88
- # on to actually see real shapes and values, not a wall of null.
70
+ # Samples both sides of a rekeying edge separately, each labelled by its own id.
89
71
  #
72
+ # A rekey changes the id, so pairing by id would show every `after` as nil.
90
73
  # @param before [Hash{String => Hash}] source state per old record id
91
74
  # @param after [Hash{String => Hash}] translated state per new record id
92
75
  # @return [Array<Hash{Symbol => Object}>] up to `SAMPLE_SIZE` Hashes whose `:id` ends in
@@ -5,17 +5,8 @@ require_relative "../storage_shape"
5
5
 
6
6
  module Hecks
7
7
  module Translation
8
- # The question re-attestation must answer before anything else: did
9
- # the edit change the era's shape, or only its text? Cosmetic edits
10
- # (comments, whitespace, behavior) re-freeze safely; a shape change
11
- # would retroactively redefine what era N *meant* for data already
12
- # written under it, and refuses hard — there is no --accept past
13
- # this guard.
14
- #
15
- # This does not violate minted-once. That prohibition exists so
16
- # boot-time recognition never depends on canonicalization stability;
17
- # this is operator-initiated repair, where a false negative is a
18
- # loud refusal, never a silent misread.
8
+ # Decides whether an edited era text changed the era's shape or only its text.
9
+ # A shape change refuses hard; no --accept flag gets past it.
19
10
  module Reattest
20
11
  module_function
21
12
 
@@ -25,14 +16,12 @@ module Hecks
25
16
  # @param domain [String] the domain's name, used in refusal messages
26
17
  # @param ordinal [Integer] the era's ordinal, used in refusal messages
27
18
  # @param text [String] the held era's bluebook source as it now stands
28
- # @param stored_hash [String, nil] the era's minted shape hash (SHA-256 hex); nil for an
29
- # era that was never named
30
- # @param stored_projection [Hash{String => Object}, nil] the era's stored
31
- # `Runtime::StorageShape.project` result as parsed JSON; nil for a store without one
19
+ # @param stored_hash [String, nil] the era's minted shape hash (SHA-256 hex); nil if unnamed
20
+ # @param stored_projection [Hash{String => Object}, nil] the stored
21
+ # `Runtime::StorageShape.project` result as parsed JSON; nil when absent
32
22
  # @return [Symbol] `:cosmetic` when the shape is unchanged, `:unnamed` when neither a
33
- # projection nor a hash is stored so no comparison is possible
34
- # @raise [Runtime::WiringError] if `text` does not load as a bluebook, or it projects to
35
- # a shape other than the stored one
23
+ # projection nor a hash is stored
24
+ # @raise [Runtime::WiringError] if `text` does not load, or projects to another shape
36
25
  def shape_guard!(domain:, ordinal:, text:, stored_hash:, stored_projection: nil)
37
26
  bluebook = shadow(text)
38
27
  unless bluebook
@@ -41,13 +30,8 @@ module Hecks
41
30
  "bluebook — a held era text is bootable source; restore a loadable text"
42
31
  end
43
32
 
44
- # The stored projection is the preferred comparison: structural,
45
- # version-free, and the same mechanism every boot trusts — so
46
- # this guard never depends on canonicalization stability, and a
47
- # future canonical-form version cannot make cosmetic edits to
48
- # old-form eras false-refuse as shape changes. The hash path
49
- # survives only as a fallback for stores that predate stored
50
- # projections.
33
+ # The stored projection is compared first: it is version-free, so a new canonical form
34
+ # cannot make a cosmetic edit look like a shape change. The hash is the fallback.
51
35
  if stored_projection
52
36
  edited = JSON.parse(JSON.generate(Runtime::StorageShape.project(bluebook)))
53
37
  return :cosmetic if edited == stored_projection