hecks 1.2.0 → 1.4.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 (358) hide show
  1. checksums.yaml +4 -4
  2. data/lib/hecks/adapters/driven/claude_code.rb +7 -7
  3. data/lib/hecks/adapters/driven/d1.rb +187 -23
  4. data/lib/hecks/adapters/driven/folder.rb +10 -10
  5. data/lib/hecks/adapters/driven/google_authentication.rb +8 -8
  6. data/lib/hecks/adapters/driven/governance_authorization.rb +31 -13
  7. data/lib/hecks/adapters/driven/heki/journal.rb +60 -2
  8. data/lib/hecks/adapters/driven/heki/saga_store.rb +5 -5
  9. data/lib/hecks/adapters/driven/heki.rb +13 -7
  10. data/lib/hecks/adapters/driven/identity_registry.rb +2 -2
  11. data/lib/hecks/adapters/driven/in_memory_ordering.rb +3 -3
  12. data/lib/hecks/adapters/driven/lambda/client.rb +34 -9
  13. data/lib/hecks/adapters/driven/lambda.rb +39 -33
  14. data/lib/hecks/adapters/driven/local_storage.rb +17 -10
  15. data/lib/hecks/adapters/driven/memory.rb +205 -9
  16. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +1 -1
  17. data/lib/hecks/adapters/driven/postgres/codec.rb +27 -11
  18. data/lib/hecks/adapters/driven/postgres/outbox.rb +40 -2
  19. data/lib/hecks/adapters/driven/postgres/reconnect.rb +23 -7
  20. data/lib/hecks/adapters/driven/postgres/schema_builder.rb +14 -14
  21. data/lib/hecks/adapters/driven/postgres.rb +175 -28
  22. data/lib/hecks/adapters/driven/postgres_era.adapter +5 -0
  23. data/lib/hecks/adapters/driven/prism.rb +4 -4
  24. data/lib/hecks/adapters/driven/sql_query_builder.rb +34 -22
  25. data/lib/hecks/adapters/driven/sqlite/codec.rb +38 -10
  26. data/lib/hecks/adapters/driven/sqlite/projection.rb +60 -32
  27. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +12 -12
  28. data/lib/hecks/adapters/driven/sqlite.rb +181 -21
  29. data/lib/hecks/adapters/driven.rb +4 -4
  30. data/lib/hecks/adapters/driving/github_webhook.rb +145 -0
  31. data/lib/hecks/behaviors/dsl.rb +2 -2
  32. data/lib/hecks/behaviors/expectations.rb +51 -23
  33. data/lib/hecks/behaviors/ir.rb +1 -1
  34. data/lib/hecks/behaviors/rspec.rb +1 -1
  35. data/lib/hecks/behaviors/runner.rb +2 -2
  36. data/lib/hecks/behaviors.rb +1 -1
  37. data/lib/hecks/bluebook/aggregate.rb +13 -13
  38. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +10 -10
  39. data/lib/hecks/bluebook/assembly/build.rb +1 -1
  40. data/lib/hecks/bluebook/assembly/contract.rb +39 -16
  41. data/lib/hecks/bluebook/assembly/contracts.rb +40 -38
  42. data/lib/hecks/bluebook/assembly/marks.rb +18 -18
  43. data/lib/hecks/bluebook/assembly/specializer.rb +19 -21
  44. data/lib/hecks/bluebook/assembly.rb +9 -9
  45. data/lib/hecks/bluebook/attribute.rb +9 -9
  46. data/lib/hecks/bluebook/behaviour/aggregate.rb +11 -11
  47. data/lib/hecks/bluebook/behaviour/attribute.rb +5 -5
  48. data/lib/hecks/bluebook/behaviour/chapter.rb +23 -5
  49. data/lib/hecks/bluebook/behaviour/command.rb +23 -23
  50. data/lib/hecks/bluebook/behaviour/domain_port.rb +27 -3
  51. data/lib/hecks/bluebook/behaviour/entity.rb +8 -8
  52. data/lib/hecks/bluebook/behaviour/hexagon.rb +4 -4
  53. data/lib/hecks/bluebook/behaviour/lifecycle.rb +5 -5
  54. data/lib/hecks/bluebook/behaviour/policy.rb +12 -12
  55. data/lib/hecks/bluebook/behaviour/process_manager.rb +7 -7
  56. data/lib/hecks/bluebook/behaviour/query.rb +1 -1
  57. data/lib/hecks/bluebook/behaviour/read_model.rb +8 -8
  58. data/lib/hecks/bluebook/behaviour/traits.rb +12 -12
  59. data/lib/hecks/bluebook/behaviour/value_object.rb +6 -6
  60. data/lib/hecks/bluebook/capabilities.rb +27 -0
  61. data/lib/hecks/bluebook/chapter.rb +28 -9
  62. data/lib/hecks/bluebook/command.rb +12 -12
  63. data/lib/hecks/bluebook/domain_port.rb +9 -9
  64. data/lib/hecks/bluebook/dsl/adapter_builder.rb +24 -0
  65. data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +49 -49
  66. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +96 -96
  67. data/lib/hecks/bluebook/dsl/attribute_collector.rb +41 -41
  68. data/lib/hecks/bluebook/dsl/binding_proxy.rb +22 -2
  69. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +111 -74
  70. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +48 -30
  71. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +116 -0
  72. data/lib/hecks/bluebook/dsl/command_builder.rb +103 -103
  73. data/lib/hecks/bluebook/dsl/const_shim.rb +46 -15
  74. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +90 -25
  75. data/lib/hecks/bluebook/dsl/entity_builder.rb +56 -56
  76. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +148 -132
  77. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +89 -30
  78. data/lib/hecks/bluebook/dsl/identity_declaration.rb +17 -17
  79. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +27 -4
  80. data/lib/hecks/bluebook/dsl/policy_builder.rb +30 -21
  81. data/lib/hecks/bluebook/dsl/port_builder.rb +38 -7
  82. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +56 -22
  83. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +35 -35
  84. data/lib/hecks/bluebook/dsl/query_builder.rb +5 -5
  85. data/lib/hecks/bluebook/dsl/read_model_builder.rb +34 -34
  86. data/lib/hecks/bluebook/dsl/rule_reference.rb +41 -39
  87. data/lib/hecks/bluebook/dsl/translation_builder.rb +9 -9
  88. data/lib/hecks/bluebook/dsl/value_object_builder.rb +16 -16
  89. data/lib/hecks/bluebook/dsl/word_gate.rb +59 -53
  90. data/lib/hecks/bluebook/dsl/world_builder.rb +51 -8
  91. data/lib/hecks/bluebook/entity.rb +11 -11
  92. data/lib/hecks/bluebook/expression/ast_json.rb +20 -20
  93. data/lib/hecks/bluebook/expression/ast_reader.rb +3 -3
  94. data/lib/hecks/bluebook/expression/canonical_form.rb +9 -9
  95. data/lib/hecks/bluebook/expression/evaluator.rb +18 -18
  96. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +18 -18
  97. data/lib/hecks/bluebook/expression/resolver.rb +60 -62
  98. data/lib/hecks/bluebook/hexagon.rb +1 -1
  99. data/lib/hecks/bluebook/lifecycle.rb +1 -1
  100. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -1
  101. data/lib/hecks/bluebook/meta_validator/judge.rb +122 -86
  102. data/lib/hecks/bluebook/meta_validator/plan.rb +39 -39
  103. data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -2
  104. data/lib/hecks/bluebook/meta_validator/readings.rb +43 -43
  105. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +44 -37
  106. data/lib/hecks/bluebook/meta_validator/shapes.rb +25 -21
  107. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +145 -31
  108. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +6 -6
  109. data/lib/hecks/bluebook/meta_validator/world_judge.rb +5 -5
  110. data/lib/hecks/bluebook/meta_validator.rb +70 -70
  111. data/lib/hecks/bluebook/model_check.rb +301 -84
  112. data/lib/hecks/bluebook/pattern_subset.rb +9 -9
  113. data/lib/hecks/bluebook/policy.rb +15 -13
  114. data/lib/hecks/bluebook/process_manager.rb +14 -14
  115. data/lib/hecks/bluebook/project_register.rb +6 -6
  116. data/lib/hecks/bluebook/query.rb +4 -4
  117. data/lib/hecks/bluebook/read_model.rb +14 -14
  118. data/lib/hecks/bluebook/reference.rb +8 -8
  119. data/lib/hecks/bluebook/smoke_test.rb +19 -19
  120. data/lib/hecks/bluebook/synthesizer.rb +12 -12
  121. data/lib/hecks/bluebook/translation.rb +4 -4
  122. data/lib/hecks/bluebook/value_object.rb +6 -6
  123. data/lib/hecks/bluebook.rb +2 -2
  124. data/lib/hecks/codemod/legacy_dispatch_args.rb +299 -0
  125. data/lib/hecks/codemod/legacy_dispatch_recorder.rb +186 -0
  126. data/lib/hecks/codemod.rb +36 -35
  127. data/lib/hecks/construct.rb +6 -6
  128. data/lib/hecks/corpus.rb +317 -0
  129. data/lib/hecks/deprecation.rb +95 -0
  130. data/lib/hecks/doc/reference.rb +19 -19
  131. data/lib/hecks/embryonaut_bluebook.rb +11 -11
  132. data/lib/hecks/facade/cli_door.rb +69 -10
  133. data/lib/hecks/facade/cli_runner.rb +105 -24
  134. data/lib/hecks/facade/command_request.rb +23 -0
  135. data/lib/hecks/facade/handle.rb +79 -32
  136. data/lib/hecks/facade/json_door.rb +106 -25
  137. data/lib/hecks/facade/surface/aggregate_door.rb +42 -27
  138. data/lib/hecks/facade/surface/chapter.rb +26 -17
  139. data/lib/hecks/facade/surface.rb +16 -3
  140. data/lib/hecks/facade.rb +15 -4
  141. data/lib/hecks/forms/app.rb +46 -30
  142. data/lib/hecks/forms/command_form_renderer.rb +70 -9
  143. data/lib/hecks/forms/field_renderer.rb +142 -6
  144. data/lib/hecks/forms/field_shape.rb +183 -20
  145. data/lib/hecks/forms/html.rb +51 -7
  146. data/lib/hecks/forms/index_renderer.rb +14 -2
  147. data/lib/hecks/forms/params.rb +120 -23
  148. data/lib/hecks/forms/port_argument.rb +2 -2
  149. data/lib/hecks/forms/query_form_renderer.rb +2 -2
  150. data/lib/hecks/forms/record_renderer.rb +2 -2
  151. data/lib/hecks/forms/record_table.rb +1 -1
  152. data/lib/hecks/forms/value_object_shape.rb +3 -3
  153. data/lib/hecks/forms.rb +24 -4
  154. data/lib/hecks/fqn.rb +1 -1
  155. data/lib/hecks/framework/bluebook/governance.bluebook +9 -0
  156. data/lib/hecks/framework.rb +48 -17
  157. data/lib/hecks/freezer.rb +11 -11
  158. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +90 -90
  159. data/lib/hecks/fuzzing/combination_miner.rb +119 -0
  160. data/lib/hecks/fuzzing/concurrent_dispatch.rb +361 -0
  161. data/lib/hecks/fuzzing/coverage_campaign.rb +118 -0
  162. data/lib/hecks/fuzzing/differential.rb +158 -0
  163. data/lib/hecks/fuzzing/domain_generator.rb +694 -0
  164. data/lib/hecks/fuzzing/era_boundary.rb +124 -0
  165. data/lib/hecks/fuzzing/form_census.rb +199 -0
  166. data/lib/hecks/fuzzing/generated_domain_check.rb +95 -0
  167. data/lib/hecks/fuzzing/invalid_value_generator.rb +6 -6
  168. data/lib/hecks/fuzzing/isolated_boot.rb +226 -38
  169. data/lib/hecks/fuzzing/nondeterministic.rb +67 -0
  170. data/lib/hecks/fuzzing/persistence_parity.rb +161 -0
  171. data/lib/hecks/fuzzing/properties/corrections.rb +100 -0
  172. data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +321 -41
  173. data/lib/hecks/fuzzing/properties/guards.rb +129 -26
  174. data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +32 -32
  175. data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +31 -11
  176. data/lib/hecks/fuzzing/properties/outbox.rb +142 -0
  177. data/lib/hecks/fuzzing/properties/querying.rb +17 -17
  178. data/lib/hecks/fuzzing/properties.rb +84 -39
  179. data/lib/hecks/fuzzing/qa_settings.rb +152 -0
  180. data/lib/hecks/fuzzing/replay.rb +224 -114
  181. data/lib/hecks/fuzzing/rotation_priority.rb +94 -0
  182. data/lib/hecks/fuzzing/rust_gap_manifest.rb +113 -0
  183. data/lib/hecks/fuzzing/self_consistency.rb +676 -0
  184. data/lib/hecks/fuzzing/sequence_generator/adversary.rb +526 -0
  185. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +101 -30
  186. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +55 -8
  187. data/lib/hecks/fuzzing/sequence_generator/picker.rb +31 -11
  188. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +123 -32
  189. data/lib/hecks/fuzzing/sequence_generator.rb +152 -31
  190. data/lib/hecks/fuzzing/shrinker.rb +197 -0
  191. data/lib/hecks/fuzzing/structural_skips.rb +39 -0
  192. data/lib/hecks/fuzzing/sweep_depth.rb +53 -0
  193. data/lib/hecks/fuzzing/target_capabilities.rb +180 -0
  194. data/lib/hecks/fuzzing/value_generator.rb +66 -14
  195. data/lib/hecks/fuzzing.rb +11 -0
  196. data/lib/hecks/grammar/evolve.rb +10 -10
  197. data/lib/hecks/grammar.rb +7 -7
  198. data/lib/hecks/ir.rb +13 -13
  199. data/lib/hecks/language/bluebook/bluebook.bluebook +41 -0
  200. data/lib/hecks/language/bluebook/policy.bluebook +11 -1
  201. data/lib/hecks/language/bluebook/vocabulary.bluebook +365 -15
  202. data/lib/hecks/language/oidc.json +5 -0
  203. data/lib/hecks/literal.rb +9 -9
  204. data/lib/hecks/naming.rb +89 -21
  205. data/lib/hecks/ports/access_control.rb +58 -2
  206. data/lib/hecks/ports/agent/answers.rb +83 -6
  207. data/lib/hecks/ports/agent.rb +119 -35
  208. data/lib/hecks/ports/authentication.rb +44 -4
  209. data/lib/hecks/ports/authorization.rb +53 -11
  210. data/lib/hecks/ports/clock.rb +42 -23
  211. data/lib/hecks/ports/extraction.rb +16 -0
  212. data/lib/hecks/ports/identity_assignment.rb +24 -2
  213. data/lib/hecks/ports/identity_generation.rb +17 -3
  214. data/lib/hecks/ports/identity_resolution.rb +18 -1
  215. data/lib/hecks/ports/loading.rb +4 -0
  216. data/lib/hecks/ports/persistence/append_only.rb +172 -8
  217. data/lib/hecks/ports/persistence/binding_policy.rb +34 -0
  218. data/lib/hecks/ports/persistence/codec_boundary.rb +178 -0
  219. data/lib/hecks/ports/persistence/execution.rb +4 -0
  220. data/lib/hecks/ports/persistence/null_saga_store.rb +12 -1
  221. data/lib/hecks/ports/persistence/plugin.rb +42 -4
  222. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +218 -25
  223. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +77 -9
  224. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +81 -24
  225. data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +29 -18
  226. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +144 -60
  227. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +103 -8
  228. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +98 -23
  229. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +282 -109
  230. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +63 -25
  231. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +160 -58
  232. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +51 -28
  233. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +28 -5
  234. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +25 -12
  235. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +129 -34
  236. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +51 -6
  237. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +44 -6
  238. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +16 -0
  239. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +57 -4
  240. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +25 -2
  241. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +338 -83
  242. data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +68 -10
  243. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +9 -3
  244. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +9 -2
  245. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +42 -8
  246. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +16 -1
  247. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +36 -5
  248. data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +23 -3
  249. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +18 -19
  250. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +5 -5
  251. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +1 -1
  252. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -2
  253. data/lib/hecks/ports/persistence/plugins/era.rb +12 -2
  254. data/lib/hecks/ports/persistence/remote_runtime.rb +9 -2
  255. data/lib/hecks/ports/persistence/repository_factory.rb +29 -6
  256. data/lib/hecks/ports/persistence/state_codec.rb +319 -0
  257. data/lib/hecks/ports/persistence.rb +36 -1
  258. data/lib/hecks/ports/projection.rb +61 -7
  259. data/lib/hecks/ports/query/in_memory.rb +3 -3
  260. data/lib/hecks/ports/query/ordering.rb +6 -6
  261. data/lib/hecks/ports/query.rb +35 -0
  262. data/lib/hecks/projections/bootstrap_table.rb +112 -0
  263. data/lib/hecks/projections/diagrams.rb +75 -75
  264. data/lib/hecks/projections/glossary/html.rb +250 -0
  265. data/lib/hecks/projections/glossary/markdown.rb +105 -0
  266. data/lib/hecks/projections/glossary/mermaid.rb +110 -0
  267. data/lib/hecks/projections/glossary/page.css +271 -0
  268. data/lib/hecks/projections/glossary/page.js +72 -0
  269. data/lib/hecks/projections/glossary/sections.rb +17 -0
  270. data/lib/hecks/projections/glossary/sentences.rb +205 -0
  271. data/lib/hecks/projections/glossary.rb +214 -286
  272. data/lib/hecks/projections/ir.rb +1 -1
  273. data/lib/hecks/projections/model/deviations.rb +18 -17
  274. data/lib/hecks/projections/model.rb +25 -21
  275. data/lib/hecks/projections/oidc.rb +7 -7
  276. data/lib/hecks/projections/parser_table.rb +5 -5
  277. data/lib/hecks/projections/reference.rb +3 -3
  278. data/lib/hecks/projections/rust_vocabulary.rb +443 -0
  279. data/lib/hecks/projections/shape.rb +2 -2
  280. data/lib/hecks/projections/statements.rb +11 -11
  281. data/lib/hecks/projections/vocabulary.rb +9 -9
  282. data/lib/hecks/projections.rb +5 -3
  283. data/lib/hecks/projector/cli_projector.rb +29 -29
  284. data/lib/hecks/projector/docs_projector.rb +13 -13
  285. data/lib/hecks/projector/exporter.rb +42 -21
  286. data/lib/hecks/projector/ir_projector.rb +1 -1
  287. data/lib/hecks/projector/narrate_projector.rb +15 -22
  288. data/lib/hecks/projector/target.rb +13 -13
  289. data/lib/hecks/projector.rb +15 -15
  290. data/lib/hecks/query_ir.rb +47 -47
  291. data/lib/hecks/query_specification/common/comparators.rb +19 -3
  292. data/lib/hecks/query_specification/common/comparison.rb +132 -24
  293. data/lib/hecks/query_specification/common/dsl.rb +65 -9
  294. data/lib/hecks/query_specification/common/null_policy.rb +57 -13
  295. data/lib/hecks/query_specification/common/null_semantics.rb +4 -0
  296. data/lib/hecks/query_specification/common/options.rb +25 -0
  297. data/lib/hecks/query_specification/field_path.rb +69 -15
  298. data/lib/hecks/query_specification/hop_path.rb +57 -20
  299. data/lib/hecks/query_specification/read_model/specification.rb +4 -0
  300. data/lib/hecks/rendering.rb +3 -3
  301. data/lib/hecks/router/namespace_installer.rb +3 -3
  302. data/lib/hecks/router.rb +1 -1
  303. data/lib/hecks/runtime/aggregate_lock.rb +11 -11
  304. data/lib/hecks/runtime/boot_gates.rb +3 -3
  305. data/lib/hecks/runtime/caller.rb +8 -8
  306. data/lib/hecks/runtime/capability_graph.rb +2 -2
  307. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +22 -25
  308. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +64 -67
  309. data/lib/hecks/runtime/command_interpreter.rb +159 -102
  310. data/lib/hecks/runtime/command_rules/admissibility.rb +69 -69
  311. data/lib/hecks/runtime/command_rules/arithmetic.rb +137 -91
  312. data/lib/hecks/runtime/command_rules/authorization.rb +38 -17
  313. data/lib/hecks/runtime/command_rules/emission.rb +18 -1
  314. data/lib/hecks/runtime/command_rules/references.rb +94 -19
  315. data/lib/hecks/runtime/command_rules.rb +3 -0
  316. data/lib/hecks/runtime/dependency_planning.rb +11 -11
  317. data/lib/hecks/runtime/dispatcher.rb +283 -90
  318. data/lib/hecks/runtime/entity_element.rb +282 -46
  319. data/lib/hecks/runtime/entity_interpreter.rb +160 -69
  320. data/lib/hecks/runtime/errors.rb +19 -19
  321. data/lib/hecks/runtime/event.rb +6 -6
  322. data/lib/hecks/runtime/identity.rb +22 -22
  323. data/lib/hecks/runtime/instance.rb +39 -14
  324. data/lib/hecks/runtime/interpreting.rb +12 -12
  325. data/lib/hecks/runtime/invocation.rb +276 -0
  326. data/lib/hecks/runtime/loader.rb +14 -14
  327. data/lib/hecks/runtime/outbox.rb +23 -23
  328. data/lib/hecks/runtime/policy_interpreter.rb +54 -54
  329. data/lib/hecks/runtime/port_operation_interpreter.rb +22 -19
  330. data/lib/hecks/runtime/query_interpreter.rb +111 -56
  331. data/lib/hecks/runtime/reaction_invocation.rb +76 -9
  332. data/lib/hecks/runtime/read_model_interpreter.rb +40 -40
  333. data/lib/hecks/runtime/rebuild_sweep.rb +4 -4
  334. data/lib/hecks/runtime/reference_hop.rb +6 -6
  335. data/lib/hecks/runtime/refusal_wording.rb +92 -112
  336. data/lib/hecks/runtime/registry/saga_persistence.rb +21 -21
  337. data/lib/hecks/runtime/registry/verification.rb +36 -26
  338. data/lib/hecks/runtime/registry.rb +56 -27
  339. data/lib/hecks/runtime/remote_dispatcher.rb +38 -23
  340. data/lib/hecks/runtime/routing.rb +10 -88
  341. data/lib/hecks/runtime/saga_interpreter/correlation.rb +17 -17
  342. data/lib/hecks/runtime/saga_interpreter.rb +93 -56
  343. data/lib/hecks/runtime/saga_pending_dispatch.rb +12 -12
  344. data/lib/hecks/runtime/tenant_check.rb +9 -9
  345. data/lib/hecks/runtime/tenant_scope.rb +5 -5
  346. data/lib/hecks/runtime/value/admission.rb +75 -30
  347. data/lib/hecks/runtime/value/coercion.rb +379 -226
  348. data/lib/hecks/runtime/value/entity_list_coercion.rb +248 -0
  349. data/lib/hecks/runtime/value.rb +28 -23
  350. data/lib/hecks/runtime.rb +7 -7
  351. data/lib/hecks/storehouse.rb +64 -64
  352. data/lib/hecks/version.rb +3 -3
  353. data/lib/hecks/vocabulary.rb +207 -5
  354. data/lib/hecks.rb +13 -11
  355. data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +11 -11
  356. data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +14 -12
  357. data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +11 -11
  358. metadata +43 -2
