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
|
@@ -8,28 +8,19 @@ module Hecks
|
|
|
8
8
|
module Adapters
|
|
9
9
|
class PostgresEra
|
|
10
10
|
module LineageManager
|
|
11
|
-
# What a mint must prove
|
|
12
|
-
#
|
|
13
|
-
# first two layers pass over the live compiled chain.
|
|
11
|
+
# What a mint must prove first: the edge covers the whole diff, no identity path was
|
|
12
|
+
# re-keyed, and the audit's first two layers pass over the compiled chain.
|
|
14
13
|
module CoverageCheck
|
|
15
|
-
# Refuses a mint whose translation edge leaves any part of the shape change
|
|
16
|
-
# unexplained.
|
|
14
|
+
# Refuses a mint whose translation edge leaves any part of the shape change unexplained.
|
|
17
15
|
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
# every held aggregate must still be claimed. The refusal is
|
|
21
|
-
# EraGuard's own, byte for byte.
|
|
16
|
+
# Every vanished or retyped path in the held-to-current diff must be explained and every
|
|
17
|
+
# held aggregate claimed; the refusal is EraGuard's own, byte for byte.
|
|
22
18
|
#
|
|
23
|
-
# @param registry [Runtime::Registry]
|
|
24
|
-
# claim a held aggregate through `was:` or `retired`
|
|
19
|
+
# @param registry [Runtime::Registry] where translations may claim a held aggregate
|
|
25
20
|
# @param bluebook [Bluebook::Chapter] the domain as currently declared
|
|
26
|
-
# @param held_bluebook [Bluebook::Chapter] the domain as the latest held era
|
|
27
|
-
# text declares it (a shadow parse)
|
|
21
|
+
# @param held_bluebook [Bluebook::Chapter] the domain as the latest held era declares it
|
|
28
22
|
# @param edge [Bluebook::Translation] the one edge leaving the latest held era
|
|
29
|
-
# @
|
|
30
|
-
# @raise [Runtime::WiringError] if an identity path changed without a `rekey`
|
|
31
|
-
# rule, a vanished or retyped path has no rule, a new required attribute has
|
|
32
|
-
# nothing to fill it, or a held aggregate is neither renamed nor retired
|
|
23
|
+
# @raise [Runtime::WiringError] on an unruled identity change or an uncovered path
|
|
33
24
|
def check_coverage!(registry, bluebook, held_bluebook, edge)
|
|
34
25
|
bluebook.aggregates.each do |aggregate|
|
|
35
26
|
rules = Ports::Persistence::Lineage.from_declared(edge.for_aggregate(aggregate.name), aggregate.name)
|
|
@@ -46,30 +37,19 @@ module Hecks
|
|
|
46
37
|
Runtime::EraGuard.check_vanished_aggregates!(registry, bluebook, held_bluebook)
|
|
47
38
|
end
|
|
48
39
|
|
|
49
|
-
# Refuses a mint that changes an aggregate's identity paths without declaring
|
|
50
|
-
# a `rekey`.
|
|
40
|
+
# Refuses a mint that changes an aggregate's identity paths without declaring a `rekey`.
|
|
51
41
|
#
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
# key, so this refuses unless the edge declares a `rekey` for
|
|
55
|
-
# this aggregate covering exactly that. `rules.rekey?` (see
|
|
56
|
-
# `Ports::Persistence::Lineage`'s own comment) is the single
|
|
57
|
-
# source of truth every consumer of this fact asks — this is not
|
|
58
|
-
# a second, independent check of `declared.rekeys`.
|
|
42
|
+
# Stored ids were fixed under the prior key, so the edge must declare a `rekey` for it;
|
|
43
|
+
# `rules.rekey?` is the one source of truth for that fact.
|
|
59
44
|
#
|
|
60
45
|
# @param bluebook [Bluebook::Chapter] the domain, named in the refusal
|
|
61
46
|
# @param aggregate [Bluebook::Aggregate] the aggregate as currently declared
|
|
62
|
-
# @param held_aggregate [Bluebook::Aggregate] the same aggregate
|
|
63
|
-
#
|
|
64
|
-
# @
|
|
65
|
-
# aggregate; nil when the edge declares none, which cannot excuse a change
|
|
66
|
-
# @return [nil] when the identity paths are unchanged or a `rekey` covers them
|
|
67
|
-
# @raise [Runtime::WiringError] if the identity paths differ and no `rekey` rule
|
|
68
|
-
# is declared
|
|
47
|
+
# @param held_aggregate [Bluebook::Aggregate] the same aggregate in the held era
|
|
48
|
+
# @param rules [Ports::Persistence::Lineage, nil] the edge's rules; nil excuses nothing
|
|
49
|
+
# @raise [Runtime::WiringError] if the identity paths differ and no `rekey` is declared
|
|
69
50
|
def check_identity_unchanged!(bluebook, aggregate, held_aggregate, rules)
|
|
70
|
-
#
|
|
71
|
-
#
|
|
72
|
-
# and so would let two different composites compare as unchanged.
|
|
51
|
+
# Full path lists, not the single-head shortcut: it is nil for every composite identity
|
|
52
|
+
# and would let two different composites compare equal.
|
|
73
53
|
return if held_aggregate.identity_paths == aggregate.identity_paths
|
|
74
54
|
return if rules&.rekey?
|
|
75
55
|
|
|
@@ -83,28 +63,16 @@ module Hecks
|
|
|
83
63
|
"data explicitly"
|
|
84
64
|
end
|
|
85
65
|
|
|
86
|
-
# Previews
|
|
87
|
-
#
|
|
88
|
-
#
|
|
89
|
-
# Layers 1 and 2 of the audit, over the live compiled chain —
|
|
90
|
-
# before anything is minted, so a refusal leaves no half-born
|
|
91
|
-
# era. (A convert meeting an unmapped value raises inside the
|
|
92
|
-
# preview query itself: same rollback-shaped outcome.)
|
|
66
|
+
# Previews each aggregate's translated head through the pending chain and audits it.
|
|
67
|
+
# Runs before anything is minted, so a refusal leaves no half-born era.
|
|
93
68
|
#
|
|
94
69
|
# @param bluebook [Bluebook::Chapter] the domain as currently declared
|
|
95
|
-
# @param lineage [Adapters::PostgresEra::Lineage] the domain's lineage, on an open
|
|
96
|
-
#
|
|
97
|
-
# @param chain [Array<Hash{Symbol => Bluebook::Translation}>] the full edge chain
|
|
98
|
-
# ending in `edge`, as `edge_chain` returns it
|
|
70
|
+
# @param lineage [Adapters::PostgresEra::Lineage] the domain's lineage, on an open db
|
|
71
|
+
# @param chain [Array<Hash>] the full edge chain ending in `edge`, per `edge_chain`
|
|
99
72
|
# @param ordinal [Integer] the ordinal of the era about to be minted
|
|
100
|
-
# @param edge [Bluebook::Translation] the pending edge
|
|
101
|
-
#
|
|
102
|
-
# @
|
|
103
|
-
# @raise [Runtime::WiringError] if Postgres refuses the translated preview query
|
|
104
|
-
# (a `convert` meeting an unmapped value, for one), or the audit reports any
|
|
105
|
-
# violation; the message lists them all
|
|
106
|
-
# @raise [PG::Error] if Postgres refuses the "before" query; only the translated
|
|
107
|
-
# preview is rescued into a `Runtime::WiringError`
|
|
73
|
+
# @param edge [Bluebook::Translation] the pending edge
|
|
74
|
+
# @raise [Runtime::WiringError] if a preview query fails or the audit reports a violation
|
|
75
|
+
# @raise [PG::Error] if Postgres refuses the "before" query
|
|
108
76
|
def audit!(bluebook, lineage, chain, ordinal, edge)
|
|
109
77
|
violations = []
|
|
110
78
|
bluebook.aggregates.each do |aggregate|
|
|
@@ -5,65 +5,29 @@ module Hecks
|
|
|
5
5
|
module Adapters
|
|
6
6
|
class PostgresEra
|
|
7
7
|
module LineageManager
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
# held-but-superseded shape boots read-only-toward-the-fence; an
|
|
11
|
-
# unheld shape goes to the minter.
|
|
8
|
+
# Boot-time era resolution: first boot holds era 1, a quiet reboot changes nothing,
|
|
9
|
+
# a superseded shape boots read-only, an unheld shape goes to the minter.
|
|
12
10
|
module EraResolver
|
|
13
11
|
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
14
|
-
# Resolves which era this boot is and records it on the registry
|
|
15
|
-
# on a first boot and minting the next era when the shape is one no era holds.
|
|
12
|
+
# Resolves which era this boot is and records it on the registry.
|
|
16
13
|
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
# own comment above, all sharing one `db` connection closed in
|
|
21
|
-
# `ensure`. Splitting the branches into separate methods would
|
|
22
|
-
# turn each `return` (which exits `check!`, closing `db`) into a
|
|
23
|
-
# sentinel value threaded back up, obscuring the mutual
|
|
24
|
-
# exclusivity that is the method's whole point.
|
|
25
|
-
#
|
|
26
|
-
# @param registry [Runtime::Registry] the booting registry; `resolved_eras` gets
|
|
27
|
-
# this domain's ordinal on every path but a first boot (where the adapter
|
|
28
|
-
# self-resolves to era 1), and `superseded_eras` gets the newest ordinal when
|
|
29
|
-
# this checkout's shape is held but superseded
|
|
30
|
-
# @param bluebook [Bluebook::Chapter] the domain being booted
|
|
31
|
-
# @param current_text [String] the domain's bluebook source as it stands on disk,
|
|
32
|
-
# held verbatim as the new era's text on a first boot or a mint
|
|
33
|
-
# @param settings [Hash{Symbol, String => Object}] the world's persistence settings
|
|
34
|
-
# for this binding; `database` is required, `schema`, `role` (a Postgres role to
|
|
35
|
-
# grant this era's privileges to) and `allow_superuser` are honored
|
|
36
|
-
# @param directory [String, nil] the domain's bluebook directory, where
|
|
37
|
-
# `HECKS_SCAFFOLD=1` writes a translation edge; nil disables scaffolding
|
|
38
|
-
# @return [Integer, nil] the ordinal of the era this boot minted, or nil when it
|
|
39
|
-
# minted nothing (first boot, quiet reboot, or a held-but-superseded shape)
|
|
40
|
-
# @raise [Runtime::WiringError] if the database cannot be reached, the connection
|
|
41
|
-
# is a superuser or has BYPASSRLS without `allow_superuser`, a declared
|
|
42
|
-
# `formerly_known_as` rename cannot be applied, a held text fails its integrity
|
|
43
|
-
# check, or the shape is unheld and `mint!` refuses
|
|
44
|
-
# @raise [Bluebook::DSL::Malformed] if a held era's text parses under neither the
|
|
45
|
-
# current nor the legacy grammar
|
|
14
|
+
# @return [Integer, nil] the ordinal minted, or nil when this boot minted nothing
|
|
15
|
+
# @raise [Runtime::WiringError] if the connection is refused, a held text fails its
|
|
16
|
+
# integrity check, or the shape is unheld and `mint!` refuses
|
|
46
17
|
def check!(registry:, bluebook:, current_text:, settings:, directory: nil)
|
|
47
18
|
db = PostgresEra.connect_for(bluebook.name, settings)
|
|
48
19
|
lineage = Lineage.new(db, bluebook.name, formerly_known_as: bluebook.formerly_known_as)
|
|
49
|
-
# First, before ensure_base
|
|
50
|
-
#
|
|
51
|
-
# earliest at which the connection's own role is known. See
|
|
52
|
-
# check_fence_applies!'s own header (BUG#24) for why a
|
|
53
|
-
# superuser connection refuses here by default.
|
|
20
|
+
# First, before ensure_base!: the earliest point the connection's role is known,
|
|
21
|
+
# so a superuser connection refuses here by default.
|
|
54
22
|
lineage.check_fence_applies!(allow_superuser: PostgresEra.setting(settings, :allow_superuser, default: false))
|
|
55
23
|
lineage.ensure_base!
|
|
56
|
-
#
|
|
57
|
-
# tell a genuinely stored `false` apart from an absent key (see
|
|
58
|
-
# PostgresEra.setting's own comment for the full reasoning).
|
|
24
|
+
# key? first, never `||`: a stored `false` must not read as an absent key.
|
|
59
25
|
role = settings.key?(:role) ? settings[:role] : settings["role"]
|
|
60
26
|
|
|
61
27
|
held = lineage.eras
|
|
62
28
|
if held.empty?
|
|
63
29
|
lineage.hold_first!(current_text, projection: Runtime::StorageShape.project(bluebook))
|
|
64
30
|
bluebook.aggregates.each { |aggregate| lineage.ensure_first_head!(aggregate.storage_name) }
|
|
65
|
-
# hold_first! already established era 1 as current for
|
|
66
|
-
# every role; this one just needs its own privileges.
|
|
67
31
|
lineage.grant_role!(role, aggregates: bluebook.aggregates, era: 1) if role
|
|
68
32
|
return
|
|
69
33
|
end
|
|
@@ -71,15 +35,8 @@ module Hecks
|
|
|
71
35
|
current_shape = Runtime::StorageShape.project(bluebook)
|
|
72
36
|
shapes = held.map { |era| [era, Runtime::StorageShape.project(shadow(era[:held_text]))] }
|
|
73
37
|
if bluebook.formerly_known_as
|
|
74
|
-
#
|
|
75
|
-
#
|
|
76
|
-
# is permanently the old one — the frozen text is authentic
|
|
77
|
-
# record ("this domain really was called that, at the
|
|
78
|
-
# time") and must never be rewritten. Only the in-memory
|
|
79
|
-
# shape used for this comparison is normalized, and only
|
|
80
|
-
# where it exactly matches the declared old name, so an
|
|
81
|
-
# unrelated domain that happens to shape-match some other
|
|
82
|
-
# domain's history still shows up as a real mismatch.
|
|
38
|
+
# Held text is frozen record and keeps the prior name; only the in-memory shape is
|
|
39
|
+
# normalized, and only on an exact match with the declared prior name.
|
|
83
40
|
shapes = shapes.map do |era, shape|
|
|
84
41
|
[era, shape["name"] == bluebook.formerly_known_as ? shape.merge("name" => bluebook.name) : shape]
|
|
85
42
|
end
|
|
@@ -88,8 +45,6 @@ module Hecks
|
|
|
88
45
|
latest, latest_shape = shapes.last
|
|
89
46
|
if latest_shape == current_shape
|
|
90
47
|
bluebook.aggregates.each { |aggregate| lineage.ensure_first_head!(aggregate.storage_name) } if latest[:ordinal] == 1
|
|
91
|
-
# A quiet reboot changes no era, so there is nothing to
|
|
92
|
-
# advance — only this role's own privileges, if it is new.
|
|
93
48
|
lineage.grant_role!(role, aggregates: bluebook.aggregates, era: latest[:ordinal]) if role
|
|
94
49
|
registry.resolved_eras[bluebook.name] = latest[:ordinal]
|
|
95
50
|
return
|
|
@@ -97,24 +52,11 @@ module Hecks
|
|
|
97
52
|
|
|
98
53
|
matched, = shapes.find { |_, shape| shape == current_shape }
|
|
99
54
|
if matched
|
|
100
|
-
# A
|
|
101
|
-
#
|
|
102
|
-
# adapter that recognizes this rather than refusing), but it
|
|
103
|
-
# may not keep writing: the shared era fence was already
|
|
104
|
-
# advanced past this ordinal by whichever mint superseded
|
|
105
|
-
# it, and nothing here may roll that back. Granting only
|
|
106
|
-
# this role's privileges, never advance_era!, is what keeps
|
|
107
|
-
# that true — see advance_era!'s own warning against being
|
|
108
|
-
# called with a superseded ordinal.
|
|
55
|
+
# A superseded era (an old checkout) may read but not write: never advance_era!
|
|
56
|
+
# here, since the fence is already past this ordinal.
|
|
109
57
|
lineage.grant_role!(role, aggregates: bluebook.aggregates, era: matched[:ordinal]) if role
|
|
110
58
|
registry.resolved_eras[bluebook.name] = matched[:ordinal]
|
|
111
|
-
#
|
|
112
|
-
# which era it is: `RepositoryFactory.build` hands this to
|
|
113
|
-
# the adapter as `superseded_by:`, and `PostgresEra#append`
|
|
114
|
-
# refuses on it before issuing the INSERT. That is the
|
|
115
|
-
# in-process half of "may not keep writing" — the half that
|
|
116
|
-
# holds even for a connection the RLS fence cannot bite
|
|
117
|
-
# (a superuser under allow_superuser; BUG#24).
|
|
59
|
+
# The adapter refuses appends on this, even where the RLS fence cannot bind.
|
|
118
60
|
registry.superseded_eras[bluebook.name] = latest[:ordinal]
|
|
119
61
|
return
|
|
120
62
|
end
|
data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb
CHANGED
|
@@ -6,26 +6,17 @@ module Hecks
|
|
|
6
6
|
module Adapters
|
|
7
7
|
class PostgresEra
|
|
8
8
|
module LineageManager
|
|
9
|
-
# Tail-merge
|
|
10
|
-
#
|
|
11
|
-
# ordinals, under the full audit, in one transaction.
|
|
9
|
+
# Tail-merge (bin/merge_tail): interleaves the stale world's post-cut writes into the
|
|
10
|
+
# head by global ordinal, audited, in one transaction.
|
|
12
11
|
module MergeCoordinator
|
|
13
|
-
# Merges
|
|
14
|
-
# era's head, on a connection of its own that it closes afterwards.
|
|
12
|
+
# Merges writes old checkouts made after the last mint into the current era's head.
|
|
15
13
|
#
|
|
16
|
-
# @param registry [Runtime::Registry] the loaded registry; supplies the
|
|
17
|
-
# translation edges the chain is built from
|
|
18
|
-
# @param bluebook [Bluebook::Chapter] the domain whose tail is merged
|
|
19
|
-
# @param settings [Hash{Symbol, String => Object}] the world's persistence
|
|
20
|
-
# settings for this binding; `database` is required
|
|
21
14
|
# @param winners [Hash{String => String}] record id to `"old"` or `"new"`, naming
|
|
22
|
-
# which world's
|
|
15
|
+
# which world's record wins for each id both worlds touched since the cut
|
|
23
16
|
# @return [true] when the merge committed
|
|
24
|
-
# @raise [Runtime::WiringError] if the
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
# or merge holds the domain lock for 10 seconds, or Postgres refuses a
|
|
28
|
-
# statement; every refusal rolls the merge back
|
|
17
|
+
# @raise [Runtime::WiringError] if the domain stands at era 1, the edge chain is
|
|
18
|
+
# broken, a contested record has no winner, or the audit reports violations;
|
|
19
|
+
# every refusal rolls the merge back
|
|
29
20
|
def merge!(registry:, bluebook:, settings:, winners: {})
|
|
30
21
|
db = PostgresEra.connect_for(bluebook.name, settings)
|
|
31
22
|
lineage = Lineage.new(db, bluebook.name, formerly_known_as: bluebook.formerly_known_as)
|
|
@@ -7,34 +7,10 @@ module Hecks
|
|
|
7
7
|
module Adapters
|
|
8
8
|
class PostgresEra
|
|
9
9
|
module LineageManager
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
# reviewed, check coverage, audit the live chain, and mint — or
|
|
13
|
-
# refuse toward the authoring loop by name.
|
|
10
|
+
# Names the source era, resolves its one outgoing translation edge, and mints the
|
|
11
|
+
# next era once approval, coverage and the audited chain all check out.
|
|
14
12
|
module Minter
|
|
15
|
-
# Mints the next era for a drifted shape in one transaction
|
|
16
|
-
# edge is present, current, approved where it must be, covering, and audited.
|
|
17
|
-
#
|
|
18
|
-
# @param registry [Runtime::Registry] the booting registry; supplies the loaded
|
|
19
|
-
# translation edges
|
|
20
|
-
# @param bluebook [Bluebook::Chapter] the domain as currently declared
|
|
21
|
-
# @param current_text [String] the domain's bluebook source, held verbatim as the
|
|
22
|
-
# new era's text
|
|
23
|
-
# @param lineage [Adapters::PostgresEra::Lineage] the domain's lineage, on an open
|
|
24
|
-
# connection
|
|
25
|
-
# @param latest [Hash{Symbol => Object}] the newest held era, as `Lineage#eras`
|
|
26
|
-
# returns it (`:ordinal`, `:hash`, `:label`, `:held_text`, `:watermark`)
|
|
27
|
-
# @param role [String, nil] a Postgres role to grant the new era's privileges to;
|
|
28
|
-
# nil grants nothing
|
|
29
|
-
# @param directory [String, nil] the domain's bluebook directory, where
|
|
30
|
-
# `HECKS_SCAFFOLD=1` writes a missing edge; nil disables scaffolding
|
|
31
|
-
# @return [Integer] the ordinal of the era just minted
|
|
32
|
-
# @raise [Runtime::WiringError] if no edge leaves the latest era, more than one
|
|
33
|
-
# does, the edge targets another shape, a compute or rekey edge lacks a current
|
|
34
|
-
# approval, the edge leaves drift uncovered, the chain is broken, the audit
|
|
35
|
-
# reports violations, or the mint transaction itself fails
|
|
36
|
-
# @raise [Bluebook::DSL::Malformed] if the latest held text parses under neither
|
|
37
|
-
# the current nor the legacy grammar
|
|
13
|
+
# Mints the next era for a drifted shape in one transaction.
|
|
38
14
|
def mint!(registry, bluebook, current_text, lineage, latest, role: nil, directory: nil)
|
|
39
15
|
ensure_named!(lineage, latest)
|
|
40
16
|
latest = lineage.eras.last
|
|
@@ -57,28 +33,9 @@ module Hecks
|
|
|
57
33
|
ordinal
|
|
58
34
|
end
|
|
59
35
|
|
|
60
|
-
# Finds the one translation edge
|
|
61
|
-
#
|
|
62
|
-
#
|
|
63
|
-
# mistake, not a merge to resolve automatically), and it must
|
|
64
|
-
# target the current shape's label (otherwise the edge is stale
|
|
65
|
-
# and boot must not silently mint past it).
|
|
66
|
-
#
|
|
67
|
-
# @param registry [Runtime::Registry] the registry whose loaded `translations`
|
|
68
|
-
# are searched
|
|
69
|
-
# @param bluebook [Bluebook::Chapter] the domain as currently declared
|
|
70
|
-
# @param lineage [Adapters::PostgresEra::Lineage] the domain's lineage, used only
|
|
71
|
-
# when scaffolding a missing edge
|
|
72
|
-
# @param latest [Hash{Symbol => Object}] the newest held era, already named;
|
|
73
|
-
# `:label` is the edge's required source and `:ordinal` appears in refusals
|
|
74
|
-
# @param label [String] the current shape's label, the edge's required target
|
|
75
|
-
# @param ordinal [Integer] the ordinal of the era about to be minted
|
|
76
|
-
# @param directory [String, nil] where `HECKS_SCAFFOLD=1` writes a missing edge;
|
|
77
|
-
# nil disables scaffolding
|
|
78
|
-
# @return [Bluebook::Translation] the single edge from `latest[:label]` to `label`
|
|
79
|
-
# @raise [Runtime::WiringError] if no edge leaves the latest era (naming the
|
|
80
|
-
# scaffold it wrote, when it wrote one), more than one does, or the one edge
|
|
81
|
-
# targets a label other than `label`
|
|
36
|
+
# Finds the one translation edge leaving the held era and targeting the current
|
|
37
|
+
# shape's label; a second edge from the same source is a wiring mistake, not a
|
|
38
|
+
# merge to resolve automatically.
|
|
82
39
|
def resolve_edge!(registry, bluebook, lineage, latest, label, ordinal, directory)
|
|
83
40
|
edges = registry.translations.select { |t| t.domain == bluebook.name && t.from == latest[:label] }
|
|
84
41
|
refuse_toward_the_scaffold!(registry, bluebook, lineage, latest, ordinal, directory) if edges.empty?
|
|
@@ -97,29 +54,10 @@ module Hecks
|
|
|
97
54
|
edge
|
|
98
55
|
end
|
|
99
56
|
|
|
100
|
-
# Refuses a mint whose edge carries a compute or rekey rule without a recorded
|
|
101
|
-
#
|
|
57
|
+
# Refuses a mint whose edge carries a compute or rekey rule without a recorded,
|
|
58
|
+
# edge-matching, journal-current approval.
|
|
102
59
|
#
|
|
103
|
-
# A compute's
|
|
104
|
-
# is the audit's human-approved sample — mint stays
|
|
105
|
-
# non-interactive by requiring the approval to already exist,
|
|
106
|
-
# recorded in this database by `bin/translation_audit …
|
|
107
|
-
# --approve` and bound to what was actually reviewed: this
|
|
108
|
-
# edge's parsed content, and the journal as it stood when the
|
|
109
|
-
# samples were read. A journal that has advanced past the
|
|
110
|
-
# review invalidates it — the approved samples no longer cover
|
|
111
|
-
# the data.
|
|
112
|
-
#
|
|
113
|
-
# @param bluebook [Bluebook::Chapter] the domain, named in the refusal
|
|
114
|
-
# @param lineage [Adapters::PostgresEra::Lineage] the domain's lineage, which holds
|
|
115
|
-
# the recorded approvals and the journal's last ordinal
|
|
116
|
-
# @param edge [Bluebook::Translation] the edge about to be minted through
|
|
117
|
-
# @param ordinal [Integer] the ordinal of the era about to be minted
|
|
118
|
-
# @return [nil] when the edge has no compute or rekey rule, or its approval is
|
|
119
|
-
# current
|
|
120
|
-
# @raise [Runtime::WiringError] if no approval is recorded for this shape pair, the
|
|
121
|
-
# approval's edge digest differs from this edge's, or the journal has advanced
|
|
122
|
-
# past the reviewed ordinal
|
|
60
|
+
# A compute or rekey's only verification is a human-approved audit sample.
|
|
123
61
|
def ensure_compute_rekey_approved!(bluebook, lineage, edge, ordinal)
|
|
124
62
|
return unless edge.aggregates.any? { |declared| !declared.computes.empty? || !declared.rekeys.empty? }
|
|
125
63
|
|
|
@@ -139,28 +77,8 @@ module Hecks
|
|
|
139
77
|
"human approved no longer cover the data; re-run bin/translation_audit with --approve"
|
|
140
78
|
end
|
|
141
79
|
|
|
142
|
-
# Refuses
|
|
143
|
-
#
|
|
144
|
-
#
|
|
145
|
-
# No edge yet: the boot refuses toward the authoring loop —
|
|
146
|
-
# naming both tools and the era ordinal. With HECKS_SCAFFOLD=1
|
|
147
|
-
# the boot runs the scaffold first (an explicit flag, never a
|
|
148
|
-
# silent side-effect) and the refusal names the file it wrote.
|
|
149
|
-
#
|
|
150
|
-
# @param registry [Runtime::Registry] the registry, forwarded to `scaffold!` when
|
|
151
|
-
# scaffolding is on
|
|
152
|
-
# @param bluebook [Bluebook::Chapter] the domain, named in the refusal
|
|
153
|
-
# @param lineage [Adapters::PostgresEra::Lineage] the domain's lineage, forwarded
|
|
154
|
-
# to `scaffold!` when scaffolding is on
|
|
155
|
-
# @param latest [Hash{Symbol => Object}] the newest held era, forwarded to
|
|
156
|
-
# `scaffold!` when scaffolding is on
|
|
157
|
-
# @param ordinal [Integer] the ordinal of the era about to be minted, named in
|
|
158
|
-
# the refusal
|
|
159
|
-
# @param directory [String, nil] the domain's bluebook directory; scaffolding
|
|
160
|
-
# requires this to be present as well as `HECKS_SCAFFOLD=1`
|
|
161
|
-
# @return [void] never returns
|
|
162
|
-
# @raise [Runtime::WiringError] always; the message names the scaffolded file
|
|
163
|
-
# when `HECKS_SCAFFOLD=1` and `directory` wrote one
|
|
80
|
+
# Refuses toward the authoring loop, or, under HECKS_SCAFFOLD=1, scaffolds the
|
|
81
|
+
# missing edge first and names the file it wrote.
|
|
164
82
|
def refuse_toward_the_scaffold!(registry, bluebook, lineage, latest, ordinal, directory)
|
|
165
83
|
if ENV["HECKS_SCAFFOLD"] == "1" && directory
|
|
166
84
|
path = scaffold!(registry, bluebook, lineage, latest, directory)
|
|
@@ -175,19 +93,8 @@ module Hecks
|
|
|
175
93
|
"check it with bin/translation_audit, then boot again"
|
|
176
94
|
end
|
|
177
95
|
|
|
178
|
-
# Diffs the held era against the current shape and writes the edge
|
|
179
|
-
#
|
|
180
|
-
# `unresolved` lines.
|
|
181
|
-
#
|
|
182
|
-
# @param _registry [Runtime::Registry] unused; kept so the signature matches its
|
|
183
|
-
# caller's own arguments
|
|
184
|
-
# @param bluebook [Bluebook::Chapter] the domain as currently declared
|
|
185
|
-
# @param lineage [Adapters::PostgresEra::Lineage] the domain's lineage; named so
|
|
186
|
-
# `ensure_named!` can mint a name for `latest` first if it has none
|
|
187
|
-
# @param latest [Hash{Symbol => Object}] the newest held era, as `Lineage#eras`
|
|
188
|
-
# returns it
|
|
189
|
-
# @param directory [String] the domain's bluebook directory to write the edge under
|
|
190
|
-
# @return [String] the path `Translation::Scaffold::Writer#write!` wrote
|
|
96
|
+
# Diffs the held era against the current shape and writes the edge file —
|
|
97
|
+
# confident rules inline, ambiguities as parse-refusing `unresolved` lines.
|
|
191
98
|
def scaffold!(_registry, bluebook, lineage, latest, directory)
|
|
192
99
|
ensure_named!(lineage, latest)
|
|
193
100
|
latest = lineage.eras.last
|
|
@@ -209,15 +116,7 @@ module Hecks
|
|
|
209
116
|
|
|
210
117
|
# Mints a name for an era that has none yet, leaving an already-named era untouched.
|
|
211
118
|
#
|
|
212
|
-
# Era names are minted once
|
|
213
|
-
# seen has no name yet; it gets one the moment an edge needs to
|
|
214
|
-
# leave it.
|
|
215
|
-
#
|
|
216
|
-
# @param lineage [Adapters::PostgresEra::Lineage] the domain's lineage, which
|
|
217
|
-
# records the minted name
|
|
218
|
-
# @param era [Hash{Symbol => Object}] the era to name, as `Lineage#eras` returns it;
|
|
219
|
-
# `:hash` present means it is already named
|
|
220
|
-
# @return [void]
|
|
119
|
+
# Era names are minted once, the moment an edge first needs to leave that era.
|
|
221
120
|
def ensure_named!(lineage, era)
|
|
222
121
|
return if era[:hash]
|
|
223
122
|
|
|
@@ -10,26 +10,8 @@ require_relative "../../../../../runtime/registry"
|
|
|
10
10
|
module Hecks
|
|
11
11
|
module Adapters
|
|
12
12
|
class PostgresEra
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
# acts: a drifted shape whose translation edge exists, matches by
|
|
16
|
-
# shape label, covers the whole diff, and passes the audit mints
|
|
17
|
-
# the next era — one transaction — and boots into it. Everything
|
|
18
|
-
# else refuses, as loudly and as specifically as the situation
|
|
19
|
-
# allows, naming both authoring tools.
|
|
20
|
-
#
|
|
21
|
-
# Minting happens here, once: era identity (SHA-256 of the canonical
|
|
22
|
-
# storage-shape serialization; the short prefix is the label edges
|
|
23
|
-
# and refusals use) is computed at mint time and stored in
|
|
24
|
-
# hecks_eras. Everything else reads stored names and never hashes
|
|
25
|
-
# anything — an era name is a storage fact, minted on this path or
|
|
26
|
-
# absent, never reconstructed.
|
|
27
|
-
#
|
|
28
|
-
# One concern per file under lineage_manager/: era_resolver (which
|
|
29
|
-
# era is this boot?), minter (the mint path and its refusals),
|
|
30
|
-
# merge_coordinator (bin/merge_tail's driver), coverage_check
|
|
31
|
-
# (what a mint must prove first). What stays here is what they
|
|
32
|
-
# share: the edge chain, and the shadow parse.
|
|
13
|
+
# PostgresEra's era gate: mints the next era when an edge covers the drift, else refuses.
|
|
14
|
+
# Era names are hashed once at mint time and stored in hecks_eras, never reconstructed.
|
|
33
15
|
module LineageManager
|
|
34
16
|
extend EraResolver
|
|
35
17
|
extend Minter
|
|
@@ -39,23 +21,14 @@ module Hecks
|
|
|
39
21
|
module_function
|
|
40
22
|
|
|
41
23
|
# Collects the translation edge for every step from era 1 to the current shape.
|
|
24
|
+
# Each mint required its own edge, so a gap in the chain means a deleted file.
|
|
42
25
|
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
# deleted file, and deserves its own refusal.
|
|
47
|
-
#
|
|
48
|
-
# @param registry [Runtime::Registry] the registry whose loaded `translations`
|
|
49
|
-
# are searched
|
|
50
|
-
# @param bluebook [Bluebook::Chapter] the domain; only edges declared for its
|
|
51
|
-
# name are considered
|
|
52
|
-
# @param eras [Array<Hash{Symbol => Object}>] the ancestor eras in ordinal order,
|
|
53
|
-
# as `Lineage#eras` returns them; only `:label` is read
|
|
26
|
+
# @param registry [Runtime::Registry] the registry whose loaded `translations` are searched
|
|
27
|
+
# @param bluebook [Bluebook::Chapter] the domain; only edges for its name count
|
|
28
|
+
# @param eras [Array<Hash>] the ancestor eras in order, as `Lineage#eras` returns them
|
|
54
29
|
# @param current_label [String] the shape label the last step must lead to
|
|
55
|
-
# @return [Array<Hash
|
|
56
|
-
#
|
|
57
|
-
# @raise [Runtime::WiringError] if no loaded translation leads one label to the
|
|
58
|
-
# next
|
|
30
|
+
# @return [Array<Hash>] one `{ translation: edge }` per step, in mint order
|
|
31
|
+
# @raise [Runtime::WiringError] if no loaded translation leads one label to the next
|
|
59
32
|
def edge_chain(registry, bluebook, eras, current_label)
|
|
60
33
|
labels = eras.map { |era| era[:label] } + [current_label]
|
|
61
34
|
(0...(labels.size - 1)).map do |index|
|
|
@@ -71,18 +44,13 @@ module Hecks
|
|
|
71
44
|
end
|
|
72
45
|
end
|
|
73
46
|
|
|
74
|
-
# Parses a held era's bluebook text into a throwaway registry,
|
|
75
|
-
# one untouched.
|
|
47
|
+
# Parses a held era's bluebook text into a throwaway registry, not the live one.
|
|
76
48
|
#
|
|
77
|
-
#
|
|
78
|
-
# extractor reads source from disk at the eval path — so a
|
|
79
|
-
# shadow parse writes the text to a scratch file first.
|
|
49
|
+
# The predicate extractor reads source from disk, so the text goes through a scratch file.
|
|
80
50
|
#
|
|
81
|
-
# @param source [String] bluebook source text
|
|
82
|
-
# @return [Bluebook::Chapter, nil] the first bluebook the text declares
|
|
83
|
-
#
|
|
84
|
-
# @raise [Bluebook::DSL::Malformed] if the text parses under neither the current
|
|
85
|
-
# grammar nor the legacy shadow-parse fallback
|
|
51
|
+
# @param source [String] bluebook source text from `hecks_eras.held_text`
|
|
52
|
+
# @return [Bluebook::Chapter, nil] the first bluebook the text declares
|
|
53
|
+
# @raise [Bluebook::DSL::Malformed] if the text parses under neither grammar
|
|
86
54
|
def shadow(source)
|
|
87
55
|
file = Tempfile.new(["hecks-era-", ".bluebook"])
|
|
88
56
|
file.write(source)
|