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
|
@@ -2,37 +2,13 @@ require "json"
|
|
|
2
2
|
|
|
3
3
|
module Hecks
|
|
4
4
|
module Translation
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
# — the part that turns one TranslationAggregate's declared rules into
|
|
8
|
-
# a jsonb-transforming SQL expression. No database connection, no
|
|
9
|
-
# watermark, no era chain, no catalog lookup: those live in
|
|
10
|
-
# head_compiler.rb's own per-mint assembly, which calls into this
|
|
11
|
-
# module instead of defining these methods itself.
|
|
12
|
-
#
|
|
13
|
-
# A module of its own — not private methods on
|
|
14
|
-
# Adapters::PostgresEra::Lineage — so a second, adapter-agnostic
|
|
15
|
-
# caller (Exporter.translation_aggregate's build-time SQL export,
|
|
16
|
-
# feeding rust/host's own future boot-time mint) can call the exact
|
|
17
|
-
# same code Ruby's own mint path runs, not a hand-ported duplicate
|
|
18
|
-
# that could silently drift the way a hand-kept
|
|
19
|
-
# `Exporter.translation_hash` can drift from `hecks_eras`/
|
|
20
|
-
# `hecks_approvals`' real schema (leaving out rekeys and backfills).
|
|
5
|
+
# Compiles one TranslationAggregate's declared rules into a jsonb-transforming SQL
|
|
6
|
+
# expression, shared by Ruby's own mint path and any other SQL-emitting caller.
|
|
21
7
|
module RuleCompiler
|
|
22
8
|
module_function
|
|
23
9
|
|
|
24
|
-
#
|
|
25
|
-
# expression
|
|
26
|
-
# in the reference transform's phase order (renames, moves,
|
|
27
|
-
# converts, drops), computes last. `retype` compiles to nothing:
|
|
28
|
-
# stored state never carries a type name.
|
|
29
|
-
# Compiles a declared edge's rename/move/convert/drop/compute rules into one nested SQL
|
|
30
|
-
# expression over the `state` jsonb column.
|
|
31
|
-
#
|
|
32
|
-
# @param declared [Bluebook::TranslationAggregate] this edge's declared rules for one
|
|
33
|
-
# aggregate
|
|
34
|
-
# @return [String] a SQL expression, `"state"` unchanged when `declared` declares none
|
|
35
|
-
# of the five rule kinds
|
|
10
|
+
# Compiles one edge's rename/move/convert/drop/compute/backfill rules into a nested
|
|
11
|
+
# SQL expression over `state`, composed innermost-first in that phase order.
|
|
36
12
|
def compile_rules(declared)
|
|
37
13
|
expression = "state"
|
|
38
14
|
declared.renames.each do |old_name, new_name|
|
|
@@ -54,108 +30,47 @@ module Hecks
|
|
|
54
30
|
declared.computes.each do |compute|
|
|
55
31
|
expression = compile_compute(expression, compute)
|
|
56
32
|
end
|
|
57
|
-
#
|
|
58
|
-
#
|
|
59
|
-
# already answered") — now compiled here too, closing the gap
|
|
60
|
-
# this rule kind otherwise leaves: `rust/host`'s boot-time mint
|
|
61
|
-
# audit reads this exact compiled expression, never
|
|
62
|
-
# `Lineage#translate`, so it cannot see a backfilled value unless
|
|
63
|
-
# backfills compile to SQL like every other rule kind here. A
|
|
64
|
-
# real, live gap for any new required value-object member with no
|
|
65
|
-
# source data at all — `compute` cannot fill it either, since its
|
|
66
|
-
# own guard requires a real, already-present field to consume
|
|
67
|
-
# (found live: a client site's Attendee redesign, commit 4326dcd,
|
|
68
|
-
# needed exactly this and had nothing that worked).
|
|
33
|
+
# Backfilled last, same order as `Lineage#translate`'s in-process pass, so the
|
|
34
|
+
# boot-time mint audit (which reads only this compiled SQL) sees the same result.
|
|
69
35
|
declared.backfills.each do |backfill|
|
|
70
36
|
expression = compile_backfill(expression, backfill)
|
|
71
37
|
end
|
|
72
38
|
expression
|
|
73
39
|
end
|
|
74
40
|
|
|
75
|
-
#
|
|
76
|
-
#
|
|
77
|
-
# every other rule kind is already read in `compile_rules`
|
|
78
|
-
# (`declared.computes`, `declared.moves`, ...), not through the
|
|
79
|
-
# `Ports::Persistence::Lineage` wrapper the app-level consumers
|
|
80
|
-
# (coverage_check.rb, minter.rb, layer_two.rb) go through — this
|
|
81
|
-
# module builds SQL straight off the IR either way.
|
|
82
|
-
# Reports whether an edge's declared rules for an aggregate include a rekey.
|
|
83
|
-
#
|
|
84
|
-
# @param declared [Bluebook::TranslationAggregate, nil] this edge's declared rules for
|
|
85
|
-
# one aggregate; nil for an aggregate the edge declares nothing about
|
|
86
|
-
# @return [Boolean] true when `declared` is present and its `rekeys` is non-empty
|
|
41
|
+
# Reports whether an edge's declared rules for an aggregate include a rekey, read
|
|
42
|
+
# directly off the raw IR like every other rule kind `compile_rules` checks.
|
|
87
43
|
def rekeyed?(declared) = declared && !declared.rekeys.empty?
|
|
88
44
|
|
|
89
|
-
#
|
|
90
|
-
#
|
|
91
|
-
# declared) stays the bare `aggregate_id` passthrough it always
|
|
92
|
-
# was — this case only appears in an edge that actually declares
|
|
93
|
-
# one.
|
|
94
|
-
#
|
|
95
|
-
# @param guard [String] a SQL boolean expression gating when the rekey applies, such as
|
|
96
|
-
# `"operation = 'save'"`
|
|
97
|
-
# @param declared [Bluebook::TranslationAggregate] this edge's declared rules; must
|
|
98
|
-
# declare a rekey (`rekeyed?(declared)` true)
|
|
99
|
-
# @return [String] a `"CASE WHEN ... END AS aggregate_id"` SQL expression
|
|
45
|
+
# Builds a `CASE WHEN ... END AS aggregate_id` expression that only overrides
|
|
46
|
+
# `aggregate_id` when `guard` matches, leaving the common no-rekey case untouched.
|
|
100
47
|
def id_case(guard, declared)
|
|
101
48
|
"CASE WHEN #{guard} THEN #{compile_id_expression(declared)} ELSE aggregate_id END AS aggregate_id"
|
|
102
49
|
end
|
|
103
50
|
|
|
104
|
-
#
|
|
105
|
-
# progressively-built
|
|
106
|
-
# from. A rekey doesn't consume or move any field the way a move
|
|
107
|
-
# or compute does, so there is no same-edge rename/move ordering
|
|
108
|
-
# it needs to see first — it reads the record's stored fields
|
|
109
|
-
# exactly as they already are, the same `__s` convention
|
|
110
|
-
# `compile_compute` exposes.
|
|
111
|
-
#
|
|
112
|
-
# @param declared [Bluebook::TranslationAggregate] this edge's declared rules; its
|
|
113
|
-
# first `rekeys` entry supplies the SQL
|
|
114
|
-
# @return [String] a SQL expression evaluating the rekey's own SQL against the record's
|
|
115
|
-
# current `state`
|
|
51
|
+
# Evaluates a rekey's own SQL against the record's current `state`, read directly
|
|
52
|
+
# rather than through `compile_rules`'s progressively-built expression chain.
|
|
116
53
|
def compile_id_expression(declared)
|
|
117
54
|
rekey = declared.rekeys.first
|
|
118
55
|
"(SELECT (#{rekey.sql}) FROM (SELECT (state) AS __s) __outer)"
|
|
119
56
|
end
|
|
120
57
|
|
|
121
|
-
#
|
|
122
|
-
#
|
|
123
|
-
# in-process. The old field is exposed under its own name (as
|
|
124
|
-
# text, exactly as the author's expression expects to cast it).
|
|
125
|
-
#
|
|
126
|
-
# @param expression [String] the SQL expression built so far by `compile_rules`, read as
|
|
127
|
-
# `__s` inside the compute's own SQL
|
|
128
|
-
# @param compute [Bluebook::TranslationCompute] the declared compute rule
|
|
129
|
-
# @return [String] `expression` wrapped so the compute's field lands at its declared
|
|
130
|
-
# destination when the source field is present, unchanged otherwise
|
|
58
|
+
# Wraps `expression` so a compute's SQL result lands at its declared destination
|
|
59
|
+
# when the source path is present; the whole record stays readable as `__s`.
|
|
131
60
|
def compile_compute(expression, compute)
|
|
132
61
|
from = compute.from.to_s
|
|
133
62
|
to = compute.to.to_s
|
|
134
|
-
"(SELECT CASE WHEN
|
|
135
|
-
"hecks_tr_insert(
|
|
63
|
+
"(SELECT CASE WHEN (__x).present THEN " \
|
|
64
|
+
"hecks_tr_insert((__x).remaining, #{path_literal(to)}, to_jsonb((#{compute.sql})), " \
|
|
136
65
|
"#{text_literal("compute #{from} to: #{to}")}) " \
|
|
137
66
|
"ELSE __s END " \
|
|
138
67
|
"FROM (SELECT (#{expression}) AS __s) __outer, " \
|
|
139
|
-
"LATERAL (SELECT (__s
|
|
68
|
+
"LATERAL (SELECT hecks_tr_extract(__s, #{path_literal(from)}) AS __x) __extract, " \
|
|
69
|
+
"LATERAL (SELECT (__s #>> #{path_literal(from)}) AS #{quote(from)}) __fields)"
|
|
140
70
|
end
|
|
141
71
|
|
|
142
|
-
#
|
|
143
|
-
#
|
|
144
|
-
# no field to consume: `hecks_tr_extract`'s own `.present` flag
|
|
145
|
-
# (already installed for `hecks_tr_drop`/`hecks_tr_move`/
|
|
146
|
-
# `hecks_tr_convert` — no new database function needed) answers
|
|
147
|
-
# "is this path — bare or a dotted value-object member alike —
|
|
148
|
-
# already there," and `hecks_tr_insert` (already merge-safe: it
|
|
149
|
-
# creates a missing intermediate container without disturbing any
|
|
150
|
-
# sibling member already in it) fills it only when it is not, the
|
|
151
|
-
# exact "never overwrites a value already there" rule `Lineage#
|
|
152
|
-
# translate`'s own in-process backfill already holds itself to.
|
|
153
|
-
#
|
|
154
|
-
# @param expression [String] the SQL expression built so far by `compile_rules`, read as
|
|
155
|
-
# `__s` inside this backfill's own check
|
|
156
|
-
# @param backfill [Bluebook::TranslationBackfill] the declared backfill rule
|
|
157
|
-
# @return [String] `expression` wrapped so the backfill's default lands at its declared
|
|
158
|
-
# path when nothing is there yet, unchanged otherwise
|
|
72
|
+
# Wraps `expression` so a backfill's default lands at its declared path only when
|
|
73
|
+
# nothing is already there, the same rule `Lineage#translate`'s own pass holds to.
|
|
159
74
|
def compile_backfill(expression, backfill)
|
|
160
75
|
name = backfill.name.to_s
|
|
161
76
|
default_json = JSON.generate(backfill.default)
|
|
@@ -165,32 +80,17 @@ module Hecks
|
|
|
165
80
|
"FROM (SELECT (#{expression}) AS __s) __outer)"
|
|
166
81
|
end
|
|
167
82
|
|
|
168
|
-
#
|
|
169
|
-
#
|
|
170
|
-
# never wires PostgresEra should never need the gem" reasoning
|
|
171
|
-
# `PostgresEra.connect_for`'s own `require "pg"` already holds
|
|
172
|
-
# itself to, so a build tool that exports translations for a
|
|
173
|
-
# non-Postgres-bound domain (there are none today, but nothing
|
|
174
|
-
# here should assume there never will be) doesn't gain a hard
|
|
175
|
-
# dependency on `pg` just by loading this file.
|
|
176
|
-
#
|
|
177
|
-
# @param name [String, Symbol] the identifier to quote
|
|
178
|
-
# @return [String] `name` as a double-quoted Postgres identifier
|
|
83
|
+
# Quotes a Postgres identifier; requires "pg" lazily so a non-Postgres-bound
|
|
84
|
+
# domain never gains a hard dependency on the gem just by loading this file.
|
|
179
85
|
def quote(name)
|
|
180
86
|
require "pg"
|
|
181
87
|
PG::Connection.quote_ident(name.to_s)
|
|
182
88
|
end
|
|
183
89
|
|
|
184
90
|
# Renders a Ruby value as a single-quoted SQL text literal, escaping embedded quotes.
|
|
185
|
-
#
|
|
186
|
-
# @param text [String, Symbol, Object] the value to render; converted with `to_s`
|
|
187
|
-
# @return [String] a single-quoted SQL literal
|
|
188
91
|
def text_literal(text) = "'#{text.to_s.gsub("'", "''")}'"
|
|
189
92
|
|
|
190
93
|
# Renders a dotted path as a SQL `text[]` array literal, one element per segment.
|
|
191
|
-
#
|
|
192
|
-
# @param path [String, Symbol] a bare or dotted path, such as `"price.cents"`
|
|
193
|
-
# @return [String] a SQL `ARRAY[...]::text[]` expression
|
|
194
94
|
def path_literal(path)
|
|
195
95
|
segments = path.to_s.split(".").map { |segment| text_literal(segment) }
|
|
196
96
|
"ARRAY[#{segments.join(', ')}]::text[]"
|
|
@@ -3,18 +3,16 @@ require_relative "../../storage_shape"
|
|
|
3
3
|
module Hecks
|
|
4
4
|
module Translation
|
|
5
5
|
module Scaffold
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
# everything ambiguous left unresolved for a human.
|
|
6
|
+
# Diffs two eras' storage shapes into the edge's declarations; rules are written only
|
|
7
|
+
# for unique signature pairs, everything else is left unresolved.
|
|
9
8
|
module Differ
|
|
10
|
-
#
|
|
9
|
+
# Diffs two bluebook IRs into the edge's declarations.
|
|
11
10
|
#
|
|
12
11
|
# @param held_bluebook [Bluebook::Chapter] the era being translated from
|
|
13
12
|
# @param current_bluebook [Bluebook::Chapter] the era being translated to
|
|
14
|
-
# @return [Hash{Symbol => Object}] `:aggregates` (Array<Scaffold::ScaffoldedAggregate
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
# aggregate names left ambiguous)
|
|
13
|
+
# @return [Hash{Symbol => Object}] `:aggregates` (Array<Scaffold::ScaffoldedAggregate>),
|
|
14
|
+
# `:retired` (Array<String>, vanished names with no successor), `:unclaimed`
|
|
15
|
+
# (Array<String>, vanished names left ambiguous)
|
|
18
16
|
def diff(held_bluebook, current_bluebook)
|
|
19
17
|
held_shapes = projections(held_bluebook)
|
|
20
18
|
current_shapes = projections(current_bluebook)
|
|
@@ -34,31 +32,19 @@ module Hecks
|
|
|
34
32
|
{ aggregates: aggregates, retired: matched[:retired], unclaimed: matched[:unclaimed] }
|
|
35
33
|
end
|
|
36
34
|
|
|
37
|
-
# Projects a bluebook's storage shape
|
|
38
|
-
#
|
|
39
|
-
# @param bluebook [Bluebook::Chapter] the bluebook to project
|
|
40
|
-
# @return [Hash{String => Hash}] the bluebook's storage-shape aggregates (see
|
|
41
|
-
# `Runtime::StorageShape.project`), keyed by aggregate name
|
|
35
|
+
# Projects a bluebook's storage shape, indexing its aggregates by name.
|
|
42
36
|
def projections(bluebook)
|
|
43
37
|
Runtime::StorageShape.project(bluebook)["aggregates"].to_h { |shape| [shape["name"], shape] }
|
|
44
38
|
end
|
|
45
39
|
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
# beside an unmatched new one might be a rename-plus-reshape, and
|
|
50
|
-
# writing `retired` there would be a guess that strands data.
|
|
51
|
-
# Anything ambiguous stays unclaimed, and the coverage gate names
|
|
52
|
-
# it until a human decides.
|
|
40
|
+
# Pairs vanished aggregates with new ones whose full shape reappears under exactly one
|
|
41
|
+
# name. A vanished aggregate is `retired` only when no unmatched new one remains, since
|
|
42
|
+
# it could be a rename-plus-reshape and guessing would strand data.
|
|
53
43
|
#
|
|
54
|
-
# @param held_shapes [Hash{String => Hash}]
|
|
55
|
-
#
|
|
56
|
-
# @
|
|
57
|
-
#
|
|
58
|
-
# @return [Hash{Symbol => Object}] `:pairs` (Hash{String => String, nil}, each current
|
|
59
|
-
# name to its matched held name, or nil when unmatched), `:retired` (Array<String>,
|
|
60
|
-
# vanished names with no successor), `:unclaimed` (Array<String>, vanished names
|
|
61
|
-
# left ambiguous)
|
|
44
|
+
# @param held_shapes [Hash{String => Hash}] held aggregate shapes, keyed by name
|
|
45
|
+
# @param current_shapes [Hash{String => Hash}] current aggregate shapes, keyed by name
|
|
46
|
+
# @return [Hash{Symbol => Object}] `:pairs` (current name to held name, or nil),
|
|
47
|
+
# `:retired` (Array<String>), `:unclaimed` (Array<String>)
|
|
62
48
|
def match_aggregates(held_shapes, current_shapes)
|
|
63
49
|
pairs = {}
|
|
64
50
|
current_shapes.each_key { |name| pairs[name] = held_shapes.key?(name) ? name : nil }
|
|
@@ -81,20 +67,14 @@ module Hecks
|
|
|
81
67
|
{ pairs: pairs, retired: retired, unclaimed: retired.empty? ? unclaimed : [] }
|
|
82
68
|
end
|
|
83
69
|
|
|
84
|
-
#
|
|
85
|
-
#
|
|
86
|
-
#
|
|
87
|
-
# top-level) or a move (any dotted end). Same path, same members,
|
|
88
|
-
# new type name: a retype. Anything else: unresolved, carrying its
|
|
89
|
-
# type-compatible candidates (an empty list is the arrow toward
|
|
90
|
-
# compute, or drop).
|
|
70
|
+
# Resolves every changed path in one aggregate into rules by signature matching:
|
|
71
|
+
# a unique pair is a rename (both top-level) or a move (any dotted end), same members
|
|
72
|
+
# under a new type name is a retype, anything else is unresolved with its candidates.
|
|
91
73
|
#
|
|
92
|
-
# @param held_shape [Hash{String => Object}] the held era's aggregate shape
|
|
93
|
-
# `projections`)
|
|
74
|
+
# @param held_shape [Hash{String => Object}] the held era's aggregate shape
|
|
94
75
|
# @param current_shape [Hash{String => Object}] the current era's aggregate shape
|
|
95
|
-
# @return [Array<Hash{Symbol => Object}>] one rule
|
|
96
|
-
#
|
|
97
|
-
# `:unresolved` (see `Renderer#render_rule`); `[]` when nothing changed
|
|
76
|
+
# @return [Array<Hash{Symbol => Object}>] one rule per changed path (see
|
|
77
|
+
# `Renderer#render_rule`); `[]` when nothing changed
|
|
98
78
|
def attribute_rules(held_shape, current_shape)
|
|
99
79
|
rules = []
|
|
100
80
|
rules << identity_hint(held_shape, current_shape)
|
|
@@ -108,26 +88,13 @@ module Hecks
|
|
|
108
88
|
vanished = vanished_paths(held_attrs, current_attrs, retyped)
|
|
109
89
|
appeared = appeared_paths(held_attrs, current_attrs, retyped)
|
|
110
90
|
|
|
111
|
-
# Mutates `rules` in place
|
|
112
|
-
#
|
|
113
|
-
# `taken`, below, is recomputed from `rules` at the top of every
|
|
114
|
-
# iteration, so a target this same loop already claimed for an
|
|
115
|
-
# earlier vanished path is excluded from a later one. Passing a
|
|
116
|
-
# snapshot instead of the live array would let two vanished
|
|
117
|
-
# paths both match the same appeared target.
|
|
91
|
+
# Mutates `rules` in place: each iteration must see targets claimed by earlier ones,
|
|
92
|
+
# or two vanished paths could match the same appeared target.
|
|
118
93
|
resolve_vanished_rules!(rules, vanished, appeared)
|
|
119
94
|
rules
|
|
120
95
|
end
|
|
121
96
|
|
|
122
|
-
#
|
|
123
|
-
# type's own name changed
|
|
124
|
-
#
|
|
125
|
-
# @param held_attrs [Hash{String => Hash}] the held era's attributes, keyed by name
|
|
126
|
-
# @param current_attrs [Hash{String => Hash}] the current era's attributes, keyed by
|
|
127
|
-
# name
|
|
128
|
-
# @return [Array<Hash{Symbol => String}>] one `{kind: :retype, from:, to:}` rule per
|
|
129
|
-
# attribute whose members are unchanged but whose type name changed; `[]` when none
|
|
130
|
-
# match
|
|
97
|
+
# Retype rules for attributes whose members are unchanged but whose type name changed.
|
|
131
98
|
def retype_rules(held_attrs, current_attrs)
|
|
132
99
|
(held_attrs.keys & current_attrs.keys).filter_map do |name|
|
|
133
100
|
held = held_attrs[name]
|
|
@@ -140,16 +107,7 @@ module Hecks
|
|
|
140
107
|
end
|
|
141
108
|
end
|
|
142
109
|
|
|
143
|
-
# Resolves each vanished path into a rename, move or unresolved rule
|
|
144
|
-
# `rules` in place.
|
|
145
|
-
#
|
|
146
|
-
# @param rules [Array<Hash{Symbol => Object}>] the rule list to append to; also read
|
|
147
|
-
# for `:rename`/`:move` targets an earlier iteration already claimed
|
|
148
|
-
# @param vanished [Hash{String => Object}] vanished paths to type signature (see
|
|
149
|
-
# `vanished_paths`)
|
|
150
|
-
# @param appeared [Hash{String => Object}] appeared paths to type signature (see
|
|
151
|
-
# `appeared_paths`)
|
|
152
|
-
# @return [void]
|
|
110
|
+
# Resolves each vanished path into a rename, move or unresolved rule appended to `rules`.
|
|
153
111
|
def resolve_vanished_rules!(rules, vanished, appeared)
|
|
154
112
|
vanished.each do |path, signature|
|
|
155
113
|
matches = appeared.select { |_, candidate| candidate == signature }.keys
|
|
@@ -166,18 +124,9 @@ module Hecks
|
|
|
166
124
|
end
|
|
167
125
|
end
|
|
168
126
|
|
|
169
|
-
# Held paths that need explaining:
|
|
170
|
-
#
|
|
171
|
-
#
|
|
172
|
-
# for.
|
|
173
|
-
#
|
|
174
|
-
# @param held_attrs [Hash{String => Hash}] the held era's attributes, keyed by name
|
|
175
|
-
# @param current_attrs [Hash{String => Hash}] the current era's attributes, keyed by
|
|
176
|
-
# name
|
|
177
|
-
# @param retyped [Array<String>] type names already claimed by a `:retype` rule,
|
|
178
|
-
# excluded here
|
|
179
|
-
# @return [Hash{String => Object}] each vanished or changed path, dotted for a member,
|
|
180
|
-
# valued by that path's type signature
|
|
127
|
+
# Held paths that need explaining: vanished attributes, and members that vanished or
|
|
128
|
+
# changed type inside a kept attribute — the set EraGuard demands coverage for.
|
|
129
|
+
# Returns each path (dotted for a member) valued by its type signature.
|
|
181
130
|
def vanished_paths(held_attrs, current_attrs, retyped)
|
|
182
131
|
paths = {}
|
|
183
132
|
held_attrs.each do |name, held|
|
|
@@ -199,17 +148,7 @@ module Hecks
|
|
|
199
148
|
paths
|
|
200
149
|
end
|
|
201
150
|
|
|
202
|
-
# Current paths that need explaining
|
|
203
|
-
# that appeared (or changed type) inside a kept attribute — the mirror of
|
|
204
|
-
# `vanished_paths`.
|
|
205
|
-
#
|
|
206
|
-
# @param held_attrs [Hash{String => Hash}] the held era's attributes, keyed by name
|
|
207
|
-
# @param current_attrs [Hash{String => Hash}] the current era's attributes, keyed by
|
|
208
|
-
# name
|
|
209
|
-
# @param retyped [Array<String>] type names already claimed by a `:retype` rule,
|
|
210
|
-
# excluded here
|
|
211
|
-
# @return [Hash{String => Object}] each appeared or changed path, dotted for a
|
|
212
|
-
# member, valued by that path's type signature
|
|
151
|
+
# Current paths that need explaining; the mirror of `vanished_paths`.
|
|
213
152
|
def appeared_paths(held_attrs, current_attrs, retyped)
|
|
214
153
|
paths = {}
|
|
215
154
|
current_attrs.each do |name, current|
|
|
@@ -230,58 +169,30 @@ module Hecks
|
|
|
230
169
|
paths
|
|
231
170
|
end
|
|
232
171
|
|
|
233
|
-
#
|
|
234
|
-
#
|
|
235
|
-
# .project_aggregate`), it was simply never read here. An
|
|
236
|
-
# unresolved placeholder, not a guess: `coverage_check.rb`'s own
|
|
237
|
-
# `check_identity_unchanged!` is the real gate this only hints
|
|
238
|
-
# toward, the same "tool proactively guides you" pattern the
|
|
239
|
-
# generic unresolved message already gives unfed fields.
|
|
240
|
-
#
|
|
241
|
-
# @param held_shape [Hash{String => Object}] the held era's aggregate shape
|
|
242
|
-
# @param current_shape [Hash{String => Object}] the current era's aggregate shape
|
|
243
|
-
# @return [Hash{Symbol => Object}, nil] `{kind: :unresolved, from: :identity,
|
|
244
|
-
# candidates: []}` when the identity paths differ; nil when they match
|
|
172
|
+
# An unresolved placeholder when the identity paths differ; nil when they match.
|
|
173
|
+
# It only hints: `check_identity_unchanged!` in `coverage_check.rb` is the real gate.
|
|
245
174
|
def identity_hint(held_shape, current_shape)
|
|
246
175
|
return if held_shape["identity"] == current_shape["identity"]
|
|
247
176
|
|
|
248
177
|
{ kind: :unresolved, from: :identity, candidates: [] }
|
|
249
178
|
end
|
|
250
179
|
|
|
251
|
-
#
|
|
252
|
-
#
|
|
253
|
-
# @param appeared [Hash{String => Object}] appeared paths to type signature (see
|
|
254
|
-
# `appeared_paths`)
|
|
255
|
-
# @param signature [Object] the vanished path's own type signature to match against
|
|
256
|
-
# @return [Array<String>] appeared paths whose scalar signature (see `scalar_of`)
|
|
257
|
-
# matches `signature`'s
|
|
180
|
+
# Appeared paths type-compatible with a vanished path's signature.
|
|
258
181
|
def compatible_candidates(appeared, signature)
|
|
259
182
|
appeared.select { |_, candidate| scalar_of(candidate) == scalar_of(signature) }.keys
|
|
260
183
|
end
|
|
261
184
|
|
|
262
|
-
# Reduces a type signature to
|
|
263
|
-
#
|
|
264
|
-
# @param signature [Object, Hash] a path's type signature
|
|
265
|
-
# @return [Object] `signature["members"]` for a container Hash, else `signature`
|
|
266
|
-
# unchanged
|
|
185
|
+
# Reduces a type signature to what `compatible_candidates` compares: members or the scalar.
|
|
267
186
|
def scalar_of(signature) = signature.is_a?(Hash) ? signature["members"] : signature
|
|
268
187
|
|
|
269
|
-
#
|
|
270
|
-
#
|
|
271
|
-
# @param attribute [Hash{String => Object}] one path's type signature
|
|
272
|
-
# @return [Hash{String => Object}] each member's name to its type; `{}` when
|
|
273
|
-
# `attribute` is not a container
|
|
188
|
+
# A container attribute's members keyed by name; `{}` for a scalar.
|
|
274
189
|
def members_of(attribute)
|
|
275
190
|
return {} unless container?(attribute)
|
|
276
191
|
|
|
277
192
|
attribute["type"]["members"].to_h { |member| [member["name"], member["type"]] }
|
|
278
193
|
end
|
|
279
194
|
|
|
280
|
-
#
|
|
281
|
-
# scalar.
|
|
282
|
-
#
|
|
283
|
-
# @param attribute [Hash{String => Object}] one path's type signature
|
|
284
|
-
# @return [Boolean] true if `attribute["type"]` is a Hash, false for a scalar
|
|
195
|
+
# Whether the attribute's type is a container (value object or entity), not a scalar.
|
|
285
196
|
def container?(attribute) = attribute["type"].is_a?(Hash)
|
|
286
197
|
end
|
|
287
198
|
end
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
module Hecks
|
|
2
2
|
module Translation
|
|
3
3
|
module Scaffold
|
|
4
|
-
#
|
|
5
|
-
# ambiguities as parse-refusing `unresolved` constructs, never
|
|
4
|
+
# Renders an edge as .bluebook text. Ambiguities become `unresolved` constructs, not
|
|
6
5
|
# comments, so an unresolved file can only boot into a refusal.
|
|
7
6
|
module Renderer
|
|
8
7
|
# Renders a scaffolded edge as loadable `.bluebook` translation source.
|
|
9
8
|
#
|
|
10
9
|
# @param edge [Scaffold::Edge] the edge to render
|
|
11
|
-
# @return [String] the
|
|
10
|
+
# @return [String] the `.bluebook` text, ending in a newline
|
|
12
11
|
def render(edge)
|
|
13
12
|
lines = ["Hecks.data_translation #{edge.domain.inspect}, from: #{edge.from.inspect}, to: #{edge.to.inspect} do"]
|
|
14
13
|
edge.aggregates.each do |aggregate|
|
|
@@ -25,10 +24,8 @@ module Hecks
|
|
|
25
24
|
|
|
26
25
|
# Renders one scaffolded rule as a line of `.bluebook` source.
|
|
27
26
|
#
|
|
28
|
-
# @param rule [Hash{Symbol => Object}] a rule
|
|
29
|
-
#
|
|
30
|
-
# @return [String, nil] the rendered line; nil if `rule[:kind]` is none of `:rename`,
|
|
31
|
-
# `:move`, `:retype` or `:unresolved`
|
|
27
|
+
# @param rule [Hash{Symbol => Object}] a rule as `Differ#attribute_rules` builds it
|
|
28
|
+
# @return [String, nil] the rendered line; nil for an unknown `rule[:kind]`
|
|
32
29
|
def render_rule(rule)
|
|
33
30
|
case rule[:kind]
|
|
34
31
|
when :rename then "rename :#{rule[:from]}, to: :#{rule[:to]}"
|
|
@@ -40,11 +37,7 @@ module Hecks
|
|
|
40
37
|
end
|
|
41
38
|
end
|
|
42
39
|
|
|
43
|
-
# Renders a path as
|
|
44
|
-
# when dotted.
|
|
45
|
-
#
|
|
46
|
-
# @param path [String, Symbol] a bare or dotted path
|
|
47
|
-
# @return [String] `":name"` for a bare path, `path.inspect` for a dotted one
|
|
40
|
+
# Renders a bare path as a Symbol literal and a dotted path as a String literal.
|
|
48
41
|
def render_path(path) = path.to_s.include?(".") ? path.to_s.inspect : ":#{path}"
|
|
49
42
|
end
|
|
50
43
|
end
|
|
@@ -3,16 +3,10 @@ require "fileutils"
|
|
|
3
3
|
module Hecks
|
|
4
4
|
module Translation
|
|
5
5
|
module Scaffold
|
|
6
|
-
#
|
|
7
|
-
# for the same shape pair already exists.
|
|
6
|
+
# Writes the rendered edge to disk, reusing the file for the same shape pair if present.
|
|
8
7
|
module Writer
|
|
9
|
-
# Renders an edge and writes it under `directory/translations
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
# The edge file, regenerated in place when one for the same shape
|
|
13
|
-
# pair already exists (matched textually — an unresolved file
|
|
14
|
-
# cannot be loaded to ask, that being the whole point of
|
|
15
|
-
# unresolved).
|
|
8
|
+
# Renders an edge and writes it under `directory/translations`.
|
|
9
|
+
# An existing file is matched textually because an unresolved file cannot be loaded.
|
|
16
10
|
#
|
|
17
11
|
# @param directory [String] the domain's root directory
|
|
18
12
|
# @param edge [Scaffold::Edge] the edge to render and write
|
|
@@ -4,20 +4,8 @@ require_relative "scaffold/writer"
|
|
|
4
4
|
|
|
5
5
|
module Hecks
|
|
6
6
|
module Translation
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
# one (scaffold/differ.rb) and writes the edge file
|
|
10
|
-
# (scaffold/renderer.rb, scaffold/writer.rb): confident rules inline
|
|
11
|
-
# (unique signature pairs → rename/move, aggregate renames → `was:`,
|
|
12
|
-
# type renames with identical members → retype, aggregates gone
|
|
13
|
-
# without a successor → retired), ambiguities as parse-refusing
|
|
14
|
-
# `unresolved` constructs — never comments, so an unresolved file can
|
|
15
|
-
# only boot into a refusal, never a guess. It never proposes a
|
|
16
|
-
# `compute` (a computation takes domain judgment no mechanical diff
|
|
17
|
-
# can infer) — an empty-candidate `unresolved` is what points the
|
|
18
|
-
# author there. It never proposes a `drop` either: data loss is a
|
|
19
|
-
# decision, not a default. Re-running regenerates the file, matched
|
|
20
|
-
# by shape pair.
|
|
7
|
+
# Diffs the held era's storage shape against the current one and writes the edge file.
|
|
8
|
+
# Ambiguities become parse-refusing `unresolved` constructs; it never proposes compute or drop.
|
|
21
9
|
module Scaffold
|
|
22
10
|
Edge = Struct.new(:domain, :from, :to, :ordinal, :label, :aggregates, :retired, keyword_init: true)
|
|
23
11
|
ScaffoldedAggregate = Struct.new(:name, :was, :rules, keyword_init: true)
|
|
@@ -11,34 +11,15 @@ module Hecks
|
|
|
11
11
|
module Ports
|
|
12
12
|
module Persistence
|
|
13
13
|
module Plugins
|
|
14
|
-
# ADR 0033 — requiring this file
|
|
15
|
-
#
|
|
16
|
-
# binds `PostgresEra` (`Runtime::Loader.load_bound_adapters!` resolves the
|
|
17
|
-
# adapter, which autoloads this file, before the gates are collected). An
|
|
18
|
-
# app that wants schema-translation support without binding `PostgresEra`
|
|
19
|
-
# requires it explicitly, the same shape every adapter-specific spec
|
|
20
|
-
# fixture already uses to load one particular `.adapter` file rather than
|
|
21
|
-
# all of them.
|
|
14
|
+
# ADR 0033 — requiring this file installs the plugin; nothing in Hecks core
|
|
15
|
+
# requires it, so it loads only for a domain that binds `PostgresEra` (or asks explicitly).
|
|
22
16
|
module Era
|
|
23
17
|
module_function
|
|
24
18
|
|
|
25
19
|
# Registers this plugin's era gates on one boot's gate list.
|
|
26
20
|
#
|
|
27
|
-
# `
|
|
28
|
-
#
|
|
29
|
-
# `EraCheck` or "era" by name. Two gates, both `:pre_verify`:
|
|
30
|
-
#
|
|
31
|
-
# `:era_compute_rules` — unconditional, whenever this plugin is
|
|
32
|
-
# loaded at all. A `compute`/`rekey` rule requires Postgres
|
|
33
|
-
# whatever adapter is actually bound (ADR 0031's own reasoning,
|
|
34
|
-
# unchanged) — this is the rich, adapter-aware version of that
|
|
35
|
-
# check; `Runtime::Loader`'s own structural backstop (plain
|
|
36
|
-
# `Bluebook::Translation` data, no plugin-specific class) only
|
|
37
|
-
# ever fires when no persistence plugin is loaded at all.
|
|
38
|
-
#
|
|
39
|
-
# `:era_check` — conditional, exactly ADR 0031's own gate,
|
|
40
|
-
# unchanged: registered only when this registry has an aggregate
|
|
41
|
-
# actually bound to a lineage-capable adapter.
|
|
21
|
+
# Two `:pre_verify` gates: `era_compute_rules` always runs; `era_check` (ADR 0031)
|
|
22
|
+
# runs only when the registry binds something lineage-capable.
|
|
42
23
|
#
|
|
43
24
|
# @param registry [Runtime::Registry] the registry being booted, asked whether any
|
|
44
25
|
# bluebook's first aggregate is bound to a lineage-capable adapter
|