@@ -11,12 +11,20 @@ module Hecks
11
11
  # version, recording a Layer-3 approval, and minting an era's name
12
12
  # once (never recomputed after).
13
13
  module EraStore
14
+ # Lists every era the domain holds, oldest first, refusing any whose text was edited.
15
+ #
14
16
  # Every held text is verified against its raw-byte digest on the
15
17
  # way out — an edited storage fact refuses rather than silently
16
- # reporting "no drift". This is NOT the era name (which hashes
18
+ # reporting "no drift". This is not the era name (which hashes
17
19
  # the canonical projection, minted once, never recomputed): it
18
- # is a plain integrity check over bytes, and a row from before
19
- # the check existed is backfilled, not refused.
20
+ # is a plain integrity check over bytes, and a row that carries
21
+ # no digest yet is backfilled, not refused.
22
+ #
23
+ # @return [Array<Hash{Symbol => Object}>] one Hash per era in ordinal order, `[]` when
24
+ # the domain holds none; keys are `:ordinal` (Integer), `:hash` and `:label` (String,
25
+ # nil until `mint_name!` names the era), `:held_text` (String) and `:watermark`
26
+ # (Integer journal ordinal the era was cut at, nil for era 1)
27
+ # @raise [Runtime::WiringError] if a held text no longer matches its stored digest
20
28
  def eras
