hecks 2.8.0 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/exe/hecks +4 -6
- 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 +17 -98
- 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 +5 -48
- 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 +31 -141
- 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 +14 -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 +25 -31
- 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 +16 -69
- 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 -194
- 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 -111
- 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 +53 -267
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +43 -305
- 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 +6 -21
- data/lib/hecks/bluebook/model_check.rb +100 -597
- 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 +4 -23
- data/lib/hecks/cli/document.rb +3 -21
- data/lib/hecks/cli/ir.rb +3 -5
- data/lib/hecks/cli/mcp.rb +2 -3
- data/lib/hecks/cli/mcp_door.rb +19 -114
- data/lib/hecks/cli/model_check.rb +18 -85
- data/lib/hecks/cli/project_cli.rb +7 -40
- data/lib/hecks/cli/project_diagrams.rb +0 -7
- data/lib/hecks/cli/run.rb +12 -58
- data/lib/hecks/cli/smoke_test.rb +2 -16
- data/lib/hecks/cli/stores.rb +1 -2
- data/lib/hecks/cli.rb +18 -24
- 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 +82 -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 +9 -90
- 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 +61 -64
- 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 +6 -25
- 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 +18 -124
- 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 +150 -678
- 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 +2 -15
- 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 +42 -134
- 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 +3 -6
- data/lib/hecks/release/runner/commands.rb +2 -4
- data/lib/hecks/release/runner/gem_publisher.rb +2 -3
- data/lib/hecks/release/runner/npm_publisher.rb +6 -20
- data/lib/hecks/release/runner/preflight.rb +4 -19
- data/lib/hecks/release/runner/tagger.rb +2 -9
- data/lib/hecks/release/runner.rb +3 -32
- 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 +124 -306
- 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 +64 -219
- 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 +117 -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 +99 -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 +141 -568
- 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.rb +26 -81
- 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 +3 -2
|
@@ -8,52 +8,23 @@ require_relative "expected_era"
|
|
|
8
8
|
|
|
9
9
|
module Hecks
|
|
10
10
|
module Runtime
|
|
11
|
-
# The boot-time era gate
|
|
12
|
-
#
|
|
13
|
-
# adapter can carry across a shape change; an adapter that cannot
|
|
14
|
-
# translate has no era to hold, and holding one for it would record
|
|
15
|
-
# history about data nothing can act on.
|
|
16
|
-
#
|
|
17
|
-
# The whole domain is handed to the capable adapter's own era check
|
|
18
|
-
# (Postgres: hold, recognize, mint, or refuse toward the scaffold),
|
|
19
|
-
# which keeps its era facts as rows beside its data. That
|
|
20
|
-
# co-location is load-bearing — a watermark only means something
|
|
21
|
-
# against the journal it was cut from, and an approval recorded
|
|
22
|
-
# anywhere but the reviewed database binds to nothing.
|
|
23
|
-
#
|
|
24
|
-
# The capability is asked of the adapter, never of its name: a
|
|
25
|
-
# second adapter that grows an era story declares lineage_capable?
|
|
26
|
-
# and era_check! and needs no change here.
|
|
27
|
-
#
|
|
28
|
-
# Detection and identity are separate jobs: this check never hashes
|
|
29
|
-
# anything — era names come from the store, already minted (by the
|
|
30
|
-
# scaffold) or absent. Refusal wordings are contract, pinned by the
|
|
31
|
-
# corpus.
|
|
11
|
+
# The boot-time era gate for lineage-capable adapters (Postgres today):
|
|
12
|
+
# each capable adapter's own era_check! decides hold, recognize, mint, or refuse.
|
|
32
13
|
module EraCheck
|
|
33
14
|
module_function
|
|
34
15
|
|
|
35
16
|
# Runs both halves of the era gate over every bluebook in a registry.
|
|
36
17
|
#
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
# moment `uses_framework` made a second, differently-sourced
|
|
41
|
-
# bluebook (Governance, Identity — `lib/hecks/framework/bluebook/`,
|
|
42
|
-
# not the domain's own directory) share a boot with the first.
|
|
43
|
-
# Caught the hard way: three domains booted together, one real
|
|
44
|
-
# source text (the domain's own), and every other domain's era-1
|
|
45
|
-
# held that text under its own name — a shadow-parse of it later
|
|
46
|
-
# reconstructs a completely different shape, and every boot after
|
|
47
|
-
# the first refuses toward a scaffold that was never the real
|
|
48
|
-
# drift.
|
|
18
|
+
# Looks up each bluebook's own source separately: `uses_framework` can share a boot between
|
|
19
|
+
# the domain's own bluebook and a differently-sourced one, so one file read once and reused
|
|
20
|
+
# for every bluebook would attribute the wrong text.
|
|
49
21
|
#
|
|
50
22
|
# @param registry [Runtime::Registry] the registry being booted
|
|
51
|
-
# @param directory [String]
|
|
52
|
-
# each bluebook's `.bluebook` source
|
|
23
|
+
# @param directory [String] the domain's bluebook directory, searched for each source
|
|
53
24
|
# @return [void]
|
|
54
|
-
# @raise [Runtime::WiringError] if a compute rule is bound to
|
|
55
|
-
#
|
|
56
|
-
#
|
|
25
|
+
# @raise [Runtime::WiringError] if a compute rule is bound to a non-lineage-capable adapter,
|
|
26
|
+
# a persistence binding cannot be resolved, a lineage-bound bluebook has no findable
|
|
27
|
+
# source, or `era_check!` refuses the boot
|
|
57
28
|
def check!(registry, directory)
|
|
58
29
|
check_compute_rules_for_registry!(registry)
|
|
59
30
|
check_lineage!(registry, directory)
|
|
@@ -61,12 +32,8 @@ module Hecks
|
|
|
61
32
|
|
|
62
33
|
# Refuses the boot when any bluebook's compute rule is bound away from Postgres.
|
|
63
34
|
#
|
|
64
|
-
#
|
|
65
|
-
#
|
|
66
|
-
# actually bound, so this must run for every registry, the same way
|
|
67
|
-
# `registry.verify!` does — it is not conditional on any adapter
|
|
68
|
-
# being lineage-capable, and must never be skipped by
|
|
69
|
-
# `check_lineage!`'s own capability gate below.
|
|
35
|
+
# Runs unconditionally for every registry, unlike check_lineage!'s
|
|
36
|
+
# capability-gated pass below (ADR 0031).
|
|
70
37
|
#
|
|
71
38
|
# @param registry [Runtime::Registry] the registry whose bluebooks are all checked
|
|
72
39
|
# @return [void]
|
|
@@ -78,11 +45,8 @@ module Hecks
|
|
|
78
45
|
|
|
79
46
|
# Hands every bluebook, with its own source text, to its adapter's era check.
|
|
80
47
|
#
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
# `check_bluebook!` below still carries its own per-bluebook
|
|
84
|
-
# `lineage_capable?` return-early, unchanged, for a registry with a
|
|
85
|
-
# mix of lineage-capable and plain-adapter bluebooks.
|
|
48
|
+
# Capability-gated (ADR 0031): check_bluebook! below still returns
|
|
49
|
+
# early for any bluebook whose own binding isn't lineage-capable.
|
|
86
50
|
#
|
|
87
51
|
# @param registry [Runtime::Registry] the registry being booted
|
|
88
52
|
# @param directory [String] path of the domain's own bluebook directory
|
|
@@ -98,12 +62,9 @@ module Hecks
|
|
|
98
62
|
|
|
99
63
|
# Decides whether a registry binds anything that carries eras.
|
|
100
64
|
#
|
|
101
|
-
#
|
|
102
|
-
#
|
|
103
|
-
#
|
|
104
|
-
# per-bluebook anchor check, just asked once, up front, of the
|
|
105
|
-
# whole registry, so a registry with nothing lineage-capable bound
|
|
106
|
-
# anywhere never registers the gate at all.
|
|
65
|
+
# Mirrors check_bluebook!'s own per-bluebook anchor check, asked
|
|
66
|
+
# once up front so a registry with nothing lineage-capable never
|
|
67
|
+
# registers the `:era_check` gate at all.
|
|
107
68
|
#
|
|
108
69
|
# @param registry [Runtime::Registry] the registry whose bluebooks are asked
|
|
109
70
|
# @return [Boolean] true when some bluebook's first aggregate is bound to a
|
|
@@ -121,51 +82,15 @@ module Hecks
|
|
|
121
82
|
|
|
122
83
|
# Reads the source text one bluebook was declared in, wherever that source lives.
|
|
123
84
|
#
|
|
124
|
-
#
|
|
125
|
-
#
|
|
126
|
-
#
|
|
127
|
-
#
|
|
128
|
-
# booted together, one real source text read once (the domain's
|
|
129
|
-
# own, ".first"'d), and every other domain's era-1 held that text
|
|
130
|
-
# under its own name — a later shadow-parse of it reconstructs a
|
|
131
|
-
# completely different shape, and every boot after the first
|
|
132
|
-
# refuses toward a scaffold that was never the real drift.
|
|
133
|
-
#
|
|
134
|
-
# A single-file directory whose one file names something else
|
|
135
|
-
# falls back to it anyway (a fixture may legitimately name its
|
|
136
|
-
# file differently from the `Hecks.bluebook` it declares) — unless
|
|
137
|
-
# this bluebook is a known framework member or a vendored
|
|
138
|
-
# embryonaut bluebook (see `vendored_source_for` below), in which
|
|
139
|
-
# case that one file is certainly some other domain's, not this
|
|
140
|
-
# one's, and the real registry is asked instead — the only other
|
|
141
|
-
# two places a bluebook in this registry could have come from, per
|
|
142
|
-
# `uses_framework` and `uses_embryonaut_bluebook`.
|
|
143
|
-
#
|
|
144
|
-
# The bug this guards against, found live: `Framework.members` was
|
|
145
|
-
# the only exclusion checked here, so a domain attaching a
|
|
146
|
-
# vendored bluebook instead (`uses_embryonaut_bluebook`, which has
|
|
147
|
-
# no equivalent registry — see embryonaut_bluebook.rb's own
|
|
148
|
-
# header) fell straight through the single-file fallback: a
|
|
149
|
-
# directory holding exactly one `.bluebook` file (the target
|
|
150
|
-
# domain's own) handed that same text back for the vendored
|
|
151
|
-
# bluebook's era check too. PostgresEra minted era 1 for the
|
|
152
|
-
# vendored domain with the target's own source stamped as its
|
|
153
|
-
# `held_text` — the label computed from it, too — so the very
|
|
154
|
-
# next boot re-derived the vendored domain's real shape, found it
|
|
155
|
-
# didn't match what got (wrongly) stored, and refused to boot
|
|
156
|
-
# toward a scaffold for drift that never actually happened.
|
|
157
|
-
# `registry:` is what lets this check the one thing
|
|
158
|
-
# `Framework.members` cannot: whether some hecksagon in this
|
|
159
|
-
# registry declared `uses_embryonaut_bluebook` for this exact
|
|
160
|
-
# bluebook name, the same way `EmbryonautBluebook.load!` itself
|
|
161
|
-
# already resolves the vendored package's own directory.
|
|
85
|
+
# Matched by declared name, not position: a domain directory using
|
|
86
|
+
# `uses_framework` may hold more than one file, and a framework
|
|
87
|
+
# member or vendored bluebook is excluded from the single-file
|
|
88
|
+
# fallback so its own real source is read, not a sibling's.
|
|
162
89
|
#
|
|
163
90
|
# @param bluebook [Bluebook::Chapter] the bluebook whose source is wanted
|
|
164
91
|
# @param directory [String] path of the domain's own bluebook directory
|
|
165
|
-
# @param registry [Runtime::Registry, nil]
|
|
166
|
-
#
|
|
167
|
-
# @return [String, nil] the UTF-8 text of every matching file joined with `"\n"`; nil
|
|
168
|
-
# when no source file could be found
|
|
92
|
+
# @param registry [Runtime::Registry, nil] nil skips the vendored-bluebook lookup
|
|
93
|
+
# @return [String, nil] UTF-8 text of every matching file joined with `"\n"`, or nil
|
|
169
94
|
def source_text_for(bluebook, directory, registry: nil)
|
|
170
95
|
domain_files = Dir[File.join(directory, "*.bluebook")]
|
|
171
96
|
own = domain_files.select { |path| declares_bluebook?(path, bluebook.name) }
|
|
@@ -190,13 +115,8 @@ module Hecks
|
|
|
190
115
|
|
|
191
116
|
# Picks the files to read for a bluebook no file in the domain directory declares.
|
|
192
117
|
#
|
|
193
|
-
#
|
|
194
|
-
#
|
|
195
|
-
# order: a genuinely single-file domain directory whose one file
|
|
196
|
-
# just happens to name something else (but only when this
|
|
197
|
-
# bluebook isn't already known to come from somewhere else
|
|
198
|
-
# entirely — the exact guard the bug below was missing half of);
|
|
199
|
-
# a framework member; a vendored embryonaut bluebook.
|
|
118
|
+
# Tries, in order: the domain's own single remaining file, a framework member, then a
|
|
119
|
+
# vendored embryonaut bluebook.
|
|
200
120
|
#
|
|
201
121
|
# @param bluebook [Bluebook::Chapter] the bluebook whose source is wanted
|
|
202
122
|
# @param directory [String] path of the domain's own bluebook directory
|
|
@@ -222,13 +142,8 @@ module Hecks
|
|
|
222
142
|
|
|
223
143
|
# Recovers the vendored package name behind a bluebook, if some hecksagon vendored it.
|
|
224
144
|
#
|
|
225
|
-
#
|
|
226
|
-
#
|
|
227
|
-
# (`HecksagonBuilder#uses_embryonaut_bluebook`'s own
|
|
228
|
-
# `@vendored_bluebooks`), matched the same way
|
|
229
|
-
# `EmbryonautBluebook.load!` itself decides idempotency: the
|
|
230
|
-
# vendored name Pascal-cases to this bluebook's own declared name.
|
|
231
|
-
# Nil for an ordinary bluebook nothing ever vendored.
|
|
145
|
+
# Matched by Pascal-casing: the vendored name Pascal-cases to this
|
|
146
|
+
# bluebook's own declared name.
|
|
232
147
|
#
|
|
233
148
|
# @param registry [Runtime::Registry] the registry whose hecksagons are searched
|
|
234
149
|
# @param bluebook_name [String] the bluebook's declared Pascal-case name
|
|
@@ -244,17 +159,9 @@ module Hecks
|
|
|
244
159
|
|
|
245
160
|
# Lists the `.bluebook` files a vendored embryonaut package ships.
|
|
246
161
|
#
|
|
247
|
-
#
|
|
248
|
-
#
|
|
249
|
-
#
|
|
250
|
-
# directory, always `registry.root`'s immediate child — see
|
|
251
|
-
# `Runtime::Loader.boot`) rather than threading `registry.root`
|
|
252
|
-
# through as a second parameter. Every `.bluebook` file the
|
|
253
|
-
# package ships, in the same `Dir.glob` order actually loaded at
|
|
254
|
-
# boot time — order matters here because this text is later
|
|
255
|
-
# re-parsed whole (`EraCheck::shadow`) to reconstruct the shape a
|
|
256
|
-
# held era claims, and that reconstruction must see the files in
|
|
257
|
-
# the order that actually built the live shape.
|
|
162
|
+
# Listed in `Dir.glob` order, matching load order at boot, since a
|
|
163
|
+
# later reconstruction of this text depends on seeing files in the
|
|
164
|
+
# order that built the live shape.
|
|
258
165
|
#
|
|
259
166
|
# @param directory [String] path of the domain's own bluebook directory, whose parent
|
|
260
167
|
# holds `vendor/embryonaut_bluebooks`
|
|
@@ -269,16 +176,12 @@ module Hecks
|
|
|
269
176
|
|
|
270
177
|
# Hands one bluebook to its adapter's `era_check!`, when that adapter carries eras.
|
|
271
178
|
#
|
|
272
|
-
# The
|
|
273
|
-
# which adapter is asked, and a bluebook with no aggregates, or one bound
|
|
274
|
-
# to an adapter that is not lineage-capable, is skipped without a word.
|
|
179
|
+
# The first aggregate is the anchor: its binding alone decides the adapter asked.
|
|
275
180
|
#
|
|
276
181
|
# @param registry [Runtime::Registry] the registry being booted
|
|
277
182
|
# @param bluebook [Bluebook::Chapter] the bluebook to check
|
|
278
|
-
# @param current_text [String, nil] the bluebook's source
|
|
279
|
-
#
|
|
280
|
-
# @param directory [String, nil] the domain's bluebook directory, named in the
|
|
281
|
-
# missing-source refusal and passed through to the adapter
|
|
183
|
+
# @param current_text [String, nil] the bluebook's source; nil means none was found
|
|
184
|
+
# @param directory [String, nil] the domain's bluebook directory, named in the refusal
|
|
282
185
|
# @return [void]
|
|
283
186
|
# @raise [Runtime::WiringError] if the first aggregate's binding cannot be resolved,
|
|
284
187
|
# `current_text` is nil for a lineage-bound bluebook, or the adapter's `era_check!`
|
|
@@ -305,10 +208,8 @@ module Hecks
|
|
|
305
208
|
|
|
306
209
|
# Refuses the boot when one bluebook's compute rule is bound away from Postgres.
|
|
307
210
|
#
|
|
308
|
-
#
|
|
309
|
-
#
|
|
310
|
-
# implementation, so an aggregate carrying one cannot boot
|
|
311
|
-
# anywhere but Postgres, whatever any shape comparison would say.
|
|
211
|
+
# A compute rule's SQL is its only implementation, so it cannot
|
|
212
|
+
# boot on any adapter but Postgres, independent of shape checks.
|
|
312
213
|
#
|
|
313
214
|
# @param registry [Runtime::Registry] the registry holding the declared translations
|
|
314
215
|
# and the aggregate's bindings
|
|
@@ -343,17 +244,13 @@ module Hecks
|
|
|
343
244
|
|
|
344
245
|
# Asks a named adapter whether it carries eras.
|
|
345
246
|
#
|
|
346
|
-
#
|
|
347
|
-
#
|
|
348
|
-
# (translate, fork, merge). Postgres alone does today; the seam is
|
|
349
|
-
# what lets a second one arrive without touching this file.
|
|
247
|
+
# Postgres alone answers true today; the seam lets a second
|
|
248
|
+
# lineage-capable adapter arrive without touching this file.
|
|
350
249
|
#
|
|
351
250
|
# @param registry [Runtime::Registry] the registry whose `adapters` must list the name
|
|
352
251
|
# @param adapter_name [String] the adapter's name, as `adapter_for` returns it
|
|
353
|
-
# @return [Boolean] the adapter's own
|
|
354
|
-
#
|
|
355
|
-
# any `StandardError` is raised on the way (including an adapter with no Ruby
|
|
356
|
-
# implementation)
|
|
252
|
+
# @return [Boolean] the adapter's own answer; false if unlisted, not lineage-capable, or
|
|
253
|
+
# any `StandardError` is raised
|
|
357
254
|
def lineage_capable?(registry, adapter_name)
|
|
358
255
|
adapter_class = registry.adapters[adapter_name] && registry.adapter_class(adapter_name)
|
|
359
256
|
adapter_class.respond_to?(:lineage_capable?) && adapter_class.lineage_capable?
|
|
@@ -1,37 +1,18 @@
|
|
|
1
1
|
module Hecks
|
|
2
2
|
module Runtime
|
|
3
3
|
module EraGuard
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
# from the IR it is handed, which is why the Postgres mint path can
|
|
7
|
-
# call it too.
|
|
4
|
+
# Structural signature and diff of aggregate shapes, computed from the IR alone
|
|
5
|
+
# (no file I/O), so the Postgres mint path can call it too.
|
|
8
6
|
module ShapeDiff
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
# @param aggregate [Bluebook::Aggregate] the aggregate to describe
|
|
12
|
-
# @return [Array<Array>] one `[name, signature]` pair per attribute, sorted by name;
|
|
13
|
-
# `name` is a Symbol and `signature` is whatever `attribute_signature` returns
|
|
7
|
+
# Structural signature of an aggregate: sorted `[name, signature]` pairs per attribute.
|
|
14
8
|
def shape(aggregate)
|
|
15
9
|
aggregate.attributes.map do |attribute|
|
|
16
10
|
[attribute.name, attribute_signature(aggregate, attribute.type)]
|
|
17
11
|
end.sort_by(&:first)
|
|
18
12
|
end
|
|
19
13
|
|
|
20
|
-
# Expands a declared type
|
|
21
|
-
#
|
|
22
|
-
# A plain type name for a primitive; `[type_name, member_signatures]`
|
|
23
|
-
# for a value object or entity, walked recursively — so two
|
|
24
|
-
# attributes with the same declared type name but a different
|
|
25
|
-
# internal shape are never mistaken for unchanged.
|
|
26
|
-
#
|
|
27
|
-
# @param aggregate [Bluebook::Aggregate] the aggregate whose value objects and entities
|
|
28
|
-
# are searched for `type_name`
|
|
29
|
-
# @param type_name [String, Bluebook::Reference] the attribute's declared type
|
|
30
|
-
# @param seen [Array<String, Bluebook::Reference>] types already being expanded, which
|
|
31
|
-
# stops a self-referencing type from recursing forever
|
|
32
|
-
# @return [String, Bluebook::Reference, Array] `type_name` itself for a primitive, a
|
|
33
|
-
# reference, or a type already in `seen`; otherwise `[type_name, members]`, where
|
|
34
|
-
# `members` is an Array of `[member_name, signature]` pairs sorted by member name
|
|
14
|
+
# Expands a declared type so same-named types with different members never compare equal.
|
|
15
|
+
# Primitives and references come back as-is; `seen` stops self-referencing types.
|
|
35
16
|
def attribute_signature(aggregate, type_name, seen = [])
|
|
36
17
|
container = nested_type(aggregate, type_name)
|
|
37
18
|
return type_name if container.nil? || seen.include?(type_name)
|
|
@@ -42,42 +23,13 @@ module Hecks
|
|
|
42
23
|
[type_name, members]
|
|
43
24
|
end
|
|
44
25
|
|
|
45
|
-
# Looks a type name up among an aggregate's value objects, then its entities.
|
|
46
|
-
#
|
|
47
|
-
# @param aggregate [Bluebook::Aggregate] the aggregate to search
|
|
48
|
-
# @param type_name [String, Bluebook::Reference] the declared type to find
|
|
49
|
-
# @return [Bluebook::ValueObject, Bluebook::Entity, nil] the matching declaration; nil
|
|
50
|
-
# when the type is a primitive, a reference, or nothing this aggregate declares
|
|
51
26
|
def nested_type(aggregate, type_name)
|
|
52
27
|
aggregate.value_object(type_name) || aggregate.entities.find { |entity| entity.name == type_name }
|
|
53
28
|
end
|
|
54
29
|
|
|
55
|
-
#
|
|
56
|
-
#
|
|
57
|
-
#
|
|
58
|
-
# addition side of drift, which `uncovered_attributes` below never
|
|
59
|
-
# looks at, since it only walks the held shape (vanish/retype).
|
|
60
|
-
# Most additions are free (ADR 0025, "Added attributes and
|
|
61
|
-
# absence"): a default:, a list_of (frozen []), or a value object
|
|
62
|
-
# whose fields all default fill an existing record automatically
|
|
63
|
-
# via `Instance.hydrate_with_defaults`. Only the fourth case — a
|
|
64
|
-
# non-optional attribute with no way to fill itself — can leave an
|
|
65
|
-
# existing record with the field genuinely absent, and that is
|
|
66
|
-
# what this reports: unfilled by a declared translation's own
|
|
67
|
-
# `backfill`, or by a move/convert that lands an old field inside
|
|
68
|
-
# this brand-new attribute (`Lineage#fills?` — the destination-
|
|
69
|
-
# side question, never `explains?`'s source-side one, since a
|
|
70
|
-
# rename from Crate to Bin can introduce a top-level attribute
|
|
71
|
-
# name that never existed to have "vanished").
|
|
72
|
-
#
|
|
73
|
-
# @param aggregate [Bluebook::Aggregate] the aggregate as currently declared
|
|
74
|
-
# @param held_aggregate [Bluebook::Aggregate] the same aggregate as the held era's text
|
|
75
|
-
# declares it
|
|
76
|
-
# @param lineage [Ports::Persistence::Lineage, nil] the edge's rules for this aggregate; nil
|
|
77
|
-
# when the edge declares none, so nothing can fill an addition
|
|
78
|
-
# @return [Array<Symbol>] names of new, non-optional attributes with no default, no
|
|
79
|
-
# list cardinality, no fully-defaulted value object and no rule filling them; `[]`
|
|
80
|
-
# when every addition is safe
|
|
30
|
+
# Names of new, non-optional attributes that no default, list, defaulted value object
|
|
31
|
+
# or translation rule (`Lineage#fills?`) can fill on an existing record.
|
|
32
|
+
# Destination-side check: a rename can add a name that never existed to "vanish".
|
|
81
33
|
def unsafe_additions(aggregate, held_aggregate, lineage)
|
|
82
34
|
held_names = held_aggregate.attributes.map(&:name)
|
|
83
35
|
|
|
@@ -88,17 +40,7 @@ module Hecks
|
|
|
88
40
|
.map(&:name)
|
|
89
41
|
end
|
|
90
42
|
|
|
91
|
-
#
|
|
92
|
-
#
|
|
93
|
-
# The four-row table, as a predicate over the fourth row only — the
|
|
94
|
-
# other three (default:, list_of, a fully-defaulted value object)
|
|
95
|
-
# all fill an existing record for free and never reach here.
|
|
96
|
-
#
|
|
97
|
-
# @param aggregate [Bluebook::Aggregate] the aggregate declaring the attribute, searched
|
|
98
|
-
# for the value object its type may name
|
|
99
|
-
# @param attribute [Bluebook::Attribute] the newly added attribute
|
|
100
|
-
# @return [Boolean] false when the attribute is optional, has a default, is a list, or
|
|
101
|
-
# is a value object whose every field has a default; true otherwise
|
|
43
|
+
# True when a new attribute could be genuinely absent from an existing record (ADR 0025).
|
|
102
44
|
def possibly_absent?(aggregate, attribute)
|
|
103
45
|
return false if attribute.optional?
|
|
104
46
|
return false unless attribute.default.nil?
|
|
@@ -110,24 +52,8 @@ module Hecks
|
|
|
110
52
|
true
|
|
111
53
|
end
|
|
112
54
|
|
|
113
|
-
#
|
|
114
|
-
#
|
|
115
|
-
# Paths the translation needs to explain: attributes that vanished
|
|
116
|
-
# by name, attributes that kept their name but changed type (a
|
|
117
|
-
# `convert` is what lets that be declared at all), and — recursing
|
|
118
|
-
# into a same-named, same-typed value object — its own members
|
|
119
|
-
# vanishing or changing type one level down, reported as a dotted
|
|
120
|
-
# path ("price.currency"). A pure addition, at any depth, never
|
|
121
|
-
# needs covering; only vanish-or-retype does, matching the
|
|
122
|
-
# top-level rule at every depth.
|
|
123
|
-
#
|
|
124
|
-
# @param aggregate [Bluebook::Aggregate] the aggregate as currently declared
|
|
125
|
-
# @param held_aggregate [Bluebook::Aggregate] the same aggregate as the held era's text
|
|
126
|
-
# declares it
|
|
127
|
-
# @param lineage [Ports::Persistence::Lineage, nil] the edge's rules for this aggregate; nil
|
|
128
|
-
# when the edge declares none, so every vanished or retyped path is reported
|
|
129
|
-
# @return [Array<String>] bare attribute names and dotted member paths such as
|
|
130
|
-
# `"price.currency"`; `[]` when the whole diff is explained
|
|
55
|
+
# Held attribute paths that vanished or changed type with no rule explaining them,
|
|
56
|
+
# recursing into value objects as dotted paths ("price.currency"). Additions never count.
|
|
131
57
|
def uncovered_attributes(aggregate, held_aggregate, lineage)
|
|
132
58
|
paths = held_aggregate.attributes.flat_map do |held_attribute|
|
|
133
59
|
current_attribute = aggregate.attribute(held_attribute.name)
|
|
@@ -142,38 +68,12 @@ module Hecks
|
|
|
142
68
|
end
|
|
143
69
|
|
|
144
70
|
# Compares one path's held and current types, recursing into shared members.
|
|
145
|
-
#
|
|
146
|
-
# `
|
|
147
|
-
# side's own value_object and entity declarations — neither is ever
|
|
148
|
-
# nested in the DSL, only in the type graph, so both are always
|
|
149
|
-
# looked up flat off their respective aggregate. A `list_of` entity
|
|
150
|
-
# is only reached here to detect a member vanish-or-retype; there is
|
|
151
|
-
# no per-element translation machinery yet (`move`/`convert`/`drop`
|
|
152
|
-
# only reach into a single nested hash, not each element of an
|
|
153
|
-
# array) — the only way to satisfy a refusal on an entity path
|
|
154
|
-
# today is a top-level `drop` of the whole list attribute, which
|
|
155
|
-
# `explains?` already recognizes as covering everything nested
|
|
156
|
-
# under it. Blunt, but loud beats silent.
|
|
157
|
-
#
|
|
158
|
-
# @param path [String] the bare or dotted path being compared, reported on a mismatch
|
|
159
|
-
# @param held_type [String, Bluebook::Reference] the type the held era declares there
|
|
160
|
-
# @param current_type [String, Bluebook::Reference] the type declared there now
|
|
161
|
-
# @param held_aggregate [Bluebook::Aggregate] the held aggregate, searched for
|
|
162
|
-
# `held_type`'s declaration
|
|
163
|
-
# @param aggregate [Bluebook::Aggregate] the current aggregate, searched for
|
|
164
|
-
# `current_type`'s declaration
|
|
165
|
-
# @param lineage [Ports::Persistence::Lineage, nil] the edge's rules, asked whether a retype
|
|
166
|
-
# pairs the two type names; nil means no retype is accepted
|
|
167
|
-
# @param seen [Array<String, Bluebook::Reference>] current types already being
|
|
168
|
-
# expanded, which stops a self-referencing type from recursing forever
|
|
169
|
-
# @return [Array<String>] `[path]` when the types differ with no retype declared; the
|
|
170
|
-
# dotted paths of members that vanished or changed type beneath it; `[]` when
|
|
171
|
-
# nothing differs or either type is not a value object or entity
|
|
71
|
+
# A `list_of` entity is diffed only for member drift; no per-element translation exists, so
|
|
72
|
+
# only a top-level `drop` of the whole list satisfies it.
|
|
172
73
|
def diff_type(path, held_type, current_type, held_aggregate, aggregate, lineage, seen = [])
|
|
173
74
|
if held_type != current_type
|
|
174
|
-
# A declared retype
|
|
175
|
-
#
|
|
176
|
-
# member drift hiding beneath the rename is caught by name.
|
|
75
|
+
# A declared retype accepts the pair but members are still compared, so drift
|
|
76
|
+
# hidden under the rename is caught.
|
|
177
77
|
return [path] unless lineage&.retype?(held_type, current_type)
|
|
178
78
|
end
|
|
179
79
|
return [] if seen.include?(current_type)
|
|
@@ -6,23 +6,8 @@ require_relative "../../../../runtime/registry"
|
|
|
6
6
|
|
|
7
7
|
module Hecks
|
|
8
8
|
module Runtime
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
# `PostgresEra::LineageManager::CoverageCheck` calls `uncovered_
|
|
12
|
-
# attributes`/`unsafe_additions`/`refuse_uncovered!`/`refuse_unsafe_
|
|
13
|
-
# addition!`/`check_vanished_aggregates!` directly, per translation
|
|
14
|
-
# edge, over its own DB-held shapes; `Translation::Reattest` and
|
|
15
|
-
# `PostgresEra::LineageManager` call `shadow_parse` directly, to read
|
|
16
|
-
# historical bluebook text under old grammar defaults. Both are real,
|
|
17
|
-
# independent, currently-shipped consumers.
|
|
18
|
-
#
|
|
19
|
-
# There is deliberately no top-level `check!`/`check_bluebook!` here
|
|
20
|
-
# walking a registry and reading/writing a held snapshot under
|
|
21
|
-
# `data/eras/*.bluebook`: it would duplicate, on its own, the same
|
|
22
|
-
# per-aggregate walk `CoverageCheck` already performs against
|
|
23
|
-
# `PostgresEra`'s own DB-held shapes, and nothing in production would
|
|
24
|
-
# call it — an unwired driver is not kept, per ADR 0032. If one is
|
|
25
|
-
# wanted, it is built informed by `CoverageCheck`'s real orchestration.
|
|
9
|
+
# Shape-drift coverage primitives (ADR 0032). Not a driver: callers own
|
|
10
|
+
# walking a registry and reading/writing held snapshots; nothing here does either.
|
|
26
11
|
module EraGuard
|
|
27
12
|
extend ShapeDiff
|
|
28
13
|
|
|
@@ -30,20 +15,16 @@ module Hecks
|
|
|
30
15
|
|
|
31
16
|
# Refuses the boot when a held aggregate is gone and no translation says where it went.
|
|
32
17
|
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
# against, and a plain per-aggregate diff would never see it: the
|
|
37
|
-
# current aggregate simply has no held counterpart to compare to.
|
|
18
|
+
# A held aggregate matching no current name has no counterpart for a
|
|
19
|
+
# plain per-aggregate diff to compare against; only a `was:` or
|
|
20
|
+
# `retired` translation can explain it.
|
|
38
21
|
#
|
|
39
|
-
# @param registry [Runtime::Registry] the registry
|
|
40
|
-
# searched for a `was:` or a `retired` entry naming the held aggregate
|
|
22
|
+
# @param registry [Runtime::Registry] the registry searched for a `was:`/`retired` entry
|
|
41
23
|
# @param bluebook [Bluebook::Chapter] the bluebook booting now
|
|
42
24
|
# @param held_bluebook [Bluebook::Chapter] the bluebook parsed from the held era's text
|
|
43
25
|
# @return [void]
|
|
44
|
-
# @raise [Runtime::WiringError] if a held aggregate matches no current aggregate
|
|
45
|
-
#
|
|
46
|
-
# for this domain retires it
|
|
26
|
+
# @raise [Runtime::WiringError] if a held aggregate matches no current aggregate, no
|
|
27
|
+
# `was:` declares it, and no translation retires it
|
|
47
28
|
def check_vanished_aggregates!(registry, bluebook, held_bluebook)
|
|
48
29
|
held_bluebook.aggregates.each do |held_aggregate|
|
|
49
30
|
claimed = bluebook.aggregates.any? do |aggregate|
|
|
@@ -125,65 +106,16 @@ module Hecks
|
|
|
125
106
|
end
|
|
126
107
|
end
|
|
127
108
|
|
|
128
|
-
# Parses held source into its own IR, in a
|
|
129
|
-
# era's text never touches the one actually booting.
|
|
109
|
+
# Parses held source into its own IR, in a throwaway registry.
|
|
130
110
|
#
|
|
131
|
-
#
|
|
132
|
-
#
|
|
133
|
-
#
|
|
134
|
-
# that has nothing to do with syntax the live grammar cannot
|
|
135
|
-
# read at all (`identified_by { }`, `belongs_to`, `has_one`,
|
|
136
|
-
# `has_many` — genuinely removed spellings, exactly what shadow-
|
|
137
|
-
# parsing exists to keep readable): `reference_to`'s own default
|
|
138
|
-
# mint name (`default_reference_name`, attribute_collector.rb)
|
|
139
|
-
# is bare under ADR 0025 and `_id`-suffixed under shadow mode, and
|
|
140
|
-
# that fork applies even to text using nothing but current, live
|
|
141
|
-
# syntax. Held text minted under the current grammar — every real
|
|
142
|
-
# era in this corpus today, since nothing has ever minted a second
|
|
143
|
-
# one — parses fine normally; under unconditional shadow mode only
|
|
144
|
-
# the reference-naming default differs, so it silently
|
|
145
|
-
# reconstructs a different shape (and hash) than a fresh parse of
|
|
146
|
-
# the identical text — the same text hashing two different ways
|
|
147
|
-
# depending on which code path read it, breaking `ensure_named!`'s
|
|
148
|
-
# own from/to edge lookup with a spurious "no translation edge
|
|
149
|
-
# covers it" refusal that has nothing to do with any real
|
|
150
|
-
# translation gap.
|
|
151
|
-
#
|
|
152
|
-
# A normal parse can only ever succeed on text the live grammar
|
|
153
|
-
# fully understands — there is no way for it to silently produce a
|
|
154
|
-
# wrong-but-plausible answer for genuinely legacy text, since every
|
|
155
|
-
# removed spelling refuses loudly (`Malformed`) rather than
|
|
156
|
-
# degrading. So: try normal first — if the ordinary grammar reads
|
|
157
|
-
# this text without complaint, that is the canonical, unambiguous
|
|
158
|
-
# interpretation, the same one `label_of`/`mint_hash` on the same
|
|
159
|
-
# source text always computes, whoever's asking. Only on a
|
|
160
|
-
# `Malformed` refusal — the one signal that actually means "this
|
|
161
|
-
# spelling is not in the live grammar" — fall back to the legacy
|
|
162
|
-
# grammar. Any other exception (a
|
|
163
|
-
# genuine syntax error, an unrelated validation refusal) propagates
|
|
164
|
-
# unchanged; swallowing it here to retry under shadow mode would
|
|
165
|
-
# risk masking a real defect in the held text behind a confusing
|
|
166
|
-
# second failure instead of the original, more specific one.
|
|
167
|
-
#
|
|
168
|
-
# `MetaValidator.while_shadow_parsing` (ADR 0025, docs/dsl-work-
|
|
169
|
-
# slices.md's S0a) is what makes the fallback a legacy grammar
|
|
170
|
-
# rather than just a second copy of today's: it stops
|
|
171
|
-
# `BluebookBuilder.build` from judging this text against the
|
|
172
|
-
# grammar as it stands now, which is the one thing that would make
|
|
173
|
-
# a removed spelling refuse history the day it is removed from
|
|
174
|
-
# live source. The scratch registry is throwaway either way —
|
|
175
|
-
# nothing here is dispatched against or exposed to the real one —
|
|
176
|
-
# so skipping the judge/assemble round-trip changes nothing this
|
|
177
|
-
# method reads: `shape`, `uncovered_attributes`, and friends only
|
|
178
|
-
# ever ask the built IR for its own structure.
|
|
111
|
+
# Tries the live grammar first, falling back to the shadow one only
|
|
112
|
+
# on `Malformed` — the one signal meaning "not in the live grammar"
|
|
113
|
+
# (ADR 0025); any other exception propagates unchanged.
|
|
179
114
|
#
|
|
180
115
|
# @param source [String] the held bluebook text to evaluate
|
|
181
|
-
# @param path [String] the file path
|
|
182
|
-
#
|
|
183
|
-
# @
|
|
184
|
-
# declares none
|
|
185
|
-
# @raise [Bluebook::DSL::Malformed] if the text parses under neither the live grammar
|
|
186
|
-
# nor the legacy one
|
|
116
|
+
# @param path [String] the file path reported as the text's origin
|
|
117
|
+
# @return [Bluebook::Chapter, nil] the first bluebook declared; nil when it declares none
|
|
118
|
+
# @raise [Bluebook::DSL::Malformed] if neither grammar accepts the text
|
|
187
119
|
# @raise [SyntaxError] if the text is not valid Ruby
|
|
188
120
|
def shadow_parse(source, path)
|
|
189
121
|
parse_bluebook(source, path, shadow: false)
|
|
@@ -196,7 +128,7 @@ module Hecks
|
|
|
196
128
|
# @param source [String] the bluebook text to evaluate
|
|
197
129
|
# @param path [String] the file path reported to `Kernel.eval` as the text's origin
|
|
198
130
|
# @param shadow [Boolean] true evaluates inside `MetaValidator.while_shadow_parsing`
|
|
199
|
-
# (the
|
|
131
|
+
# (the shadow grammar); false evaluates under the live grammar
|
|
200
132
|
# @return [Bluebook::Chapter, nil] the first bluebook the text registered in the scratch
|
|
201
133
|
# registry; nil when it declares none
|
|
202
134
|
# @raise [Bluebook::DSL::Malformed] if the chosen grammar refuses the text
|
|
@@ -5,26 +5,11 @@ require_relative "storage_shape"
|
|
|
5
5
|
|
|
6
6
|
module Hecks
|
|
7
7
|
module Runtime
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
# plain SHA256 comparison over raw bytes, unrelated to any of this);
|
|
11
|
-
# this only supplies the wording once that's already fired.
|
|
8
|
+
# Wording for the boot refusal when a held era's frozen text was
|
|
9
|
+
# edited after freezing (detected elsewhere via a digest mismatch).
|
|
12
10
|
#
|
|
13
|
-
# Lives here, not under `Ports::Persistence
|
|
14
|
-
# calls `
|
|
15
|
-
# (DSL-execution machinery), the "an adapter/port reaches into the
|
|
16
|
-
# runtime instead of being handed already-computed data" shape that
|
|
17
|
-
# has caused trouble here before. A capability this dependent on the
|
|
18
|
-
# runtime is a runtime-owned one that the Postgres adapter calls, not
|
|
19
|
-
# a ports-level module that happens to reach sideways into it.
|
|
20
|
-
#
|
|
21
|
-
# Every tamper refusal reaches the same generic wording, cosmetic edit
|
|
22
|
-
# or real shape change alike: telling the two apart by re-parsing the
|
|
23
|
-
# edited text is a pure quality-of-message nicety, not a safety
|
|
24
|
-
# property, and an edit that cannot be classified has to fall to the
|
|
25
|
-
# generic wording anyway. An operator judges "did this matter"
|
|
26
|
-
# themselves, reading the still-archived original — an anomalous
|
|
27
|
-
# recovery moment already, not a normal boot path.
|
|
11
|
+
# Lives here, not under `Ports::Persistence`, because `project` below
|
|
12
|
+
# calls runtime DSL-execution machinery (`EraGuard`, `StorageShape`) directly.
|
|
28
13
|
module EraTamper
|
|
29
14
|
module_function
|
|
30
15
|
|
|
@@ -40,12 +25,8 @@ module Hecks
|
|
|
40
25
|
|
|
41
26
|
# Parses a bluebook text and returns its storage-shape projection.
|
|
42
27
|
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
# Always parsed through a fresh tempfile, never the held file's own
|
|
46
|
-
# path: the predicate extractor caches source by path, and a held
|
|
47
|
-
# path whose content has changed (the very situation this module
|
|
48
|
-
# exists for) would hand it stale lines.
|
|
28
|
+
# Always parsed from a fresh tempfile, never the held file's own path,
|
|
29
|
+
# since the predicate extractor caches source by path and would see stale lines there.
|
|
49
30
|
#
|
|
50
31
|
# @param text [String] the bluebook source to parse
|
|
51
32
|
# @param _source_path [String, nil] ignored; the text is always parsed from a tempfile
|