hecks 2.7.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.
- checksums.yaml +4 -4
- data/exe/hecks +11 -0
- data/lib/hecks/adapters/driven/claude_code.rb +4 -104
- data/lib/hecks/adapters/driven/d1.rb +44 -237
- data/lib/hecks/adapters/driven/folder.rb +17 -76
- data/lib/hecks/adapters/driven/google_authentication.rb +15 -49
- data/lib/hecks/adapters/driven/governance_authorization.rb +23 -70
- data/lib/hecks/adapters/driven/heki/journal.rb +8 -41
- data/lib/hecks/adapters/driven/heki/saga_store.rb +12 -54
- data/lib/hecks/adapters/driven/heki/snapshot.rb +4 -12
- data/lib/hecks/adapters/driven/heki.rb +13 -42
- data/lib/hecks/adapters/driven/identity_registry.rb +3 -14
- data/lib/hecks/adapters/driven/in_memory_ordering.rb +9 -26
- data/lib/hecks/adapters/driven/in_process_key_vault.rb +2 -14
- data/lib/hecks/adapters/driven/lambda/client.rb +10 -51
- data/lib/hecks/adapters/driven/lambda.rb +10 -84
- data/lib/hecks/adapters/driven/local_storage.rb +5 -40
- data/lib/hecks/adapters/driven/memory.rb +18 -99
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +5 -21
- data/lib/hecks/adapters/driven/postgres/codec.rb +6 -28
- data/lib/hecks/adapters/driven/postgres/outbox.rb +3 -12
- data/lib/hecks/adapters/driven/postgres/reconnect.rb +4 -30
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +34 -108
- data/lib/hecks/adapters/driven/postgres.rb +145 -134
- data/lib/hecks/adapters/driven/postgres_era.adapter +4 -15
- data/lib/hecks/adapters/driven/prism.rb +7 -30
- data/lib/hecks/adapters/driven/sql_query_builder.rb +21 -121
- data/lib/hecks/adapters/driven/sqlite/codec.rb +8 -40
- data/lib/hecks/adapters/driven/sqlite/projection.rb +26 -82
- data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +40 -84
- data/lib/hecks/adapters/driven/sqlite.rb +128 -65
- data/lib/hecks/adapters/driven/tenant_provisioner.rb +15 -37
- data/lib/hecks/adapters/driven.rb +5 -36
- data/lib/hecks/adapters/driving/github_webhook.rb +8 -76
- data/lib/hecks/behaviors/dsl.rb +7 -25
- data/lib/hecks/behaviors/expectations.rb +32 -142
- data/lib/hecks/behaviors/ir.rb +7 -20
- data/lib/hecks/behaviors/rspec.rb +6 -17
- data/lib/hecks/behaviors/runner.rb +10 -34
- data/lib/hecks/behaviors.rb +4 -8
- data/lib/hecks/bluebook/aggregate.rb +9 -75
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +9 -38
- data/lib/hecks/bluebook/assembly/build.rb +4 -15
- data/lib/hecks/bluebook/assembly/contract.rb +15 -136
- data/lib/hecks/bluebook/assembly/contracts.rb +54 -174
- data/lib/hecks/bluebook/assembly/marks.rb +31 -223
- data/lib/hecks/bluebook/assembly/specializer.rb +6 -52
- data/lib/hecks/bluebook/assembly.rb +6 -45
- data/lib/hecks/bluebook/attribute.rb +12 -61
- data/lib/hecks/bluebook/behaviour/aggregate.rb +10 -39
- data/lib/hecks/bluebook/behaviour/attribute.rb +3 -14
- data/lib/hecks/bluebook/behaviour/chapter.rb +17 -42
- data/lib/hecks/bluebook/behaviour/command.rb +14 -66
- data/lib/hecks/bluebook/behaviour/domain_port.rb +4 -20
- data/lib/hecks/bluebook/behaviour/entity.rb +7 -27
- data/lib/hecks/bluebook/behaviour/hexagon.rb +23 -41
- data/lib/hecks/bluebook/behaviour/lifecycle.rb +15 -40
- data/lib/hecks/bluebook/behaviour/policy.rb +23 -52
- data/lib/hecks/bluebook/behaviour/process_manager.rb +30 -57
- data/lib/hecks/bluebook/behaviour/read_model.rb +38 -26
- data/lib/hecks/bluebook/behaviour/traits.rb +27 -64
- data/lib/hecks/bluebook/behaviour/value_object.rb +5 -24
- data/lib/hecks/bluebook/capabilities.rb +17 -49
- data/lib/hecks/bluebook/chapter.rb +10 -48
- data/lib/hecks/bluebook/command.rb +23 -81
- data/lib/hecks/bluebook/domain_port.rb +14 -63
- data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +50 -229
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +50 -377
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +33 -204
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +17 -65
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +86 -708
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +56 -170
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +1 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +74 -546
- data/lib/hecks/bluebook/dsl/const_shim.rb +8 -41
- data/lib/hecks/bluebook/dsl/domain_port_builder.rb +12 -87
- data/lib/hecks/bluebook/dsl/entity_builder.rb +44 -330
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +20 -269
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +26 -189
- data/lib/hecks/bluebook/dsl/identity_declaration.rb +13 -88
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +6 -20
- data/lib/hecks/bluebook/dsl/policy_builder.rb +16 -88
- data/lib/hecks/bluebook/dsl/port_builder.rb +2 -6
- data/lib/hecks/bluebook/dsl/port_operation_builder.rb +22 -96
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +31 -184
- data/lib/hecks/bluebook/dsl/query_builder.rb +11 -42
- data/lib/hecks/bluebook/dsl/read_model_builder.rb +75 -201
- data/lib/hecks/bluebook/dsl/rule_reference.rb +22 -163
- data/lib/hecks/bluebook/dsl/translation_builder.rb +28 -114
- data/lib/hecks/bluebook/dsl/value_object_builder.rb +10 -124
- data/lib/hecks/bluebook/dsl/word_gate.rb +16 -162
- data/lib/hecks/bluebook/dsl/world_builder.rb +19 -106
- data/lib/hecks/bluebook/entity.rb +13 -71
- data/lib/hecks/bluebook/expression/ast_json.rb +24 -190
- data/lib/hecks/bluebook/expression/ast_reader.rb +12 -54
- data/lib/hecks/bluebook/expression/canonical_form.rb +11 -88
- data/lib/hecks/bluebook/expression/evaluator.rb +47 -295
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +30 -147
- data/lib/hecks/bluebook/expression/resolver.rb +37 -660
- data/lib/hecks/bluebook/hexagon.rb +5 -28
- data/lib/hecks/bluebook/lifecycle.rb +5 -16
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -7
- data/lib/hecks/bluebook/meta_validator/judge.rb +111 -361
- data/lib/hecks/bluebook/meta_validator/plan.rb +33 -162
- data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -7
- data/lib/hecks/bluebook/meta_validator/readings.rb +56 -342
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +24 -176
- data/lib/hecks/bluebook/meta_validator/shapes.rb +54 -268
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +47 -308
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +7 -43
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -18
- data/lib/hecks/bluebook/meta_validator.rb +79 -349
- data/lib/hecks/bluebook/model_check/client_profile.rb +10 -91
- data/lib/hecks/bluebook/model_check.rb +102 -600
- data/lib/hecks/bluebook/pattern_subset.rb +11 -69
- data/lib/hecks/bluebook/process_manager.rb +13 -83
- data/lib/hecks/bluebook/project_loader.rb +3 -39
- data/lib/hecks/bluebook/project_register.rb +12 -60
- data/lib/hecks/bluebook/query.rb +9 -48
- data/lib/hecks/bluebook/read_model.rb +57 -81
- data/lib/hecks/bluebook/reference.rb +7 -41
- data/lib/hecks/bluebook/smoke_test.rb +8 -98
- data/lib/hecks/bluebook/synthesizer.rb +13 -62
- data/lib/hecks/bluebook/translation.rb +26 -62
- data/lib/hecks/bluebook/value_object.rb +11 -36
- data/lib/hecks/bluebook.rb +5 -22
- data/lib/hecks/cache_dir.rb +84 -0
- data/lib/hecks/cli/document.rb +86 -0
- data/lib/hecks/cli/ir.rb +45 -0
- data/lib/hecks/cli/mcp.rb +31 -0
- data/lib/hecks/cli/mcp_door.rb +366 -0
- data/lib/hecks/cli/model_check.rb +203 -0
- data/lib/hecks/cli/project_cli.rb +90 -0
- data/lib/hecks/cli/project_diagrams.rb +36 -0
- data/lib/hecks/cli/run.rb +173 -0
- data/lib/hecks/cli/smoke_test.rb +45 -0
- data/lib/hecks/cli/stores.rb +53 -0
- data/lib/hecks/cli.rb +160 -0
- data/lib/hecks/construct.rb +8 -34
- data/lib/hecks/deploy/bluebook/deploy.bluebook +33 -142
- data/lib/hecks/deploy/bluebook/deploy.hecksagon +2 -9
- data/lib/hecks/embryonaut_bluebook/lock.rb +3 -35
- data/lib/hecks/embryonaut_bluebook/shape.rb +1 -17
- data/lib/hecks/embryonaut_bluebook/vendor.rb +8 -53
- data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +4 -19
- data/lib/hecks/embryonaut_bluebook.rb +4 -71
- data/lib/hecks/facade/cli_door.rb +24 -106
- data/lib/hecks/facade/cli_runner.rb +28 -172
- data/lib/hecks/facade/command_request.rb +13 -33
- data/lib/hecks/facade/handle.rb +34 -121
- data/lib/hecks/facade/json_door.rb +31 -146
- data/lib/hecks/facade/surface/aggregate_door.rb +39 -104
- data/lib/hecks/facade/surface/chapter.rb +10 -54
- data/lib/hecks/facade/surface.rb +8 -23
- data/lib/hecks/facade.rb +10 -25
- data/lib/hecks/forms/app.rb +15 -70
- data/lib/hecks/forms/command_form_renderer.rb +10 -29
- data/lib/hecks/forms/field_renderer.rb +17 -156
- data/lib/hecks/forms/field_shape.rb +30 -222
- data/lib/hecks/forms/html.rb +12 -47
- data/lib/hecks/forms/index_renderer.rb +1 -4
- data/lib/hecks/forms/page.rb +3 -9
- data/lib/hecks/forms/params.rb +14 -60
- data/lib/hecks/forms/port_argument.rb +2 -19
- data/lib/hecks/forms/query_form_renderer.rb +4 -79
- data/lib/hecks/forms/record_renderer.rb +8 -75
- data/lib/hecks/forms/record_table.rb +7 -50
- data/lib/hecks/forms/reference_options.rb +3 -30
- data/lib/hecks/forms/value_object_shape.rb +8 -35
- data/lib/hecks/forms.rb +5 -33
- data/lib/hecks/fqn.rb +5 -12
- data/lib/hecks/framework/bluebook/compliance.bluebook +16 -65
- data/lib/hecks/framework/bluebook/console_settings.bluebook +47 -134
- data/lib/hecks/framework/bluebook/framework.hecksagon +5 -14
- data/lib/hecks/framework/bluebook/governance.bluebook +13 -34
- data/lib/hecks/framework/bluebook/identity.bluebook +11 -26
- data/lib/hecks/framework/bluebook/privacy.bluebook +8 -33
- data/lib/hecks/framework.rb +11 -80
- data/lib/hecks/freezer.rb +5 -39
- data/lib/hecks/grammar/expression.bluebook +15 -40
- data/lib/hecks/grammar/translation.bluebook +3 -6
- data/lib/hecks/grammar.rb +16 -41
- data/lib/hecks/ir.rb +14 -83
- data/lib/hecks/language/adapter.bluebook +2 -7
- data/lib/hecks/language/bluebook/aggregate.bluebook +56 -221
- data/lib/hecks/language/bluebook/attaches/paging.bluebook +6 -15
- data/lib/hecks/language/bluebook/bluebook.bluebook +15 -83
- data/lib/hecks/language/bluebook/bluebook.hecksagon +3 -15
- data/lib/hecks/language/bluebook/command.bluebook +27 -144
- data/lib/hecks/language/bluebook/entity.bluebook +24 -97
- data/lib/hecks/language/bluebook/policy.bluebook +16 -67
- data/lib/hecks/language/bluebook/process_manager.bluebook +28 -151
- data/lib/hecks/language/bluebook/projection.bluebook +126 -60
- data/lib/hecks/language/bluebook/query.bluebook +12 -43
- data/lib/hecks/language/bluebook/shape.bluebook +23 -73
- data/lib/hecks/language/bluebook/syntax.bluebook +51 -262
- data/lib/hecks/language/bluebook/vocabulary.bluebook +98 -197
- data/lib/hecks/language/hecksagon/adapter_binding.bluebook +3 -10
- data/lib/hecks/language/hecksagon/domain_port.bluebook +4 -19
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +6 -25
- data/lib/hecks/language/hecksagon/port_operation.bluebook +3 -14
- data/lib/hecks/language/oidc.json +35 -0
- data/lib/hecks/language/port.bluebook +4 -17
- data/lib/hecks/language/translation/translation.bluebook +3 -9
- data/lib/hecks/language/translation/translation_aggregate.bluebook +5 -24
- data/lib/hecks/language/world/wiring.bluebook +1 -3
- data/lib/hecks/language/world/world.bluebook +5 -7
- data/lib/hecks/literal.rb +8 -50
- data/lib/hecks/mcp_door_scope.rb +95 -0
- data/lib/hecks/mcp_stdio_guard.rb +4 -41
- data/lib/hecks/naming.rb +29 -137
- data/lib/hecks/ports/access_control.rb +7 -23
- data/lib/hecks/ports/agent/answers.rb +5 -23
- data/lib/hecks/ports/agent.rb +47 -172
- data/lib/hecks/ports/authentication.rb +12 -39
- data/lib/hecks/ports/authorization.rb +16 -43
- data/lib/hecks/ports/clock.rb +5 -45
- data/lib/hecks/ports/extraction.rb +7 -12
- data/lib/hecks/ports/identity_assignment.rb +8 -29
- data/lib/hecks/ports/identity_generation.rb +6 -29
- data/lib/hecks/ports/identity_resolution.rb +2 -10
- data/lib/hecks/ports/key_vault.rb +9 -45
- data/lib/hecks/ports/persistence/append_only.rb +62 -65
- data/lib/hecks/ports/persistence/binding_policy.rb +4 -14
- data/lib/hecks/ports/persistence/codec_boundary.rb +20 -80
- data/lib/hecks/ports/persistence/null_saga_store.rb +4 -20
- data/lib/hecks/ports/persistence/plugin.rb +13 -42
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +38 -141
- data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +15 -115
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +16 -84
- data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +7 -26
- data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +3 -22
- data/lib/hecks/ports/persistence/plugins/era/lineage.rb +55 -181
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/events.rb +77 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +12 -122
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +28 -128
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +73 -474
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +31 -124
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +45 -219
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +13 -108
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +18 -75
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +9 -49
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +6 -123
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +23 -55
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +14 -72
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +7 -16
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +14 -115
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +13 -45
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +127 -554
- data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +13 -63
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +2 -17
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +3 -14
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +13 -58
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -17
- data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +9 -26
- data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +9 -25
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +22 -122
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +34 -123
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +5 -12
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +3 -9
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -14
- data/lib/hecks/ports/persistence/plugins/era.rb +4 -23
- data/lib/hecks/ports/persistence/postgres_dump/connection.rb +7 -23
- data/lib/hecks/ports/persistence/postgres_dump.rb +4 -35
- data/lib/hecks/ports/persistence/remote_runtime.rb +2 -24
- data/lib/hecks/ports/persistence/repository_factory.rb +8 -27
- data/lib/hecks/ports/persistence/state_codec.rb +23 -103
- data/lib/hecks/ports/persistence.rb +7 -14
- data/lib/hecks/ports/projection.rb +42 -84
- data/lib/hecks/ports/query/in_memory.rb +10 -58
- data/lib/hecks/ports/query/ordering.rb +11 -32
- data/lib/hecks/ports/query.rb +14 -37
- data/lib/hecks/ports.rb +2 -8
- data/lib/hecks/projections/bootstrap_table.rb +11 -43
- data/lib/hecks/projections/deploy/fargate/assembly.rb +2 -15
- data/lib/hecks/projections/deploy/fargate/cdn.rb +1 -48
- data/lib/hecks/projections/deploy/fargate/cdn_default.rb +2 -11
- data/lib/hecks/projections/deploy/fargate/check.rb +5 -14
- data/lib/hecks/projections/deploy/fargate/containers.rb +3 -78
- data/lib/hecks/projections/deploy/fargate/extras.rb +3 -44
- data/lib/hecks/projections/deploy/fargate/monitoring.rb +0 -44
- data/lib/hecks/projections/deploy/fargate/settings.rb +2 -54
- data/lib/hecks/projections/deploy/fargate/yaml.rb +13 -58
- data/lib/hecks/projections/deploy/fargate.rb +35 -202
- data/lib/hecks/projections/deploy/lambda.rb +151 -679
- data/lib/hecks/projections/deploy/preview/access_yaml.rb +1 -33
- data/lib/hecks/projections/deploy/preview/containers.rb +6 -111
- data/lib/hecks/projections/deploy/preview/routing_yaml.rb +4 -56
- data/lib/hecks/projections/deploy/preview/script.rb +2 -14
- data/lib/hecks/projections/deploy/preview/settings.rb +3 -33
- data/lib/hecks/projections/deploy/preview/task_yaml.rb +2 -38
- data/lib/hecks/projections/deploy/preview/template.rb +2 -58
- data/lib/hecks/projections/deploy/preview.rb +2 -67
- data/lib/hecks/projections/deploy/scripts/settings.rb +3 -25
- data/lib/hecks/projections/deploy/scripts.rb +4 -57
- data/lib/hecks/projections/deploy/shared.rb +47 -146
- data/lib/hecks/projections/deploy/smoke.rb +4 -61
- data/lib/hecks/projections/deploy/template_diff/comparer.rb +3 -25
- data/lib/hecks/projections/deploy/template_diff/loader.rb +2 -11
- data/lib/hecks/projections/deploy/template_diff.rb +5 -57
- data/lib/hecks/projections/diagrams.rb +20 -582
- data/lib/hecks/projections/glossary/html.rb +14 -130
- data/lib/hecks/projections/glossary/markdown.rb +8 -69
- data/lib/hecks/projections/glossary/mermaid.rb +9 -66
- data/lib/hecks/projections/glossary/sensitivity.rb +5 -34
- data/lib/hecks/projections/glossary/sentences.rb +14 -159
- data/lib/hecks/projections/glossary.rb +30 -222
- data/lib/hecks/projections/ir.rb +3 -10
- data/lib/hecks/projections/model/deviations.rb +15 -42
- data/lib/hecks/projections/model.rb +12 -51
- data/lib/hecks/projections/oidc.rb +12 -56
- data/lib/hecks/projections/parser_table.rb +9 -28
- data/lib/hecks/projections/reference.rb +9 -16
- data/lib/hecks/projections/rust_vocabulary.rb +12 -250
- data/lib/hecks/projections/shape.rb +3 -29
- data/lib/hecks/projections/statements.rb +7 -86
- data/lib/hecks/projections/vocabulary.rb +6 -22
- data/lib/hecks/projections.rb +2 -16
- data/lib/hecks/projector/cli_projector.rb +60 -375
- data/lib/hecks/projector/docs_projector.rb +10 -201
- data/lib/hecks/projector/exporter.rb +46 -138
- data/lib/hecks/projector/ir_projector.rb +2 -9
- data/lib/hecks/projector/narrate_projector.rb +15 -189
- data/lib/hecks/projector/target.rb +13 -76
- data/lib/hecks/projector.rb +30 -121
- data/lib/hecks/query_specification/common/comparators.rb +5 -26
- data/lib/hecks/query_specification/common/comparison.rb +35 -143
- data/lib/hecks/query_specification/common/dsl.rb +8 -24
- data/lib/hecks/query_specification/common/null_policy.rb +20 -70
- data/lib/hecks/query_specification/common/options.rb +2 -6
- data/lib/hecks/query_specification/common/where_clause.rb +2 -10
- data/lib/hecks/query_specification/field_path.rb +37 -77
- data/lib/hecks/query_specification/hop_path.rb +12 -76
- data/lib/hecks/release/gem_pin.rb +2 -26
- data/lib/hecks/release/runner/ci_publisher.rb +93 -0
- data/lib/hecks/release/runner/commands.rb +66 -0
- data/lib/hecks/release/runner/console.rb +52 -0
- data/lib/hecks/release/runner/gem_publisher.rb +43 -0
- data/lib/hecks/release/runner/git.rb +48 -0
- data/lib/hecks/release/runner/npm_publisher.rb +75 -0
- data/lib/hecks/release/runner/preflight.rb +104 -0
- data/lib/hecks/release/runner/published.rb +55 -0
- data/lib/hecks/release/runner/tagger.rb +80 -0
- data/lib/hecks/release/runner.rb +215 -0
- data/lib/hecks/rendering.rb +4 -26
- data/lib/hecks/router/namespace_installer.rb +12 -36
- data/lib/hecks/router.rb +4 -8
- data/lib/hecks/runtime/aggregate_lock.rb +8 -33
- data/lib/hecks/runtime/boot_gates.rb +3 -18
- data/lib/hecks/runtime/caller.rb +19 -59
- data/lib/hecks/runtime/capability_graph.rb +5 -21
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +16 -78
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +23 -160
- data/lib/hecks/runtime/command_interpreter.rb +125 -307
- data/lib/hecks/runtime/command_rules/admissibility.rb +95 -366
- data/lib/hecks/runtime/command_rules/arithmetic.rb +66 -196
- data/lib/hecks/runtime/command_rules/authorization.rb +13 -45
- data/lib/hecks/runtime/command_rules/emission.rb +8 -21
- data/lib/hecks/runtime/command_rules/references.rb +23 -202
- data/lib/hecks/runtime/dependency_planning.rb +30 -102
- data/lib/hecks/runtime/dispatcher.rb +82 -241
- data/lib/hecks/runtime/entity_element.rb +40 -462
- data/lib/hecks/runtime/entity_interpreter.rb +65 -220
- data/lib/hecks/runtime/errors.rb +32 -115
- data/lib/hecks/runtime/event.rb +3 -25
- data/lib/hecks/runtime/identity.rb +18 -154
- data/lib/hecks/runtime/instance.rb +18 -150
- data/lib/hecks/runtime/interpreting.rb +11 -70
- data/lib/hecks/runtime/invocation.rb +28 -164
- data/lib/hecks/runtime/loader.rb +48 -186
- data/lib/hecks/runtime/outbox.rb +38 -261
- data/lib/hecks/runtime/policy_interpreter.rb +38 -200
- data/lib/hecks/runtime/port_operation_interpreter.rb +26 -87
- data/lib/hecks/runtime/query_interpreter.rb +45 -187
- data/lib/hecks/runtime/reaction_invocation.rb +36 -138
- data/lib/hecks/runtime/read_model_interpreter.rb +139 -208
- data/lib/hecks/runtime/rebuild_sweep.rb +8 -54
- data/lib/hecks/runtime/reference_hop.rb +8 -81
- data/lib/hecks/runtime/refusal_wording.rb +8 -89
- data/lib/hecks/runtime/registry/saga_persistence.rb +10 -102
- data/lib/hecks/runtime/registry/verification.rb +52 -225
- data/lib/hecks/runtime/registry/world_defaults.rb +4 -53
- data/lib/hecks/runtime/registry.rb +103 -244
- data/lib/hecks/runtime/remote_dispatcher.rb +37 -152
- data/lib/hecks/runtime/routing.rb +4 -15
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +14 -61
- data/lib/hecks/runtime/saga_interpreter.rb +79 -263
- data/lib/hecks/runtime/saga_pending_dispatch.rb +2 -43
- data/lib/hecks/runtime/tenant_check.rb +6 -68
- data/lib/hecks/runtime/tenant_scope.rb +3 -28
- data/lib/hecks/runtime/value/admission.rb +16 -67
- data/lib/hecks/runtime/value/coercion.rb +155 -641
- data/lib/hecks/runtime/value/entity_list_coercion.rb +26 -219
- data/lib/hecks/runtime/value.rb +12 -84
- data/lib/hecks/runtime.rb +17 -65
- data/lib/hecks/storehouse.rb +146 -567
- data/lib/hecks/tenancy/bluebook/tenancy.bluebook +8 -32
- data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +6 -23
- data/lib/hecks/vendoring/git_environment.rb +2 -8
- data/lib/hecks/vendoring/git_source.rb +4 -10
- data/lib/hecks/vendoring.rb +7 -46
- data/lib/hecks/version.rb +3 -14
- data/lib/hecks/vocabulary.rb +5 -0
- data/lib/hecks.rb +32 -82
- data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +8 -46
- data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +11 -80
- data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +10 -99
- metadata +30 -59
- data/lib/hecks/bench/cli.rb +0 -74
- data/lib/hecks/bench/environment.rb +0 -100
- data/lib/hecks/bench/postgres_probe.rb +0 -41
- data/lib/hecks/bench/report.rb +0 -116
- data/lib/hecks/bench/ruby_runner.rb +0 -151
- data/lib/hecks/bench/run.rb +0 -55
- data/lib/hecks/bench/rust_runner.rb +0 -165
- data/lib/hecks/bench/stats.rb +0 -75
- data/lib/hecks/bench/suite.rb +0 -172
- data/lib/hecks/bench/workload.rb +0 -137
- data/lib/hecks/bench.rb +0 -28
- data/lib/hecks/codemod.rb +0 -443
- data/lib/hecks/corpus.rb +0 -479
- data/lib/hecks/doc/reference.rb +0 -585
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +0 -684
- data/lib/hecks/fuzzing/combination_miner.rb +0 -178
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +0 -469
- data/lib/hecks/fuzzing/coverage_campaign.rb +0 -161
- data/lib/hecks/fuzzing/differential.rb +0 -192
- data/lib/hecks/fuzzing/domain_generator.rb +0 -871
- data/lib/hecks/fuzzing/era_boundary.rb +0 -154
- data/lib/hecks/fuzzing/form_census.rb +0 -285
- data/lib/hecks/fuzzing/generated_domain_check.rb +0 -171
- data/lib/hecks/fuzzing/invalid_value_generator.rb +0 -125
- data/lib/hecks/fuzzing/isolated_boot.rb +0 -658
- data/lib/hecks/fuzzing/nondeterministic.rb +0 -79
- data/lib/hecks/fuzzing/persistence_parity.rb +0 -253
- data/lib/hecks/fuzzing/properties/corrections.rb +0 -125
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +0 -688
- data/lib/hecks/fuzzing/properties/guards.rb +0 -398
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +0 -399
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +0 -137
- data/lib/hecks/fuzzing/properties/outbox.rb +0 -180
- data/lib/hecks/fuzzing/properties/querying.rb +0 -260
- data/lib/hecks/fuzzing/properties.rb +0 -267
- data/lib/hecks/fuzzing/qa_settings.rb +0 -164
- data/lib/hecks/fuzzing/replay.rb +0 -930
- data/lib/hecks/fuzzing/rotation_priority.rb +0 -114
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +0 -139
- data/lib/hecks/fuzzing/self_consistency.rb +0 -825
- data/lib/hecks/fuzzing/sequence_generator/adversary.rb +0 -532
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +0 -171
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +0 -127
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +0 -116
- data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +0 -138
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +0 -344
- data/lib/hecks/fuzzing/sequence_generator.rb +0 -311
- data/lib/hecks/fuzzing/shrinker.rb +0 -309
- data/lib/hecks/fuzzing/structural_skips.rb +0 -53
- data/lib/hecks/fuzzing/sweep_depth.rb +0 -61
- data/lib/hecks/fuzzing/target_capabilities.rb +0 -255
- data/lib/hecks/fuzzing/value_generator.rb +0 -340
- data/lib/hecks/fuzzing.rb +0 -23
- data/lib/hecks/grammar/evolve.rb +0 -524
- data/lib/hecks/query_ir.rb +0 -482
|
@@ -5,27 +5,8 @@ require "uri"
|
|
|
5
5
|
module Hecks
|
|
6
6
|
module Runtime
|
|
7
7
|
module EraCheck
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
# it with an allow-list file of the eras that should be running.
|
|
11
|
-
#
|
|
12
|
-
# `EraCheck.check!` decides at boot, against the store, whether a host may
|
|
13
|
-
# run on an era. This answers the question after a roll, from outside:
|
|
14
|
-
# did the host that came up report an era the operator expects? The two
|
|
15
|
-
# never share state. The host's own `GET /version` document
|
|
16
|
-
# (`rust/host/src/server.rs`, `version_body`) is the only input, so a
|
|
17
|
-
# rollback to an older image, or a fork of the journal back onto an older
|
|
18
|
-
# era, shows up here as an era missing from the list.
|
|
19
|
-
#
|
|
20
|
-
# ## The allow-list file
|
|
21
|
-
#
|
|
22
|
-
# One era id per line. Blank lines and lines starting with `#` are
|
|
23
|
-
# ignored, and so is a trailing ` # comment`. A file that lists no era
|
|
24
|
-
# means "only check that the host reports one", so a first roll can be
|
|
25
|
-
# checked before any era id is known. The generated `expected-era` file
|
|
26
|
-
# (`Deploy::Scripts`) has this shape.
|
|
27
|
-
#
|
|
28
|
-
# `bin/check_era` is the command-line wrapper.
|
|
8
|
+
# Compares a running host's reported era (`GET /version`) against an
|
|
9
|
+
# allow-list file of eras that should be running, for use after a roll.
|
|
29
10
|
module ExpectedEra
|
|
30
11
|
# The host could not be reached, or did not answer with a `200`.
|
|
31
12
|
class Unreachable < StandardError; end
|
|
@@ -36,7 +17,7 @@ module Hecks
|
|
|
36
17
|
# What a comparison concluded.
|
|
37
18
|
#
|
|
38
19
|
# @!attribute [r] status
|
|
39
|
-
# @return [Symbol] `:match`, `:unlisted` (no era
|
|
20
|
+
# @return [Symbol] `:match`, `:unlisted` (no era listed) or `:mismatch`
|
|
40
21
|
# @!attribute [r] era
|
|
41
22
|
# @return [String] the era the host reported
|
|
42
23
|
# @!attribute [r] allowed
|
|
@@ -6,11 +6,7 @@ module Hecks
|
|
|
6
6
|
module Ports
|
|
7
7
|
module Persistence
|
|
8
8
|
# Translates a journal entry written under an old shape into the one
|
|
9
|
-
# the current bluebook declares
|
|
10
|
-
# aggregate, or a field crossing a value-object boundary. Applied
|
|
11
|
-
# wherever entries are read, so replay derives the current head from
|
|
12
|
-
# history that was never rewritten — the port owns the meaning,
|
|
13
|
-
# adapters stay oblivious.
|
|
9
|
+
# the current bluebook declares; replay derives the head from unrewritten history.
|
|
14
10
|
class Lineage
|
|
15
11
|
# `ancestor_name` is the declared name a rename came from (matches
|
|
16
12
|
# the held bluebook's own aggregate names); `ancestor_storage_name`
|
|
@@ -24,8 +20,8 @@ module Hecks
|
|
|
24
20
|
# searched, in declaration order
|
|
25
21
|
# @param domain [String, Symbol] name of the domain the aggregate belongs to
|
|
26
22
|
# @param aggregate [Bluebook::Aggregate] the aggregate as currently declared
|
|
27
|
-
# @return [Ports::Persistence::Lineage, nil] the
|
|
28
|
-
#
|
|
23
|
+
# @return [Ports::Persistence::Lineage, nil] the first translation for `domain` naming
|
|
24
|
+
# the aggregate; nil when none does
|
|
29
25
|
def self.for(registry, domain, aggregate)
|
|
30
26
|
translation = registry.translations.find do |candidate|
|
|
31
27
|
candidate.domain == domain.to_s && candidate.for_aggregate(aggregate.name)
|
|
@@ -37,9 +33,8 @@ module Hecks
|
|
|
37
33
|
|
|
38
34
|
# Builds the rules one declared translation edge carries for one aggregate.
|
|
39
35
|
#
|
|
40
|
-
#
|
|
41
|
-
#
|
|
42
|
-
# edge in the registry mentioned the aggregate first.
|
|
36
|
+
# Unlike `for`, this uses one specific edge, not whichever edge in
|
|
37
|
+
# the registry mentions the aggregate first — what the mint path needs.
|
|
43
38
|
#
|
|
44
39
|
# @param declared [Bluebook::TranslationAggregate, nil] the edge's entry for the
|
|
45
40
|
# aggregate, as `Bluebook::Translation#for_aggregate` returns it; nil when the edge
|
|
@@ -60,24 +55,16 @@ module Hecks
|
|
|
60
55
|
ancestor_name: ancestor_name, ancestor_storage_name: ancestor_storage_name)
|
|
61
56
|
end
|
|
62
57
|
|
|
63
|
-
# @param renames [Hash{Symbol => Symbol}] old
|
|
64
|
-
# @param moves [Array<Bluebook::TranslationMove>]
|
|
65
|
-
#
|
|
66
|
-
# @param
|
|
67
|
-
#
|
|
68
|
-
# @param
|
|
69
|
-
# @param
|
|
70
|
-
#
|
|
71
|
-
# @param
|
|
72
|
-
#
|
|
73
|
-
# @param rekeys [Array<Bluebook::TranslationRekey>] SQL-only identity rewrites; only
|
|
74
|
-
# the first is read
|
|
75
|
-
# @param backfills [Array<Bluebook::TranslationBackfill>] defaults for new top-level
|
|
76
|
-
# attributes an old entry lacks
|
|
77
|
-
# @param ancestor_name [String, nil] the aggregate's declared name before the edge;
|
|
78
|
-
# nil unless the edge renames the aggregate itself
|
|
79
|
-
# @param ancestor_storage_name [String, nil] snake_case storage name of
|
|
80
|
-
# `ancestor_name`; nil unless the edge renames the aggregate itself
|
|
58
|
+
# @param renames [Hash{Symbol => Symbol}] old attribute name to new name
|
|
59
|
+
# @param moves [Array<Bluebook::TranslationMove>] from/to paths across a value object
|
|
60
|
+
# @param converts [Array<Bluebook::TranslationConvert>] moves mapped through a values table
|
|
61
|
+
# @param drops [Array<Symbol>] bare or dotted paths whose data is discarded
|
|
62
|
+
# @param retypes [Array<Bluebook::TranslationRetype>] type names meaning the same shape
|
|
63
|
+
# @param computes [Array<Bluebook::TranslationCompute>] SQL-only rules, never applied here
|
|
64
|
+
# @param rekeys [Array<Bluebook::TranslationRekey>] SQL rewrites; only the first is read
|
|
65
|
+
# @param backfills [Array<Bluebook::TranslationBackfill>] defaults for a new attribute
|
|
66
|
+
# @param ancestor_name [String, nil] the aggregate's name before the edge, if renamed
|
|
67
|
+
# @param ancestor_storage_name [String, nil] snake_case storage name of ancestor_name
|
|
81
68
|
def initialize(renames, moves = [], converts = [], drops = [], retypes: [], computes: [], rekeys: [],
|
|
82
69
|
backfills: [], ancestor_name: nil, ancestor_storage_name: nil)
|
|
83
70
|
@renames = renames
|
|
@@ -94,54 +81,39 @@ module Hecks
|
|
|
94
81
|
|
|
95
82
|
# Reports whether any rule in this edge is a compute.
|
|
96
83
|
#
|
|
97
|
-
# Compute
|
|
98
|
-
#
|
|
99
|
-
# Postgres, per-rule and by name, before the general drift
|
|
100
|
-
# machinery says anything vaguer.
|
|
84
|
+
# Compute has no in-process implementation; an aggregate carrying
|
|
85
|
+
# one refuses to boot anywhere but Postgres.
|
|
101
86
|
#
|
|
102
87
|
# @return [Boolean] true when the edge declares at least one compute rule
|
|
103
88
|
def computes? = !@computes.empty?
|
|
104
89
|
|
|
105
90
|
# Reports whether this edge rewrites the aggregate's identity.
|
|
106
91
|
#
|
|
107
|
-
# The single source of truth for
|
|
108
|
-
#
|
|
109
|
-
# minter.rb's approval gate, layer_two.rb's audit, head_compiler.rb's
|
|
110
|
-
# SQL compilation) asks this, never re-derives it from `declared`
|
|
111
|
-
# independently. One accessor to change if what a rekey rule means
|
|
112
|
-
# ever needs to change, not four call sites in four files.
|
|
92
|
+
# The single source of truth for this; other call sites ask here
|
|
93
|
+
# rather than re-deriving it from `declared` themselves.
|
|
113
94
|
#
|
|
114
95
|
# @return [Boolean] true when the edge declares at least one rekey rule
|
|
115
96
|
def rekey? = !@rekeys.empty?
|
|
116
97
|
|
|
117
98
|
# Returns the SQL expression the edge's first rekey rule declares.
|
|
118
99
|
#
|
|
119
|
-
#
|
|
120
|
-
#
|
|
121
|
-
# (an edge with more than one is a DSL-level decision, not
|
|
122
|
-
# something this reader arbitrates).
|
|
100
|
+
# Only the first rule is read, the same one-per-aggregate assumption
|
|
101
|
+
# `compute` makes; more than one is a DSL-level decision to arbitrate elsewhere.
|
|
123
102
|
#
|
|
124
103
|
# @return [String, nil] the first rekey rule's SQL; nil when the edge declares no rekey
|
|
125
104
|
def rekey_sql = @rekeys.first&.sql
|
|
126
105
|
|
|
127
106
|
# Rewrites one journal entry's state from the held shape into the current one.
|
|
128
107
|
#
|
|
129
|
-
# The reference semantics for
|
|
130
|
-
#
|
|
131
|
-
# `retype` moves nothing (stored state never carries a type name)
|
|
132
|
-
# and `compute` is deliberately not applied here: its SQL is its
|
|
133
|
-
# only implementation, so this transform neither imitates nor
|
|
134
|
-
# checks it — the source field passes through untouched, and the
|
|
135
|
-
# audit verifies compute output against the matview alone.
|
|
108
|
+
# The reference semantics for rename, move, convert, drop, and the aggregate-level `was:`.
|
|
109
|
+
# `compute` is not applied here — its SQL is the only implementation, audited separately.
|
|
136
110
|
#
|
|
137
|
-
# @param entry [Ports::Persistence::Entry] the entry as stored
|
|
138
|
-
# top-level keys and String keys
|
|
139
|
-
# @return [Ports::Persistence::Entry] a new entry with
|
|
140
|
-
#
|
|
141
|
-
#
|
|
142
|
-
#
|
|
143
|
-
# table, or a move or convert would nest under a destination already holding a
|
|
144
|
-
# non-Hash value
|
|
111
|
+
# @param entry [Ports::Persistence::Entry] the entry as stored, with Symbol
|
|
112
|
+
# top-level keys and String keys nested in a value-object Hash
|
|
113
|
+
# @return [Ports::Persistence::Entry] a new entry with translated state and the same
|
|
114
|
+
# `operation`, `id` and `mirrors`; `entry` itself when it is not a save or has no state
|
|
115
|
+
# @raise [Runtime::WiringError] if a convert value is missing from its `values` table, or a
|
|
116
|
+
# move/convert would nest under a destination already holding a non-Hash value
|
|
145
117
|
def translate(entry)
|
|
146
118
|
return entry unless entry.save? && entry.state
|
|
147
119
|
|
|
@@ -153,45 +125,18 @@ module Hecks
|
|
|
153
125
|
@moves.each { |move| apply_move(state, move) }
|
|
154
126
|
@converts.each { |convert| apply_convert(state, convert) }
|
|
155
127
|
@drops.each { |name| apply_drop(state, name) }
|
|
156
|
-
#
|
|
157
|
-
# fills the gap a rename/move/convert left untouched, never
|
|
158
|
-
# overwrites a value that already made it across. Dotted-path
|
|
159
|
-
# aware, same as `apply_drop` above (`apply_backfill`'s own
|
|
160
|
-
# header) — a bare name was the only shape this ever needed
|
|
161
|
-
# until a value object gained new required members with zero
|
|
162
|
-
# source data of their own (found live: a client site's Attendee
|
|
163
|
-
# redesign, commit 4326dcd).
|
|
128
|
+
# Only fills a gap nothing else already filled; dotted-path aware, like apply_drop.
|
|
164
129
|
@backfills.each { |backfill| apply_backfill(state, backfill) }
|
|
165
130
|
Entry.new(operation: entry.operation, id: entry.id, state: state, mirrors: entry.mirrors)
|
|
166
131
|
end
|
|
167
132
|
|
|
168
133
|
# Reports whether some rule accounts for a held path that vanished or changed type.
|
|
169
134
|
#
|
|
170
|
-
#
|
|
171
|
-
#
|
|
172
|
-
#
|
|
173
|
-
# member ("price.currency"); a rule covering the whole top-level
|
|
174
|
-
# attribute (a rename, a top-level move/convert/drop) also covers
|
|
175
|
-
# anything nested under it, since the whole value travels or goes
|
|
176
|
-
# away together. This is what catches a field — or a value object's
|
|
177
|
-
# own member — that vanished (or silently changed type) without
|
|
178
|
-
# anything explaining it, even when some other field is covered.
|
|
135
|
+
# A rule covering a whole top-level attribute also covers anything nested
|
|
136
|
+
# under it; `backfills` only matches a whole name, since a backfill adds an
|
|
137
|
+
# attribute that is new outright, never a path that existed and moved.
|
|
179
138
|
#
|
|
180
|
-
#
|
|
181
|
-
# prefix — a backfill names a top-level attribute that is new
|
|
182
|
-
# outright (nothing to be a prefix of on the held side), unlike
|
|
183
|
-
# every rule above it, which explains a path that existed and
|
|
184
|
-
# moved, converted, or vanished.
|
|
185
|
-
#
|
|
186
|
-
# One `||` chain over a closed, fixed set of rule kinds (renames,
|
|
187
|
-
# moves, converts, drops, computes, backfills) — the same six this
|
|
188
|
-
# file's other methods enumerate. Splitting each disjunct into its
|
|
189
|
-
# own predicate would scatter one question ("does any rule explain
|
|
190
|
-
# this path") across six same-shaped methods with nothing else to
|
|
191
|
-
# do.
|
|
192
|
-
#
|
|
193
|
-
# @param path [String, Symbol] a bare attribute name or a dotted value-object member
|
|
194
|
-
# path on the held side
|
|
139
|
+
# @param path [String, Symbol] a bare attribute name or a dotted value-object member path
|
|
195
140
|
# @return [Boolean] true when a rename, move, convert, drop or compute names the path or
|
|
196
141
|
# its top-level attribute as its source, or a backfill names the top-level attribute
|
|
197
142
|
# rubocop:disable-next Metrics/CyclomaticComplexity
|
|
@@ -210,32 +155,11 @@ module Hecks
|
|
|
210
155
|
|
|
211
156
|
# Reports whether some rule gives an existing record a value at a new attribute.
|
|
212
157
|
#
|
|
213
|
-
# The destination-side twin of `explains
|
|
214
|
-
#
|
|
215
|
-
#
|
|
216
|
-
# an existing record end up with a value here" — and a move or
|
|
217
|
-
# convert whose `to:` lands a old field inside a brand-new
|
|
218
|
-
# top-level attribute (`weight` becoming `contents.weight` when
|
|
219
|
-
# `Contents` did not exist before) fills that attribute for an
|
|
220
|
-
# existing record exactly as a `backfill` would, even though
|
|
221
|
-
# nothing named `contents` explains any vanished path. `compute`
|
|
222
|
-
# counts on the same terms `explains?` already grants it
|
|
223
|
-
# elsewhere in this file — Postgres-only and audited, not
|
|
224
|
-
# actually applied by this method, the same gap the vanish side
|
|
225
|
-
# already lives with.
|
|
158
|
+
# The destination-side twin of `explains?`, which checks a rule's source; this checks
|
|
159
|
+
# `@renames.value?` too, since a bare rename fills the destination unconditionally,
|
|
160
|
+
# the same way a backfill would.
|
|
226
161
|
#
|
|
227
|
-
#
|
|
228
|
-
# `rename :cost, to: :amount` is the plainest possible covering
|
|
229
|
-
# rule there is (`translate` above applies it unconditionally, no
|
|
230
|
-
# lookup table, no per-record ambiguity — simpler than a move or
|
|
231
|
-
# convert), and without it `unsafe_additions` reports the new name
|
|
232
|
-
# as an unexplained required addition on every rename-only edge,
|
|
233
|
-
# the single most common translation shape there is. `explains?`
|
|
234
|
-
# checks the source side (`@renames.key?`); this is the symmetric
|
|
235
|
-
# destination-side check.
|
|
236
|
-
#
|
|
237
|
-
# @param path [String, Symbol] the name of a top-level attribute new in the current
|
|
238
|
-
# shape
|
|
162
|
+
# @param path [String, Symbol] the name of a top-level attribute new in the current shape
|
|
239
163
|
# @return [Boolean] true when a rename, move, convert or compute lands a value in that
|
|
240
164
|
# attribute, or a backfill names it
|
|
241
165
|
def fills?(path)
|
|
@@ -250,15 +174,11 @@ module Hecks
|
|
|
250
174
|
|
|
251
175
|
# Reports whether a declared retype pairs two type names as the same shape.
|
|
252
176
|
#
|
|
253
|
-
#
|
|
254
|
-
#
|
|
255
|
-
# type name, so this never moves a value; it only satisfies the
|
|
256
|
-
# era diff's literal type-name comparison.
|
|
177
|
+
# Nothing in the stored data carries a type name, so this never moves a value;
|
|
178
|
+
# it only satisfies the era diff's literal type-name comparison.
|
|
257
179
|
#
|
|
258
|
-
# @param held_type [String, Bluebook::Reference] the type the held era declares
|
|
259
|
-
#
|
|
260
|
-
# @param current_type [String, Bluebook::Reference] the type declared now, compared by
|
|
261
|
-
# its `to_s`
|
|
180
|
+
# @param held_type [String, Bluebook::Reference] the type the held era declares
|
|
181
|
+
# @param current_type [String, Bluebook::Reference] the type declared now
|
|
262
182
|
# @return [Boolean] true when some retype rule runs from `held_type` to `current_type`
|
|
263
183
|
def retype?(held_type, current_type)
|
|
264
184
|
@retypes.any? { |retype| retype.from == held_type.to_s && retype.to == current_type.to_s }
|
|
@@ -274,30 +194,14 @@ module Hecks
|
|
|
274
194
|
end
|
|
275
195
|
end
|
|
276
196
|
|
|
277
|
-
#
|
|
278
|
-
#
|
|
279
|
-
#
|
|
280
|
-
# one rule at a time against the same hash it was reading from,
|
|
281
|
-
# loses data the instant one rule's destination is another
|
|
282
|
-
# rule's source. Applied sequentially, a swap (`rename :a, to: :b`
|
|
283
|
-
# alongside `rename :b, to: :a`) on `{a: 1, b: 2}` produces
|
|
284
|
-
# `{a: 1}` — the first rule writes `b: 1` over the real `b: 2`
|
|
285
|
-
# before the second rule ever gets a chance to read it, and the
|
|
286
|
-
# value the whole edge is supposed to preserve (2, moved to
|
|
287
|
-
# `:a`) is gone. The standard fix: snapshot every rule's old
|
|
288
|
-
# key and value from `state` first, then remove every old key
|
|
289
|
-
# and only then write every new key — a rename never reads a
|
|
290
|
-
# key this same pass has already written to, so a swap or a
|
|
291
|
-
# longer chain applies as one permutation, not a sequence of
|
|
292
|
-
# edits each stepping on the last.
|
|
197
|
+
# Snapshots every rename's old key/value before writing any new key, so a
|
|
198
|
+
# swap (:a<->:b) applies as one permutation instead of losing data when one
|
|
199
|
+
# rule's destination is another's source.
|
|
293
200
|
def apply_renames(state, renames)
|
|
294
201
|
snapshot = renames.filter_map { |old_name, new_name| [old_name, new_name, state[old_name]] if state.key?(old_name) }
|
|
295
202
|
snapshot.each { |old_name, _new_name, _value| state.delete(old_name) }
|
|
296
|
-
# Not combinable
|
|
297
|
-
#
|
|
298
|
-
# every delete done before any write, or the first rename's write
|
|
299
|
-
# becomes the second rename's delete target — see this method's
|
|
300
|
-
# own comment above.
|
|
203
|
+
# Not combinable: every delete must finish before any write, or a swap's
|
|
204
|
+
# first write becomes its second delete target.
|
|
301
205
|
snapshot.each { |_old_name, new_name, value| state[new_name] = value }
|
|
302
206
|
end
|
|
303
207
|
|
|
@@ -317,18 +221,7 @@ module Hecks
|
|
|
317
221
|
end
|
|
318
222
|
end
|
|
319
223
|
|
|
320
|
-
#
|
|
321
|
-
# mirror on the addition side. A bare name sets a plain top-level
|
|
322
|
-
# key, unchanged from before; a dotted name (`"attendee.
|
|
323
|
-
# first_name"`) reaches into an existing value-object member the
|
|
324
|
-
# same way `apply_drop`/`hecks_tr_insert` (rule_compiler.rb's own
|
|
325
|
-
# SQL-compiled twin, kept in step with this) already do — creating
|
|
326
|
-
# the container Hash if an old record somehow lacks it entirely,
|
|
327
|
-
# never overwriting a value already there at either level.
|
|
328
|
-
#
|
|
329
|
-
# @param state [Hash] the entry's own state Hash, mutated in place
|
|
330
|
-
# @param backfill [Bluebook::TranslationBackfill] the backfill rule to apply
|
|
331
|
-
# @return [void]
|
|
224
|
+
# Dotted-path aware; must stay in step with `hecks_tr_insert` in rule_compiler.rb.
|
|
332
225
|
def apply_backfill(state, backfill)
|
|
333
226
|
name = backfill.name.to_s
|
|
334
227
|
top, member = name.split(".", 2)
|
|
@@ -342,17 +235,8 @@ module Hecks
|
|
|
342
235
|
end
|
|
343
236
|
end
|
|
344
237
|
|
|
345
|
-
#
|
|
346
|
-
#
|
|
347
|
-
# key — the spelling a raw stored row carries. Translation runs on
|
|
348
|
-
# raw rows, before the state codec decodes anything (PR A3): its
|
|
349
|
-
# only caller (`Translation::Audit::LayerTwo`) feeds it
|
|
350
|
-
# head-snapshot rows straight out of `JSON.parse`, and the
|
|
351
|
-
# PostgresEra head applies the same rules in SQL before
|
|
352
|
-
# `PostgresEra#decode` ever sees the jsonb. Decode is always the
|
|
353
|
-
# last step, so an undeclared (retired) member this rule has to
|
|
354
|
-
# read is still exactly as it was written, and never something an
|
|
355
|
-
# adapter's `entries` — decoded, deep-symbol — would be fed here.
|
|
238
|
+
# Runs on raw rows, before the state codec decodes anything — decode is
|
|
239
|
+
# always the last step, so this never sees an adapter's deep-symbolized entry.
|
|
356
240
|
def apply_move(state, move)
|
|
357
241
|
old_top, old_member = move.from.split(".", 2)
|
|
358
242
|
new_top, new_member = move.to.split(".", 2)
|
|
@@ -364,9 +248,8 @@ module Hecks
|
|
|
364
248
|
insert(state, new_top.to_sym, new_member, value, rule: "move #{move.from} to: #{move.to}")
|
|
365
249
|
end
|
|
366
250
|
|
|
367
|
-
# A convert is a move whose value has nothing in common with its
|
|
368
|
-
#
|
|
369
|
-
# with no entry in the table refuses loudly rather than carry an
|
|
251
|
+
# A convert is a move whose value has nothing in common with its replacement.
|
|
252
|
+
# A value missing from the lookup table refuses loudly rather than carry an
|
|
370
253
|
# unrecognized value silently into the new era.
|
|
371
254
|
def apply_convert(state, convert)
|
|
372
255
|
old_top, old_member = convert.from.split(".", 2)
|
|
@@ -397,18 +280,9 @@ module Hecks
|
|
|
397
280
|
[value, true]
|
|
398
281
|
end
|
|
399
282
|
|
|
400
|
-
#
|
|
401
|
-
#
|
|
402
|
-
#
|
|
403
|
-
# dotted destination needs it (`state[top] ||= {}` alone only
|
|
404
|
-
# guards nil/false, so a truthy non-Hash sails straight through
|
|
405
|
-
# to `state[top][member] =`, i.e. `"team-1"["detail"] =`, which
|
|
406
|
-
# is String#[]= and raises an unrelated-looking IndexError).
|
|
407
|
-
# Whether it crashes or silently replaces the value, that is a
|
|
408
|
-
# `drop` that never declared itself — the one thing this language
|
|
409
|
-
# exists to make explicit (see apply_convert's own refusal above,
|
|
410
|
-
# the same shape). Refuse by name instead, on both sides: the SQL
|
|
411
|
-
# half (hecks_tr_insert) raises the identical wording.
|
|
283
|
+
# A destination already holding a non-Hash value (e.g. a bare reference id)
|
|
284
|
+
# must not be silently nested under — that would be an undeclared drop. The
|
|
285
|
+
# SQL half (`hecks_tr_insert`) refuses with identical wording.
|
|
412
286
|
def insert(state, top, member, value, rule:)
|
|
413
287
|
return state[top] = value unless member
|
|
414
288
|
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
module Hecks
|
|
2
|
+
module Adapters
|
|
3
|
+
class PostgresEra
|
|
4
|
+
# The shared `events` table: every domain's aggregates journal their emitted events
|
|
5
|
+
# into it, keyed by `aggregate` ("domain::AggregateName") and `aggregate_id`.
|
|
6
|
+
module Events
|
|
7
|
+
# Stores one emitted event in the `events` table, shared by every aggregate on this
|
|
8
|
+
# database and schema.
|
|
9
|
+
#
|
|
10
|
+
# @param event [Runtime::Event] the event to record; `correlation` is not stored
|
|
11
|
+
# @return [PG::Result] the INSERT's result
|
|
12
|
+
def record_event(event)
|
|
13
|
+
@db.exec_params(
|
|
14
|
+
"INSERT INTO events (name, aggregate, aggregate_id, payload, occurred_at) VALUES ($1, $2, $3, $4, $5)",
|
|
15
|
+
[event.name, event.aggregate, event.id.to_s, JSON.generate(event.payload), event.occurred_at]
|
|
16
|
+
)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Reads every recorded event in the order recorded, across all aggregates.
|
|
20
|
+
#
|
|
21
|
+
# @return [Array<Runtime::Event>] events with symbol-keyed `payload` and `correlation` nil
|
|
22
|
+
def events
|
|
23
|
+
@db.exec("SELECT * FROM events ORDER BY id").map do |row|
|
|
24
|
+
Runtime::Event.new(
|
|
25
|
+
name: row["name"],
|
|
26
|
+
aggregate: row["aggregate"],
|
|
27
|
+
id: row["aggregate_id"],
|
|
28
|
+
payload: JSON.parse(row["payload"], symbolize_names: true),
|
|
29
|
+
occurred_at: row["occurred_at"]
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Reads back one record's recorded events, oldest first — pushed down as a `WHERE`
|
|
35
|
+
# clause (`hecks_events_aggregate_id_idx`) instead of filtering `#events`'s whole-table
|
|
36
|
+
# read, since a `corrects` command's history lookup only ever needs this one record.
|
|
37
|
+
#
|
|
38
|
+
# @param aggregate [String] the `"domain::AggregateName"` key events are stored under
|
|
39
|
+
# @param id [String, Object] the record's identity, matched as `id.to_s`
|
|
40
|
+
# @return [Array<Runtime::Event>] the record's stored events; `[]` when it has none
|
|
41
|
+
def events_for(aggregate:, id:)
|
|
42
|
+
@db.exec_params(
|
|
43
|
+
"SELECT * FROM events WHERE aggregate = $1 AND aggregate_id = $2 ORDER BY id",
|
|
44
|
+
[aggregate, id.to_s]
|
|
45
|
+
).map do |row|
|
|
46
|
+
Runtime::Event.new(
|
|
47
|
+
name: row["name"],
|
|
48
|
+
aggregate: row["aggregate"],
|
|
49
|
+
id: row["aggregate_id"],
|
|
50
|
+
payload: JSON.parse(row["payload"], symbolize_names: true),
|
|
51
|
+
occurred_at: row["occurred_at"]
|
|
52
|
+
)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def create_event_table!
|
|
59
|
+
@db.exec(<<~SQL)
|
|
60
|
+
CREATE TABLE IF NOT EXISTS events (
|
|
61
|
+
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
62
|
+
name text NOT NULL,
|
|
63
|
+
aggregate text NOT NULL,
|
|
64
|
+
aggregate_id text NOT NULL,
|
|
65
|
+
payload jsonb,
|
|
66
|
+
occurred_at text
|
|
67
|
+
)
|
|
68
|
+
SQL
|
|
69
|
+
# Backs #events_for's per-record lookup (a `corrects` command's history read).
|
|
70
|
+
@db.exec(
|
|
71
|
+
"CREATE INDEX IF NOT EXISTS hecks_events_aggregate_id_idx ON events (aggregate, aggregate_id)"
|
|
72
|
+
)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|