21
29
  @db.exec_params(
22
30
  "SELECT ordinal, hash, label, held_text, watermark, held_digest, held_projection::text " \
@@ -29,8 +37,15 @@ module Hecks
29
37
  end
30
38
  end
31
39
 
40
+ # Reads one era's stored row without running the integrity check that `eras` applies.
41
+ #
32
42
  # The unverified row — what bin/reattest_era shows an operator
33
43
  # after the integrity check fires.
44
+ #
45
+ # @param ordinal [Integer] ordinal of the era to read
46
+ # @return [Hash{Symbol => String, nil}, nil] `:held_text`, `:held_digest` (SHA-256 hex,
47
+ # nil if never stored), `:hash` (nil until minted) and `:held_projection` (JSON text,
48
+ # nil if never stored); nil when the domain holds no such era
34
49
  def raw_era(ordinal)
35
50
  rows = @db.exec_params(
36
51
  "SELECT held_text, held_digest, hash, held_projection::text FROM hecks_eras WHERE domain = $1 AND ordinal = $2",
@@ -42,10 +57,17 @@ module Hecks
42
57
  held_projection: rows[0]["held_projection"] }
43
58
  end
44
59
 
45
- # The recovery path: tamper-EVIDENCE (against accident and
60
+ # Accepts an era's held text as it now stands, replacing its stored digest.
61
+ #
62
+ # The recovery path: tamper-evidence (against accident and
46
63
  # drift, not adversaries) gets resolved by a human acknowledging
47
64
  # the text as it now stands — recorded in an append-only
48
- # attestation table, never by a bare psql UPDATE.
65
+ # attestation table, never by a bare psql `UPDATE`.
66
+ #
67
+ # @param ordinal [Integer] ordinal of the era to re-attest
68
+ # @return [String] the new SHA-256 hex digest of the held text
69
+ # @raise [Runtime::WiringError] if the domain holds no era with that ordinal
70
+ # @raise [PG::Error] if Postgres refuses the attestation DDL or a write
49
71
  def reattest!(ordinal)
50
72
  era = raw_era(ordinal)
51
73
  raise Runtime::WiringError, "#{@domain} holds no era #{ordinal} to re-attest" unless era
@@ -72,6 +94,19 @@ module Hecks
72
94
  fresh
73
95
  end
74
96
 
97
+ # Checks one held text against its stored digest, storing the digest if the row has none.
98
+ #
99
+ # A text that passes (or that had no digest to fail against) also gets
100
+ # `backfill_frozen_facts!`; a text that fails gets nothing written.
101
+ #
102
+ # @param ordinal [Integer] ordinal of the era the text belongs to
103
+ # @param text [String] the era's held bluebook source text
104
+ # @param stored_digest [String, nil] SHA-256 hex digest stored with the row; nil when
105
+ # the row carries none yet
106
+ # @param stored_projection_json [String, nil] the row's stored projection as JSON text;
107
+ # nil when the row carries none yet
108
+ # @return [void]
109
+ # @raise [Runtime::WiringError] if `stored_digest` is present and does not match `text`
75
110
  def verify_integrity!(ordinal, text, stored_digest, stored_projection_json)
76
111
  digest = Digest::SHA256.hexdigest(text)
77
112
  if stored_digest.nil?
@@ -90,9 +125,17 @@ module Hecks
90
125
  raise Runtime::WiringError, Runtime::EraTamper.refusal(domain: @domain, ordinal: ordinal)
91
126
  end
92
127
 
93
- # A verified-authentic text backfills what older rows lack: its
128
+ # Fills in the archive copy and the stored projection an era row is missing.
129
+ #
130
+ # A verified-authentic text backfills what a row may lack: its
94
131
  # projection and its archive copy. Never run on a text that
95
132
  # failed verification — that would bless the edit.
133
+ #
134
+ # @param ordinal [Integer] ordinal of the era the text belongs to
135
+ # @param text [String] the era's verified held source text
136
+ # @param stored_projection_json [String, nil] the row's stored projection as JSON text;
137
+ # nil makes this derive one from `text` and store it, unless `text` does not load
138
+ # @return [void]
96
139
  def backfill_frozen_facts!(ordinal, text, stored_projection_json)
97
140
  archive_text!(ordinal, text)
98
141
  return if stored_projection_json
@@ -107,11 +150,27 @@ module Hecks
107
150
  )
108
151
  end
109
152
 
153
+ # Reports the ordinal of the newest era the domain holds.
154
+ #
155
+ # @return [Integer] the highest held ordinal, or 1 when no era is held yet
156
+ # @raise [Runtime::WiringError] if a held text no longer matches its stored digest
110
157
  def current_era
111
158
  held = eras
112
159
  held.empty? ? 1 : held.last[:ordinal]
113
160
  end
114
161
 
162
+ # Holds a domain's first source text as era 1 and makes era 1 the writable era.
163
+ #
164
+ # Call only while the domain holds no era — every caller checks `eras.empty?` first.
165
+ # An existing era 1 row is kept (`ON CONFLICT DO NOTHING`), but `advance_era!(1)` runs
166
+ # regardless, so calling this on a domain past era 1 would roll the write fence back.
167
+ #
168
+ # @param text [String] the bluebook source text to freeze as era 1
169
+ # @param projection [Hash{String => Object}, nil] the storage-shape projection of the
170
+ # bluebook, as `Runtime::StorageShape.project` returns it; nil stores none
171
+ # @return [void]
172
+ # @raise [PG::Error] if Postgres refuses the insert or the policy change, as it does
173
+ # for a role that does not own the journal
115
174
  def hold_first!(text, projection: nil)
116
175
  @db.exec_params(
117
176
  "INSERT INTO hecks_eras (domain, ordinal, held_text, held_digest, held_projection) " \
@@ -124,6 +183,15 @@ module Hecks
124
183
  advance_era!(1)
125
184
  end
126
185
 
186
+ # Copies one version of an era's text into `hecks_era_texts`, keyed by its digest.
187
+ #
188
+ # A version already archived is left alone (`ON CONFLICT DO NOTHING`), so every
189
+ # distinct text an era ever held survives a re-attestation.
190
+ #
191
+ # @param ordinal [Integer] ordinal of the era the text belongs to
192
+ # @param text [String] the source text to archive
193
+ # @return [void]
194
+ # @raise [PG::Error] if Postgres refuses the insert
127
195
  def archive_text!(ordinal, text)
128
196
  @db.exec_params(
129
197
  "INSERT INTO hecks_era_texts (domain, ordinal, digest, held_text) VALUES ($1, $2, $3, $4) " \
@@ -132,10 +200,19 @@ module Hecks
132
200
  )
133
201
  end
134
202
 
135
- # A Layer-3 approval, recorded IN the database it was reviewed
203
+ # Records that a human approved a translation edge's audit samples.
204
+ #
205
+ # A Layer-3 approval, recorded in the database it was reviewed
136
206
  # against — bound to the edge's parsed content and the journal's
137
207
  # high-water ordinal at review time. The latest row for a shape
138
208
  # pair wins (re-approval supersedes).
209
+ #
210
+ # @param from [String] label of the era shape the edge leaves
211
+ # @param to [String] label of the era shape the edge leads to
212
+ # @param edge_digest [String] SHA-256 hex digest of the edge's parsed content, as
213
+ # `Translation::Audit.edge_digest` computes it
214
+ # @return [void]
215
+ # @raise [PG::Error] if Postgres refuses the insert
139
216
  def record_approval!(from:, to:, edge_digest:)
140
217
  @db.exec_params(
141
218
  "INSERT INTO hecks_approvals (domain, from_label, to_label, edge_digest, reviewed_ordinal) " \
@@ -144,6 +221,13 @@ module Hecks
144
221
  )
145
222
  end
146
223
 
224
+ # Finds the most recent approval recorded for the edge between two era shapes.
225
+ #
226
+ # @param from [String] label of the era shape the edge leaves
227
+ # @param to [String] label of the era shape the edge leads to
228
+ # @return [Hash{Symbol => Object}, nil] `:edge_digest` (String, SHA-256 hex of the edge
229
+ # that was reviewed) and `:reviewed_ordinal` (Integer, the journal's highest ordinal at
230
+ # review time); nil when no approval is recorded for the pair
147
231
  def approval_for(from:, to:)
148
232
  rows = @db.exec_params(
149
233
  "SELECT edge_digest, reviewed_ordinal FROM hecks_approvals " \
@@ -155,8 +239,16 @@ module Hecks
155
239
  { edge_digest: rows[0]["edge_digest"], reviewed_ordinal: rows[0]["reviewed_ordinal"].to_i }
156
240
  end
157
241
 
158
- # Era identity is minted ONCE and stored; nothing ever recomputes
242
+ # Stores an era's hash and label, only if the era has no hash yet.
243
+ #
244
+ # Era identity is minted once and stored; nothing ever recomputes
159
245
  # a stored name to verify it.
246
+ #
247
+ # @param ordinal [Integer] ordinal of the era to name
248
+ # @param hash [String] the era's shape hash, SHA-256 hex
249
+ # @param label [String] the short label edges and refusals use, a prefix of `hash`
250
+ # @return [void]
251
+ # @raise [PG::Error] if Postgres refuses the update
160
252
  def mint_name!(ordinal, hash, label)
161
253
  @db.exec_params(
162
254
  "UPDATE hecks_eras SET hash = $3, label = $4, canon_form = $5 " \
@@ -165,6 +257,9 @@ module Hecks
165
257
  )
166
258
  end
167
259
 
260
+ # Reads the journal's high-water mark across every era's partition.
261
+ #
262
+ # @return [Integer] the highest ordinal in the journal, or 0 when the journal is empty
168
263
  def last_ordinal
169
264
  @db.exec("SELECT COALESCE(max(ordinal), 0) AS o FROM #{quoted_journal}")[0]["o"].to_i
170
265
  end
@@ -4,11 +4,16 @@ module Hecks
4
4
  module Adapters
5
5
  class PostgresEra
6
6
  class Lineage
7
- # THE READ-SIDE OF THE ERA WORKAROUND. Once a domain mints a
7
+ # The per-`where`-field read cache that lets a declared query find
8
+ # its ids without reducing the whole aggregate first.
9
+ #
10
+ # ## Why a cache and not an index
11
+ #
12
+ # **The read-side of the era workaround**. Once a domain mints a
8
13
  # second era, `head_view` is a `DISTINCT ON`/`UNION ALL`
9
14
  # reduction — and a `where` clause on anything but `id` (its own
10
15
  # partition key) cannot be pushed through that reduction, so every
11
- # declared query pays the cost of reducing the WHOLE aggregate
16
+ # declared query pays the cost of reducing the whole aggregate
12
17
  # before it can filter anything (see docs/implemented/postgres-era-adapter-
13
18
  # split-plan.md's own trigger section — this is a real
14
19
  # SQL-semantics wall, not a missing index; adding one to
@@ -16,29 +21,35 @@ module Hecks
16
21
  # prove a predicate on a non-partition column commutes with
17
22
  # `DISTINCT ON` without risking a stale row winning).
18
23
  #
19
- # THE WORKAROUND: one narrow table per declared `where`-field
20
- # (never `order_by`-only fields — sorting the reduced output was
21
- # never blocked by the reduction; only filtering was), holding
22
- # exactly (id, ordinal, value) — the CURRENT extracted value for
24
+ # ## The table
25
+ #
26
+ # **The workaround**: one narrow table per declared `where`-field
27
+ # (never `order_by`-only fieldssorting the reduced output is
28
+ # not blocked by the reduction; only filtering is), holding
29
+ # exactly (id, ordinal, value) — the current extracted value for
23
30
  # every live id, maintained transactionally by `append` alongside
24
31
  # the head snapshot it already upserts (same ordinal-guard idiom:
25
32
  # `WHERE ordinal < EXCLUDED.ordinal`). A query whose sole `where`
26
33
  # is on a cached field never runs the reduction at all: `SELECT id
27
34
  # FROM <field>_cache WHERE value <op> $1`, then `SELECT id, state
28
- # FROM head_view WHERE id = ANY($ids)` — safe THROUGH the
35
+ # FROM head_view WHERE id = ANY($ids)` — safe through the
29
36
  # reduction because `id` is its own partition key, unlike the
30
37
  # original field.
31
38
  #
32
- # SCOPED TO NON-LIST FIELDS ONLY, same reasoning Track A (plain
39
+ # ## What it does not cover
40
+ #
41
+ # Scoped to non-list fields only, same reasoning Track A (plain
33
42
  # Postgres) and Track B (Sqlite/D1) both landed on independently
34
43
  # for their own automatic indexing: this codebase's `contains`
35
44
  # compiles to element-membership (`jsonb_array_elements`/
36
45
  # `json_each` + `EXISTS`), which a (id, ordinal, value) cache table
37
- # keyed on ONE scalar value per id has no way to represent — a
46
+ # keyed on one scalar value per id has no way to represent — a
38
47
  # list field would need one row per (id, element), a different
39
48
  # shape this plan does not build. `PostgresEra#eligible_for_cache?`
40
49
  # is where that boundary lives.
41
50
  module FieldCache
51
+ # Names the cache table for one field of one aggregate in one era.
52
+ #
42
53
  # Deterministic and collision-free regardless of field-path
43
54
  # length or storage-name length — Postgres identifiers cap at 63
44
55
  # bytes, and a value-object member path (`compliance.review.
@@ -46,22 +57,52 @@ module Hecks
46
57
  # that if built any less defensively. Not meant to be
47
58
  # human-readable; `hecks_backfill_progress`/catalog lookups are
48
59
  # always driven by this same computed name, never typed by hand.
60
+ #
61
+ # `@domain` is part of the hash input — this table is exposed to
62
+ # the exact same collision this whole file's siblings
63
+ # (`head_view`/`head_snapshot`/`matview`, `lineage.rb`) are
64
+ # domain-qualified against in docs/decisions/0059: without it,
65
+ # two domains bound to PostgresEra against the same database,
66
+ # each with an aggregate sharing a storage_name and a cached
67
+ # where-field of the same name, derive the identical
68
+ # `hecks_fc_<hash>` table and silently share cached rows across
69
+ # domains. Already fully hashed, so folding the domain in costs
70
+ # nothing readability could lose.
71
+ #
72
+ # @param storage_name [String] the aggregate's snake-cased storage name
73
+ # @param era [Integer] ordinal of the era the cache belongs to
74
+ # @param field [String] the cached `where` field, a dotted path for a
75
+ # value-object member such as `"compliance.review.deadline_at"`
76
+ # @return [String] unquoted table name, `hecks_fc_` plus 20 hex characters
49
77
  def field_cache(storage_name, era, field)
50
- "hecks_fc_#{Digest::SHA256.hexdigest("#{storage_name}\0#{era}\0#{field}")[0, 20]}"
78
+ "hecks_fc_#{Digest::SHA256.hexdigest("#{@domain}\0#{storage_name}\0#{era}\0#{field}")[0, 20]}"
51
79
  end
52
80
 
81
+ # Creates one field's cache table if it is missing, then backfills it
82
+ # from the current head until the backfill is recorded complete.
83
+ #
53
84
  # Self-healing, same idiom as `ensure_head_snapshot!`: cheap,
54
- # unconditional, safe to call on every boot. CREATION is a
85
+ # unconditional, safe to call on every boot. Creation is a
55
86
  # short-held lock (table doesn't exist yet — nothing to block);
56
- # BACKFILL runs outside it, chunk by chunk, each chunk its own
87
+ # backfill runs outside it, chunk by chunk, each chunk its own
57
88
  # short lock — never one transaction spanning the scan, per
58
89
  # principle 1. `value_expression` is the exact SQL
59
90
  # `PostgresEra#query_expression(field)` already compiles for
60
91
  # this field, applied against a `state` column this module's own
61
92
  # SQL always makes available in scope (see `field_cache_source_sql`)
62
- # — ONE source of truth for "what does this field mean", not a
93
+ # — one source of truth for "what does this field mean", not a
63
94
  # second hand-rolled copy that could silently drift from what a
64
95
  # live query actually filters on.
96
+ #
97
+ # @param storage_name [String] the aggregate's snake-cased storage name
98
+ # @param era [Integer] ordinal of the era the cache belongs to
99
+ # @param field [String] the cached `where` field, dotted for a value-object member
100
+ # @param value_expression [String] SQL expression that extracts the field's
101
+ # value as text from a jsonb column named `state`
102
+ # @return [String] unquoted name of the cache table, as `field_cache` derives it
103
+ # @raise [PG::Error] if Postgres refuses the DDL, a source read, or an upsert
104
+ # @raise [Runtime::WiringError] if `era` is past 1, a chunk is still to be
105
+ # backfilled, and a held era's text fails its digest check (see `eras`)
65
106
  def ensure_field_cache!(storage_name, era, field, value_expression)
66
107
  name = field_cache(storage_name, era, field)
67
108
  unless table_exists?(name)
@@ -83,6 +124,19 @@ module Hecks
83
124
  name
84
125
  end
85
126
 
127
+ # Fills an existing cache table from the reduced head, one committed chunk
128
+ # of `ResumableBackfill::CHUNK_SIZE` ids at a time, resuming from the cursor
129
+ # held in `hecks_backfill_progress` and doing nothing once it is complete.
130
+ #
131
+ # @param name [String] unquoted cache table name, from `field_cache`
132
+ # @param storage_name [String] the aggregate's snake-cased storage name
133
+ # @param era [Integer] ordinal of the era whose head is read
134
+ # @param value_expression [String] SQL expression that extracts the field's
135
+ # value as text from a jsonb column named `state`
136
+ # @return [void]
137
+ # @raise [PG::Error] if Postgres refuses a source read or an upsert
138
+ # @raise [Runtime::WiringError] if `era` is past 1, a chunk is still to be
139
+ # backfilled, and a held era's text fails its digest check (see `eras`)
86
140
  def backfill_field_cache!(name, storage_name, era, value_expression)
87
141
  chunked_backfill!(
88
142
  name,
@@ -99,16 +153,29 @@ module Hecks
99
153
  )
100
154
  end
101
155
 
102
- # THE LIVE-WRITE SIDE called from `append`, inside the SAME
156
+ # Upserts one id's cached value from the state being written, leaving the
157
+ # row alone when it already carries an equal or newer ordinal.
158
+ #
159
+ # **The live-write side** — called from `append`, inside the same
103
160
  # transaction as the journal insert and the head-snapshot
104
161
  # upsert, for every field this aggregate has a cache table for.
105
- # `state_json` is the entry's OWN new state (already the thing
162
+ # `state_json` is the entry's own new state (already the thing
106
163
  # `append` is about to write) — bound as a literal jsonb value
107
164
  # and aliased `state`, so `value_expression` (built to read a
108
165
  # column literally named `state`) evaluates identically here and
109
166
  # in every backfill/query-time use, with no separate Ruby-side
110
167
  # re-implementation of "how to pick a value-object's member" to
111
168
  # keep in sync.
169
+ #
170
+ # @param name [String] unquoted cache table name, from `field_cache`
171
+ # @param id [String] the aggregate id the entry belongs to
172
+ # @param ordinal [String, Integer] the journal ordinal the entry was written
173
+ # at; `append` passes the decimal text Postgres returned from its INSERT
174
+ # @param state_json [String] the entry's encoded state, as JSON text
175
+ # @param value_expression [String] SQL expression that extracts the field's
176
+ # value as text from a jsonb column named `state`
177
+ # @return [void]
178
+ # @raise [PG::Error] if Postgres refuses the upsert
112
179
  def upsert_field_cache_row!(name, id, ordinal, state_json, value_expression)
113
180
  @db.exec_params(<<~SQL, [id, ordinal, state_json])
114
181
  INSERT INTO #{quote(name)} (id, ordinal, value)
@@ -119,6 +186,14 @@ module Hecks
119
186
  SQL
120
187
  end
121
188
 
189
+ # Removes a deleted id's row from one cache table, so a cached-field query
190
+ # stops offering that id. Called from `append` for a delete entry, inside the
191
+ # same transaction as the journal insert and the head-snapshot tombstone.
192
+ #
193
+ # @param name [String] unquoted cache table name, from `field_cache`
194
+ # @param id [String] the aggregate id whose row is removed
195
+ # @return [void]
196
+ # @raise [PG::Error] if Postgres refuses the delete
122
197
  def delete_field_cache_row!(name, id)
123
198
  @db.exec_params("DELETE FROM #{quote(name)} WHERE id = $1", [id])
124
199
  end
@@ -126,19 +201,19 @@ module Hecks
126
201
  private
127
202
 
128
203
  # The reduced (id, ordinal, state) source a field cache backfills
129
- # from — NOT the raw journal (unlike `backfill_head_snapshot!`'s
130
- # own source): a field cache reflects the CURRENT HEAD value,
204
+ # from — not the raw journal (unlike `backfill_head_snapshot!`'s
205
+ # own source): a field cache reflects the current head value,
131
206
  # which for era > 1 can come from either this era's own live
132
- # writes OR an untouched-this-era id whose value still comes
207
+ # writes or an untouched-this-era id whose value still comes
133
208
  # from the translated ancestor tail. Era 1 has no ancestor tail
134
- # (the snapshot table IS the head, verbatim); era N reduces the
135
- # SAME two sources `compile_head!`'s own final view definition
209
+ # (the snapshot table is the head, verbatim); era N reduces the
210
+ # same two sources `compile_head!`'s own final view definition
136
211
  # unions (head_compiler.rb) — this is deliberately the identical
137
212
  # shape, ordinal kept in the SELECT list instead of dropped,
138
- # because a backfilled cache row needs a REAL ordinal to guard
213
+ # because a backfilled cache row needs a real ordinal to guard
139
214
  # against a concurrent live write the same way every other
140
215
  # upsert in this adapter already does. Ordinals are safe to
141
- # compare across that union because they come from ONE spanning
216
+ # compare across that union because they come from one spanning
142
217
  # sequence per domain (see lineage.rb's own header comment) —
143
218
  # an ancestor-era ordinal is always numerically smaller than any
144
219
  # current-era one, so the ordinary `ordinal <` guard already
@@ -157,7 +232,7 @@ module Hecks
157
232
  "SELECT ordinal, aggregate_id AS id, state FROM #{quote(view)} WHERE operation = 'save'"
158
233
  else
159
234
  # No compiled ancestor matview yet (e.g. this era was just
160
- # minted and compile_head! hasn't run for THIS aggregate) —
235
+ # minted and compile_head! hasn't run for this aggregate) —
161
236
  # the live snapshot side alone is the whole truth so far.
162
237
  "SELECT NULL::bigint AS ordinal, NULL::text AS id, NULL::jsonb AS state WHERE FALSE"
163
238
  end