hecks 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/hecks/adapters/driven/claude_code.rb +7 -7
- data/lib/hecks/adapters/driven/d1.rb +187 -23
- data/lib/hecks/adapters/driven/folder.rb +10 -10
- data/lib/hecks/adapters/driven/google_authentication.rb +8 -8
- data/lib/hecks/adapters/driven/governance_authorization.rb +31 -13
- data/lib/hecks/adapters/driven/heki/journal.rb +5 -4
- data/lib/hecks/adapters/driven/heki/saga_store.rb +5 -5
- data/lib/hecks/adapters/driven/heki.rb +13 -7
- data/lib/hecks/adapters/driven/identity_registry.rb +2 -2
- data/lib/hecks/adapters/driven/in_memory_ordering.rb +3 -3
- data/lib/hecks/adapters/driven/lambda/client.rb +34 -9
- data/lib/hecks/adapters/driven/lambda.rb +39 -33
- data/lib/hecks/adapters/driven/local_storage.rb +17 -10
- data/lib/hecks/adapters/driven/memory.rb +205 -9
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +1 -1
- data/lib/hecks/adapters/driven/postgres/codec.rb +27 -11
- data/lib/hecks/adapters/driven/postgres/outbox.rb +40 -2
- data/lib/hecks/adapters/driven/postgres/reconnect.rb +23 -7
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +14 -14
- data/lib/hecks/adapters/driven/postgres.rb +175 -28
- data/lib/hecks/adapters/driven/prism.rb +4 -4
- data/lib/hecks/adapters/driven/sql_query_builder.rb +34 -22
- data/lib/hecks/adapters/driven/sqlite/codec.rb +38 -10
- data/lib/hecks/adapters/driven/sqlite/projection.rb +60 -32
- data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +12 -12
- data/lib/hecks/adapters/driven/sqlite.rb +181 -21
- data/lib/hecks/adapters/driven.rb +4 -4
- data/lib/hecks/adapters/driving/github_webhook.rb +18 -18
- data/lib/hecks/behaviors/dsl.rb +2 -2
- data/lib/hecks/behaviors/expectations.rb +23 -23
- data/lib/hecks/behaviors/ir.rb +1 -1
- data/lib/hecks/behaviors/rspec.rb +1 -1
- data/lib/hecks/behaviors/runner.rb +2 -2
- data/lib/hecks/behaviors.rb +1 -1
- data/lib/hecks/bluebook/aggregate.rb +13 -13
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +10 -10
- data/lib/hecks/bluebook/assembly/build.rb +1 -1
- data/lib/hecks/bluebook/assembly/contract.rb +39 -16
- data/lib/hecks/bluebook/assembly/contracts.rb +40 -38
- data/lib/hecks/bluebook/assembly/marks.rb +18 -18
- data/lib/hecks/bluebook/assembly/specializer.rb +19 -21
- data/lib/hecks/bluebook/assembly.rb +9 -9
- data/lib/hecks/bluebook/attribute.rb +9 -9
- data/lib/hecks/bluebook/behaviour/aggregate.rb +11 -11
- data/lib/hecks/bluebook/behaviour/attribute.rb +5 -5
- data/lib/hecks/bluebook/behaviour/chapter.rb +23 -5
- data/lib/hecks/bluebook/behaviour/command.rb +23 -23
- data/lib/hecks/bluebook/behaviour/domain_port.rb +7 -7
- data/lib/hecks/bluebook/behaviour/entity.rb +8 -8
- data/lib/hecks/bluebook/behaviour/hexagon.rb +4 -4
- data/lib/hecks/bluebook/behaviour/lifecycle.rb +5 -5
- data/lib/hecks/bluebook/behaviour/policy.rb +12 -12
- data/lib/hecks/bluebook/behaviour/process_manager.rb +7 -7
- data/lib/hecks/bluebook/behaviour/query.rb +1 -1
- data/lib/hecks/bluebook/behaviour/read_model.rb +8 -8
- data/lib/hecks/bluebook/behaviour/traits.rb +12 -12
- data/lib/hecks/bluebook/behaviour/value_object.rb +6 -6
- data/lib/hecks/bluebook/capabilities.rb +27 -0
- data/lib/hecks/bluebook/chapter.rb +28 -9
- data/lib/hecks/bluebook/command.rb +12 -12
- data/lib/hecks/bluebook/domain_port.rb +9 -9
- data/lib/hecks/bluebook/dsl/adapter_builder.rb +24 -0
- data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +49 -49
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +96 -96
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +41 -41
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +22 -2
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +111 -74
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +48 -30
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +116 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +103 -103
- data/lib/hecks/bluebook/dsl/const_shim.rb +46 -15
- data/lib/hecks/bluebook/dsl/domain_port_builder.rb +90 -25
- data/lib/hecks/bluebook/dsl/entity_builder.rb +56 -56
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +148 -132
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +89 -30
- data/lib/hecks/bluebook/dsl/identity_declaration.rb +17 -17
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +27 -4
- data/lib/hecks/bluebook/dsl/policy_builder.rb +30 -21
- data/lib/hecks/bluebook/dsl/port_builder.rb +38 -7
- data/lib/hecks/bluebook/dsl/port_operation_builder.rb +56 -22
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +35 -35
- data/lib/hecks/bluebook/dsl/query_builder.rb +5 -5
- data/lib/hecks/bluebook/dsl/read_model_builder.rb +34 -34
- data/lib/hecks/bluebook/dsl/rule_reference.rb +41 -39
- data/lib/hecks/bluebook/dsl/translation_builder.rb +9 -9
- data/lib/hecks/bluebook/dsl/value_object_builder.rb +16 -16
- data/lib/hecks/bluebook/dsl/word_gate.rb +59 -53
- data/lib/hecks/bluebook/dsl/world_builder.rb +51 -8
- data/lib/hecks/bluebook/entity.rb +11 -11
- data/lib/hecks/bluebook/expression/ast_json.rb +20 -20
- data/lib/hecks/bluebook/expression/ast_reader.rb +3 -3
- data/lib/hecks/bluebook/expression/canonical_form.rb +9 -9
- data/lib/hecks/bluebook/expression/evaluator.rb +18 -18
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +18 -18
- data/lib/hecks/bluebook/expression/resolver.rb +60 -62
- data/lib/hecks/bluebook/hexagon.rb +1 -1
- data/lib/hecks/bluebook/lifecycle.rb +1 -1
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -1
- data/lib/hecks/bluebook/meta_validator/judge.rb +101 -87
- data/lib/hecks/bluebook/meta_validator/plan.rb +39 -39
- data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -2
- data/lib/hecks/bluebook/meta_validator/readings.rb +43 -43
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +44 -37
- data/lib/hecks/bluebook/meta_validator/shapes.rb +25 -21
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +145 -31
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +6 -6
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +5 -5
- data/lib/hecks/bluebook/meta_validator.rb +70 -70
- data/lib/hecks/bluebook/model_check.rb +170 -84
- data/lib/hecks/bluebook/pattern_subset.rb +9 -9
- data/lib/hecks/bluebook/policy.rb +15 -13
- data/lib/hecks/bluebook/process_manager.rb +14 -14
- data/lib/hecks/bluebook/project_register.rb +6 -6
- data/lib/hecks/bluebook/query.rb +4 -4
- data/lib/hecks/bluebook/read_model.rb +14 -14
- data/lib/hecks/bluebook/reference.rb +8 -8
- data/lib/hecks/bluebook/smoke_test.rb +19 -19
- data/lib/hecks/bluebook/synthesizer.rb +12 -12
- data/lib/hecks/bluebook/translation.rb +4 -4
- data/lib/hecks/bluebook/value_object.rb +6 -6
- data/lib/hecks/bluebook.rb +2 -2
- data/lib/hecks/codemod/legacy_dispatch_args.rb +299 -0
- data/lib/hecks/codemod/legacy_dispatch_recorder.rb +186 -0
- data/lib/hecks/codemod.rb +36 -35
- data/lib/hecks/construct.rb +6 -6
- data/lib/hecks/corpus.rb +317 -0
- data/lib/hecks/deprecation.rb +95 -0
- data/lib/hecks/doc/reference.rb +19 -19
- data/lib/hecks/embryonaut_bluebook.rb +11 -11
- data/lib/hecks/facade/cli_door.rb +69 -10
- data/lib/hecks/facade/cli_runner.rb +105 -24
- data/lib/hecks/facade/command_request.rb +23 -0
- data/lib/hecks/facade/handle.rb +79 -32
- data/lib/hecks/facade/json_door.rb +106 -25
- data/lib/hecks/facade/surface/aggregate_door.rb +42 -27
- data/lib/hecks/facade/surface/chapter.rb +26 -17
- data/lib/hecks/facade/surface.rb +16 -3
- data/lib/hecks/facade.rb +15 -4
- data/lib/hecks/forms/app.rb +46 -30
- data/lib/hecks/forms/command_form_renderer.rb +70 -9
- data/lib/hecks/forms/field_renderer.rb +142 -6
- data/lib/hecks/forms/field_shape.rb +180 -19
- data/lib/hecks/forms/html.rb +51 -7
- data/lib/hecks/forms/index_renderer.rb +14 -2
- data/lib/hecks/forms/params.rb +120 -23
- data/lib/hecks/forms/port_argument.rb +2 -2
- data/lib/hecks/forms/query_form_renderer.rb +2 -2
- data/lib/hecks/forms/record_renderer.rb +2 -2
- data/lib/hecks/forms/record_table.rb +1 -1
- data/lib/hecks/forms/value_object_shape.rb +3 -3
- data/lib/hecks/forms.rb +24 -4
- data/lib/hecks/fqn.rb +1 -1
- data/lib/hecks/framework/bluebook/governance.bluebook +9 -0
- data/lib/hecks/framework.rb +48 -17
- data/lib/hecks/freezer.rb +11 -11
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +90 -90
- data/lib/hecks/fuzzing/combination_miner.rb +119 -0
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +140 -45
- data/lib/hecks/fuzzing/coverage_campaign.rb +118 -0
- data/lib/hecks/fuzzing/differential.rb +158 -0
- data/lib/hecks/fuzzing/domain_generator.rb +694 -0
- data/lib/hecks/fuzzing/era_boundary.rb +37 -18
- data/lib/hecks/fuzzing/form_census.rb +35 -20
- data/lib/hecks/fuzzing/generated_domain_check.rb +95 -0
- data/lib/hecks/fuzzing/invalid_value_generator.rb +6 -6
- data/lib/hecks/fuzzing/isolated_boot.rb +62 -62
- data/lib/hecks/fuzzing/nondeterministic.rb +67 -0
- data/lib/hecks/fuzzing/persistence_parity.rb +19 -21
- data/lib/hecks/fuzzing/properties/corrections.rb +9 -9
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +154 -49
- data/lib/hecks/fuzzing/properties/guards.rb +42 -42
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +32 -32
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +22 -35
- data/lib/hecks/fuzzing/properties/outbox.rb +24 -24
- data/lib/hecks/fuzzing/properties/querying.rb +17 -17
- data/lib/hecks/fuzzing/properties.rb +64 -40
- data/lib/hecks/fuzzing/qa_settings.rb +152 -0
- data/lib/hecks/fuzzing/replay.rb +114 -114
- data/lib/hecks/fuzzing/rotation_priority.rb +10 -10
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +113 -0
- data/lib/hecks/fuzzing/self_consistency.rb +141 -112
- data/lib/hecks/fuzzing/sequence_generator/adversary.rb +35 -35
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +18 -11
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +13 -12
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +21 -12
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +58 -31
- data/lib/hecks/fuzzing/sequence_generator.rb +111 -23
- data/lib/hecks/fuzzing/shrinker.rb +197 -0
- data/lib/hecks/fuzzing/structural_skips.rb +23 -130
- data/lib/hecks/fuzzing/sweep_depth.rb +4 -4
- data/lib/hecks/fuzzing/target_capabilities.rb +49 -18
- data/lib/hecks/fuzzing/value_generator.rb +14 -14
- data/lib/hecks/fuzzing.rb +5 -0
- data/lib/hecks/grammar/evolve.rb +10 -10
- data/lib/hecks/grammar.rb +7 -7
- data/lib/hecks/ir.rb +13 -13
- data/lib/hecks/language/bluebook/bluebook.bluebook +41 -0
- data/lib/hecks/language/bluebook/policy.bluebook +11 -1
- data/lib/hecks/language/bluebook/vocabulary.bluebook +348 -13
- data/lib/hecks/language/oidc.json +5 -0
- data/lib/hecks/literal.rb +9 -9
- data/lib/hecks/naming.rb +25 -25
- data/lib/hecks/ports/access_control.rb +58 -2
- data/lib/hecks/ports/agent/answers.rb +83 -6
- data/lib/hecks/ports/agent.rb +119 -35
- data/lib/hecks/ports/authentication.rb +44 -4
- data/lib/hecks/ports/authorization.rb +53 -11
- data/lib/hecks/ports/clock.rb +42 -23
- data/lib/hecks/ports/extraction.rb +16 -0
- data/lib/hecks/ports/identity_assignment.rb +24 -2
- data/lib/hecks/ports/identity_generation.rb +17 -3
- data/lib/hecks/ports/identity_resolution.rb +18 -1
- data/lib/hecks/ports/loading.rb +4 -0
- data/lib/hecks/ports/persistence/append_only.rb +172 -8
- data/lib/hecks/ports/persistence/binding_policy.rb +34 -0
- data/lib/hecks/ports/persistence/codec_boundary.rb +178 -0
- data/lib/hecks/ports/persistence/execution.rb +4 -0
- data/lib/hecks/ports/persistence/null_saga_store.rb +12 -1
- data/lib/hecks/ports/persistence/plugin.rb +42 -4
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +218 -25
- data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +77 -9
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +81 -24
- data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +29 -18
- data/lib/hecks/ports/persistence/plugins/era/lineage.rb +144 -60
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +103 -8
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +98 -23
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +282 -109
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +63 -25
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +118 -66
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +51 -28
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +28 -5
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +25 -12
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +129 -34
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +51 -6
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +33 -9
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +16 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +57 -4
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +25 -2
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +314 -90
- data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +68 -10
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +9 -3
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +9 -2
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +42 -8
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +16 -1
- data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +36 -5
- data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +23 -3
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +18 -19
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +5 -5
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -2
- data/lib/hecks/ports/persistence/plugins/era.rb +12 -2
- data/lib/hecks/ports/persistence/remote_runtime.rb +9 -2
- data/lib/hecks/ports/persistence/repository_factory.rb +23 -3
- data/lib/hecks/ports/persistence/state_codec.rb +319 -0
- data/lib/hecks/ports/persistence.rb +36 -1
- data/lib/hecks/ports/projection.rb +61 -7
- data/lib/hecks/ports/query/in_memory.rb +3 -3
- data/lib/hecks/ports/query/ordering.rb +6 -6
- data/lib/hecks/ports/query.rb +35 -0
- data/lib/hecks/projections/bootstrap_table.rb +112 -0
- data/lib/hecks/projections/diagrams.rb +75 -75
- data/lib/hecks/projections/glossary/html.rb +3 -3
- data/lib/hecks/projections/glossary/markdown.rb +3 -3
- data/lib/hecks/projections/glossary/mermaid.rb +1 -1
- data/lib/hecks/projections/glossary/sections.rb +1 -1
- data/lib/hecks/projections/glossary/sentences.rb +5 -5
- data/lib/hecks/projections/glossary.rb +15 -15
- data/lib/hecks/projections/ir.rb +1 -1
- data/lib/hecks/projections/model/deviations.rb +18 -17
- data/lib/hecks/projections/model.rb +25 -21
- data/lib/hecks/projections/oidc.rb +7 -7
- data/lib/hecks/projections/parser_table.rb +5 -5
- data/lib/hecks/projections/reference.rb +3 -3
- data/lib/hecks/projections/rust_vocabulary.rb +443 -0
- data/lib/hecks/projections/shape.rb +2 -2
- data/lib/hecks/projections/statements.rb +11 -11
- data/lib/hecks/projections/vocabulary.rb +9 -9
- data/lib/hecks/projections.rb +5 -3
- data/lib/hecks/projector/cli_projector.rb +29 -29
- data/lib/hecks/projector/docs_projector.rb +13 -13
- data/lib/hecks/projector/exporter.rb +42 -21
- data/lib/hecks/projector/ir_projector.rb +1 -1
- data/lib/hecks/projector/narrate_projector.rb +11 -11
- data/lib/hecks/projector/target.rb +13 -13
- data/lib/hecks/projector.rb +15 -15
- data/lib/hecks/query_ir.rb +47 -47
- data/lib/hecks/query_specification/common/comparators.rb +19 -3
- data/lib/hecks/query_specification/common/comparison.rb +109 -27
- data/lib/hecks/query_specification/common/dsl.rb +65 -9
- data/lib/hecks/query_specification/common/null_policy.rb +57 -13
- data/lib/hecks/query_specification/common/null_semantics.rb +4 -0
- data/lib/hecks/query_specification/common/options.rb +25 -0
- data/lib/hecks/query_specification/field_path.rb +69 -15
- data/lib/hecks/query_specification/hop_path.rb +57 -20
- data/lib/hecks/query_specification/read_model/specification.rb +4 -0
- data/lib/hecks/rendering.rb +3 -3
- data/lib/hecks/router/namespace_installer.rb +3 -3
- data/lib/hecks/router.rb +1 -1
- data/lib/hecks/runtime/aggregate_lock.rb +11 -11
- data/lib/hecks/runtime/boot_gates.rb +3 -3
- data/lib/hecks/runtime/caller.rb +8 -8
- data/lib/hecks/runtime/capability_graph.rb +2 -2
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +22 -25
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +42 -63
- data/lib/hecks/runtime/command_interpreter.rb +159 -102
- data/lib/hecks/runtime/command_rules/admissibility.rb +69 -69
- data/lib/hecks/runtime/command_rules/arithmetic.rb +137 -91
- data/lib/hecks/runtime/command_rules/authorization.rb +38 -17
- data/lib/hecks/runtime/command_rules/emission.rb +18 -1
- data/lib/hecks/runtime/command_rules/references.rb +35 -35
- data/lib/hecks/runtime/command_rules.rb +3 -0
- data/lib/hecks/runtime/dependency_planning.rb +11 -11
- data/lib/hecks/runtime/dispatcher.rb +283 -90
- data/lib/hecks/runtime/entity_element.rb +151 -67
- data/lib/hecks/runtime/entity_interpreter.rb +108 -82
- data/lib/hecks/runtime/errors.rb +19 -19
- data/lib/hecks/runtime/event.rb +6 -6
- data/lib/hecks/runtime/identity.rb +22 -22
- data/lib/hecks/runtime/instance.rb +39 -14
- data/lib/hecks/runtime/interpreting.rb +12 -12
- data/lib/hecks/runtime/invocation.rb +276 -0
- data/lib/hecks/runtime/loader.rb +14 -14
- data/lib/hecks/runtime/outbox.rb +23 -23
- data/lib/hecks/runtime/policy_interpreter.rb +54 -54
- data/lib/hecks/runtime/port_operation_interpreter.rb +22 -19
- data/lib/hecks/runtime/query_interpreter.rb +55 -64
- data/lib/hecks/runtime/reaction_invocation.rb +20 -20
- data/lib/hecks/runtime/read_model_interpreter.rb +40 -40
- data/lib/hecks/runtime/rebuild_sweep.rb +4 -4
- data/lib/hecks/runtime/reference_hop.rb +6 -6
- data/lib/hecks/runtime/refusal_wording.rb +92 -115
- data/lib/hecks/runtime/registry/saga_persistence.rb +21 -21
- data/lib/hecks/runtime/registry/verification.rb +36 -26
- data/lib/hecks/runtime/registry.rb +45 -28
- data/lib/hecks/runtime/remote_dispatcher.rb +38 -23
- data/lib/hecks/runtime/routing.rb +10 -153
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +17 -17
- data/lib/hecks/runtime/saga_interpreter.rb +64 -64
- data/lib/hecks/runtime/saga_pending_dispatch.rb +12 -12
- data/lib/hecks/runtime/tenant_check.rb +9 -9
- data/lib/hecks/runtime/tenant_scope.rb +5 -5
- data/lib/hecks/runtime/value/admission.rb +75 -30
- data/lib/hecks/runtime/value/coercion.rb +318 -127
- data/lib/hecks/runtime/value/entity_list_coercion.rb +34 -34
- data/lib/hecks/runtime/value.rb +21 -21
- data/lib/hecks/runtime.rb +7 -7
- data/lib/hecks/storehouse.rb +64 -64
- data/lib/hecks/version.rb +3 -3
- data/lib/hecks/vocabulary.rb +205 -4
- data/lib/hecks.rb +13 -11
- data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +11 -11
- data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +14 -12
- data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +11 -11
- metadata +22 -2
|
@@ -14,32 +14,32 @@ require_relative "properties/outbox"
|
|
|
14
14
|
|
|
15
15
|
module Hecks
|
|
16
16
|
module Fuzzing
|
|
17
|
-
# Declared properties, checked over a
|
|
17
|
+
# Declared properties, checked over a replayed history — the other
|
|
18
18
|
# half of property-based testing the fuzzer was missing: it already
|
|
19
19
|
# generates and (with bin/fuzz's shrinker) minimizes, but checked
|
|
20
20
|
# nothing beyond "did the interpreter crash" and "did the replay
|
|
21
21
|
# match the claim." A property here is a fact that should hold of
|
|
22
|
-
#
|
|
22
|
+
# any history a valid domain produces, independent of which seed
|
|
23
23
|
# produced it.
|
|
24
24
|
#
|
|
25
25
|
# Each property is `name => ->(history) { true/false, or a message
|
|
26
26
|
# string naming what broke }` — a truthy return (including `true`)
|
|
27
|
-
# is a pass; a String return is a failure, and the string
|
|
27
|
+
# is a pass; a String return is a failure, and the string is the
|
|
28
28
|
# finding. `history` is Replay's return shape.
|
|
29
29
|
#
|
|
30
|
-
#
|
|
30
|
+
# Every property declares the language feature it covers, in
|
|
31
31
|
# `FEATURE_COVERAGE` below — a "Construct#attribute" pair spelled
|
|
32
32
|
# exactly as `Bluebook::MetaValidator.grammar_registry` names it,
|
|
33
|
-
# the
|
|
33
|
+
# the same meta-domain that judges every real bluebook (see that
|
|
34
34
|
# module's own header: "the language IS the source"). That is the
|
|
35
35
|
# link this file exists to make real: a construct the language
|
|
36
36
|
# declares is a fact `spec/meta_domain_coverage_spec.rb` can
|
|
37
37
|
# enumerate on its own, without anyone re-typing the list here —
|
|
38
38
|
# so a new attribute added to `language/bluebook/*.bluebook` shows
|
|
39
|
-
# up in that spec as
|
|
39
|
+
# up in that spec as unclaimed the moment it lands, not whenever
|
|
40
40
|
# someone remembers to go looking. Claiming a feature here is a
|
|
41
41
|
# deliberate act (a real property, checked at least once failing
|
|
42
|
-
#
|
|
42
|
+
# and once passing — `spec/fuzzing/properties_spec.rb`'s own
|
|
43
43
|
# discipline) or an explicit, reasoned exemption in that same
|
|
44
44
|
# spec — never silence.
|
|
45
45
|
module Properties
|
|
@@ -64,11 +64,11 @@ module Hecks
|
|
|
64
64
|
|
|
65
65
|
module_function
|
|
66
66
|
|
|
67
|
-
#
|
|
67
|
+
# Which language feature each property is answerable for. Not
|
|
68
68
|
# exhaustive of everything a property's body happens to touch —
|
|
69
69
|
# `Command#attributes`, say, is exercised by nearly every property
|
|
70
|
-
# here without being what any of them was
|
|
71
|
-
# exhaustive of the feature that would go
|
|
70
|
+
# here without being what any of them was written to guard — but
|
|
71
|
+
# exhaustive of the feature that would go unchecked if this
|
|
72
72
|
# property did not exist. That is the question the coverage gate
|
|
73
73
|
# actually asks.
|
|
74
74
|
FEATURE_COVERAGE = {
|
|
@@ -80,17 +80,17 @@ module Hecks
|
|
|
80
80
|
authorize_scopes_or_refuses: %w[Query#options],
|
|
81
81
|
guard_refusals_are_declared: %w[Command#givens Command#ensures],
|
|
82
82
|
lifecycle_guard_and_given_violations_are_refused: %w[Command#from Aggregate#preconditions Entity#preconditions],
|
|
83
|
-
# Dispatch#command_name/Dispatch#with_spec are
|
|
84
|
-
# feature names — META_DOMAIN_ALL_FEATURES only walks
|
|
83
|
+
# Dispatch#command_name/Dispatch#with_spec are not claimable
|
|
84
|
+
# feature names — META_DOMAIN_ALL_FEATURES only walks one level
|
|
85
85
|
# of entity nesting (`agg.entities.flat_map`, meta_domain_
|
|
86
|
-
# coverage_spec.rb), and Dispatch sits
|
|
86
|
+
# coverage_spec.rb), and Dispatch sits two deep (ProcessManager
|
|
87
87
|
# -> Handler -> Dispatch), so those strings never exist there
|
|
88
88
|
# to claim — a pre-existing meta-domain coverage-generation gap,
|
|
89
89
|
# found here (their old META_DOMAIN_KNOWN_GAPS entries were
|
|
90
90
|
# themselves already-orphaned strings no completeness check ever
|
|
91
91
|
# verified, since KNOWN_GAPS has no "never lets a gap rot" check
|
|
92
92
|
# the way FEATURE_COVERAGE/GUARANTEED_BY_CONSTRUCTION both do).
|
|
93
|
-
# This property still closes the
|
|
93
|
+
# This property still closes the real behavior both would have
|
|
94
94
|
# named — a Dispatch's own command_name/with_spec are exactly
|
|
95
95
|
# what dispatch_args resolves and this property checks — the
|
|
96
96
|
# grammar just has no feature string for either one.
|
|
@@ -102,50 +102,69 @@ module Hecks
|
|
|
102
102
|
aggregation_matches_recompute: %w[ReadModel#count ReadModel#median_field],
|
|
103
103
|
stored_records_satisfy_declared_invariants: %w[Aggregate#invariants Entity#invariants],
|
|
104
104
|
group_by_matches_recompute: %w[ReadModel#group_by],
|
|
105
|
-
# A
|
|
105
|
+
# A runtime door, not a grammar construct — `Dispatcher#dry_run?`
|
|
106
106
|
# is something an application asks of a booted domain, not a
|
|
107
107
|
# word a bluebook can declare, so there is no feature string
|
|
108
108
|
# for it to claim. Listed (empty) rather than omitted so the
|
|
109
109
|
# discipline this table states — every property names what it
|
|
110
110
|
# is answerable for — has no silent exception.
|
|
111
111
|
dry_runs_leave_no_trace: [],
|
|
112
|
-
#
|
|
112
|
+
# Another runtime door, not a grammar construct — same reasoning
|
|
113
113
|
# as dry_runs_leave_no_trace right above: `Runtime::Outbox` is
|
|
114
114
|
# something a persistence adapter provides underneath a booted
|
|
115
115
|
# domain, never a word a bluebook declares.
|
|
116
|
-
outbox_rows_match_reactions: []
|
|
116
|
+
outbox_rows_match_reactions: [],
|
|
117
|
+
# **The `corrects` mutation's own target** — this property reads
|
|
118
|
+
# `command.mutations.select { op == :corrects }` and asks whether
|
|
119
|
+
# the event each one names was ever actually emitted, so the
|
|
120
|
+
# feature it answers for is the mutation list, the same one
|
|
121
|
+
# `mutations_match_recompute` reads for a different question.
|
|
122
|
+
# (Not `Command#references`: that field is the dangling-reference
|
|
123
|
+
# question no property asks yet, and it stays a named gap.)
|
|
124
|
+
corrections_reference_an_emitted_event: %w[Command#mutations],
|
|
125
|
+
# No feature string exists for what this one reads. It depends on
|
|
126
|
+
# an argument's own `relationship` (which reference-typed argument
|
|
127
|
+
# points at which aggregate) — but `Argument` is a value object,
|
|
128
|
+
# and the meta-domain walk enumerates aggregate and entity fields
|
|
129
|
+
# only, so no `Argument#…` name is claimable. The declaration side
|
|
130
|
+
# it shares with queries, `authorize …, tenant:`, is
|
|
131
|
+
# `Query#options`, already claimed by `authorize_scopes_or_refuses`;
|
|
132
|
+
# claiming it twice would say this property covers a query
|
|
133
|
+
# question it never asks. Listed (empty) rather than omitted, the
|
|
134
|
+
# same discipline the two runtime doors above keep.
|
|
135
|
+
commands_respect_tenant_scope: []
|
|
117
136
|
}.freeze
|
|
118
137
|
|
|
119
|
-
#
|
|
120
|
-
#
|
|
138
|
+
# Features a replay property could never catch violated, because the
|
|
139
|
+
# runtime's own construction makes the violation impossible to
|
|
121
140
|
# produce in the first place — not "untested," but unfalsifiable by
|
|
122
141
|
# a history, the same class of guarantee this codebase already
|
|
123
|
-
# states for identity ("
|
|
124
|
-
# own header) and now generalises. Each entry names the
|
|
142
|
+
# states for identity ("nothing is minted" — command_interpreter.rb's
|
|
143
|
+
# own header) and now generalises. Each entry names the one place in
|
|
125
144
|
# the runtime that makes it true, universally, for every domain and
|
|
126
145
|
# every adapter — never per-domain logic a future domain could
|
|
127
146
|
# accidentally route around.
|
|
128
147
|
#
|
|
129
|
-
#
|
|
130
|
-
# declares
|
|
148
|
+
# The bluebook/hecksagon boundary is why this works: a bluebook
|
|
149
|
+
# declares shape (attribute types, patterns, closed sets, VO
|
|
131
150
|
# invariants — see docs/decisions/0009), and shape is enforced by
|
|
132
|
-
#
|
|
151
|
+
# one coercion door every domain's every attribute passes through
|
|
133
152
|
# (`Runtime::Value.build`, via value/coercion.rb + value/admission.rb)
|
|
134
153
|
# regardless of which hecksagon later binds the aggregate to Memory,
|
|
135
154
|
# Postgres, or anything else. A value that violated its own declared
|
|
136
|
-
# pattern, invariant, or closed set could never be
|
|
137
|
-
# could never be
|
|
155
|
+
# pattern, invariant, or closed set could never be coerced, so it
|
|
156
|
+
# could never be stored, so it could never appear in a replay's own
|
|
138
157
|
# `:instances` to be caught violating it. Checking for it after the
|
|
139
158
|
# fact would be watching for something the construction path already
|
|
140
159
|
# made impossible.
|
|
141
160
|
#
|
|
142
|
-
#
|
|
143
|
-
# the
|
|
161
|
+
# Not a place to hide a real gap — a feature belongs here only once
|
|
162
|
+
# the specific enforcing code path has been read and confirmed, the
|
|
144
163
|
# same discipline `spec/fuzzing/meta_domain_coverage_spec.rb` demands
|
|
145
164
|
# of `KNOWN_GAPS` in the other direction. `Entity#identified_by` was
|
|
146
|
-
# checked
|
|
165
|
+
# checked for this category once before and found not to qualify —
|
|
147
166
|
# `command_interpreter.rb`'s `AlreadyExists` refusal was given to
|
|
148
|
-
# every
|
|
167
|
+
# every creating aggregate command uniformly, and MutationApplier
|
|
149
168
|
# (command_interpreter/mutation_applier.rb) had no matching check on
|
|
150
169
|
# an entity's own append. It does now: #check_entity_collision runs
|
|
151
170
|
# unconditionally on both branches an entity identity can arrive by
|
|
@@ -171,13 +190,18 @@ module Hecks
|
|
|
171
190
|
"(command_interpreter.rb, command.creates?) for every creating command uniformly, " \
|
|
172
191
|
"before a duplicate id can ever be stored — collision is refused at the door, not " \
|
|
173
192
|
"produced and later caught",
|
|
174
|
-
"Entity#identified_by" => "
|
|
175
|
-
"checks Array(current) against every part
|
|
176
|
-
"
|
|
177
|
-
"
|
|
178
|
-
"
|
|
179
|
-
"
|
|
180
|
-
"
|
|
193
|
+
"Entity#identified_by" => "EntityElement.check_entity_collision (runtime/entity_element.rb, moved there " \
|
|
194
|
+
"BUG#145 so both call sites share it) checks Array(current) against every part " \
|
|
195
|
+
"of the entity's own identity before an append can land — MutationApplier#" \
|
|
196
|
+
"entity_element's aggregate-owned call (Workspace.boards, on both branches " \
|
|
197
|
+
"identity arrives by: caller-supplied, or composite) AND EntityElement#" \
|
|
198
|
+
"appended_to_element's entity-owned, nested-one-hop-further call (Board.cards — " \
|
|
199
|
+
"unconditional, no auto-mint branch exists at that depth) — the same " \
|
|
200
|
+
"AlreadyExists refusal Aggregate#identified_by gets above, one or two levels " \
|
|
201
|
+
"down. Auto-minted (aggregate-owned) entities never reach the check " \
|
|
202
|
+
"(current.size + 1 can't repeat unless something remove:s from the list between " \
|
|
203
|
+
"mints, which no real domain does today — see the comment on #entity_element " \
|
|
204
|
+
"itself)",
|
|
181
205
|
"Command#attributes" => "command arguments are coerced through the SAME Value.build door as any other " \
|
|
182
206
|
"attribute — an accepted dispatch's own args already passed pattern/admits/invariant checks",
|
|
183
207
|
"Command#emits" => "CommandRules::Emission#emit iterates command.emits ITSELF to construct every " \
|
|
@@ -198,7 +222,7 @@ module Hecks
|
|
|
198
222
|
# ValueObject), so this reads "Member#pairs", not "Member#shape" —
|
|
199
223
|
# the free-text, un-parsed spelling a standalone root once needed
|
|
200
224
|
# no longer exists at all, an entity's own element is never
|
|
201
|
-
# serialized as text. "ValueObject#members" is the
|
|
225
|
+
# serialized as text. "ValueObject#members" is the same fact
|
|
202
226
|
# "ValueObject#rows" already counts, seen from the other side — a
|
|
203
227
|
# value object cannot declare admitted rows without a members list
|
|
204
228
|
# to hold them, and vice versa.
|
|
@@ -206,8 +230,8 @@ module Hecks
|
|
|
206
230
|
"Member#pairs" => "one level into ValueObject#rows — same door"
|
|
207
231
|
}.freeze
|
|
208
232
|
|
|
209
|
-
#
|
|
210
|
-
# except determinism, which needs to replay
|
|
233
|
+
# The standard battery, run over one replayed history — everything
|
|
234
|
+
# except determinism, which needs to replay twice itself and so
|
|
211
235
|
# takes the steps directly rather than a single history.
|
|
212
236
|
def check(history)
|
|
213
237
|
{ lifecycle_values_are_declared: lifecycle_values_are_declared(history),
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
require "yaml"
|
|
2
|
+
|
|
3
|
+
module Hecks
|
|
4
|
+
module Fuzzing
|
|
5
|
+
# Reads `qa/settings.yml` — the hecks_qa practice's own dials, now
|
|
6
|
+
# data in a file rather than Ruby constant literals. The why of each
|
|
7
|
+
# dial (what it does, who reads it) stays exactly one place: the
|
|
8
|
+
# comments on `QualityControlDials` in `qa/bluebook/quality_control.
|
|
9
|
+
# bluebook`, which now sources every value from an instance of this
|
|
10
|
+
# class instead of writing it inline. This class is only the loading
|
|
11
|
+
# and the validation — no dial policy lives here.
|
|
12
|
+
#
|
|
13
|
+
# **Fails loud, not quiet** — the whole practice's own opening line
|
|
14
|
+
# ("the enemy is the quiet divergence") applies to its own settings
|
|
15
|
+
# file too: a missing key, an extra key nothing recognises, or a
|
|
16
|
+
# value of the wrong shape all raise immediately, at load time
|
|
17
|
+
# (which is bluebook-load time, i.e. `Hecks.boot`), naming exactly
|
|
18
|
+
# what's wrong — never a `nil` dial silently reaching a script that
|
|
19
|
+
# assumes a number.
|
|
20
|
+
#
|
|
21
|
+
# **Plain data in, frozen data out**. `.load` parses the YAML with
|
|
22
|
+
# `Psych.safe_load_file` (no custom tags, no arbitrary Ruby objects)
|
|
23
|
+
# and hands back an instance whose accessors are the exact values a
|
|
24
|
+
# human wrote in the file — a `Hash`/`Array` for the nested dials,
|
|
25
|
+
# never a second, richer wrapper type nothing else in this practice
|
|
26
|
+
# expects.
|
|
27
|
+
class QaSettings
|
|
28
|
+
# One entry per dial this class knows about: the accessor name
|
|
29
|
+
# (matching `qa/settings.yml`'s own key, and `QualityControlDials`'
|
|
30
|
+
# constant name snake_cased) mapped to the class (or classes) a
|
|
31
|
+
# valid value must be an instance of. `TrueClass`/`FalseClass`
|
|
32
|
+
# both name a boolean dial — Ruby has no single class both `true`
|
|
33
|
+
# and `false` share. `Numeric` admits both an Integer and a Float
|
|
34
|
+
# for a fraction dial (`0` and `0.0` are both a human plausibly
|
|
35
|
+
# types for "off").
|
|
36
|
+
EXPECTED_TYPES = {
|
|
37
|
+
cadence_seconds: Integer,
|
|
38
|
+
pr_cap_per_day: Integer,
|
|
39
|
+
widening_tiers: Array,
|
|
40
|
+
sweep_max_parallel: Integer,
|
|
41
|
+
liveness_fallback_seconds: Integer,
|
|
42
|
+
draft_only: [TrueClass, FalseClass],
|
|
43
|
+
auto_merge: [TrueClass, FalseClass],
|
|
44
|
+
branch_prefix: String,
|
|
45
|
+
adversarial_fraction: Numeric,
|
|
46
|
+
guided_generation: [TrueClass, FalseClass],
|
|
47
|
+
corpus_splice_probability: Numeric,
|
|
48
|
+
favor_rare_verbs: Integer,
|
|
49
|
+
self_consistency_checks: [TrueClass, FalseClass],
|
|
50
|
+
shrink_budget: Integer,
|
|
51
|
+
yield_weight_seconds: Integer,
|
|
52
|
+
yield_decay_percent: Integer,
|
|
53
|
+
rotation_stale_floor_seconds: Integer,
|
|
54
|
+
persistence_parity_seed_cap: Integer,
|
|
55
|
+
concurrency_seed_cap: Integer,
|
|
56
|
+
adapter_parity_pairs: Hash,
|
|
57
|
+
modes: Hash,
|
|
58
|
+
role_draw_probability: Numeric,
|
|
59
|
+
dry_run_fraction: Numeric,
|
|
60
|
+
generated_domains_per_tick: Integer,
|
|
61
|
+
generated_domains_rust: [TrueClass, FalseClass],
|
|
62
|
+
generated_domain_seeds: Integer,
|
|
63
|
+
structural_refusal_boundary: Array
|
|
64
|
+
}.freeze
|
|
65
|
+
|
|
66
|
+
attr_reader(*EXPECTED_TYPES.keys)
|
|
67
|
+
|
|
68
|
+
# **The real file, always** — resolved off this file's own `__dir__`
|
|
69
|
+
# (lib/hecks/fuzzing/), never off the caller's. `QualityControlDials`
|
|
70
|
+
# is defined inside `qa/bluebook/quality_control.bluebook`, and that
|
|
71
|
+
# exact directory gets copied to a tmpdir for every isolated/replayed
|
|
72
|
+
# boot (`Hecks::Fuzzing::IsolatedBoot#copy_dereferencing` copies only
|
|
73
|
+
# `qa/bluebook`'s own contents, never its parent `qa/`) — a path
|
|
74
|
+
# resolved from the bluebook's own `__dir__` would silently point at
|
|
75
|
+
# a copy with no `settings.yml` beside it at all. `qa/settings.yml`
|
|
76
|
+
# is read-only, human-edited data with no lifecycle (see this class's
|
|
77
|
+
# own header) — there is no isolation reason to ever read a copy of
|
|
78
|
+
# it, real boot or fuzzed one, so every caller gets the one real file
|
|
79
|
+
# by default. `qa_settings_spec.rb` passes its own fixture paths
|
|
80
|
+
# explicitly instead, the same way every other test in this practice
|
|
81
|
+
# that needs a non-default dial passes one in rather than mutating
|
|
82
|
+
# global state.
|
|
83
|
+
DEFAULT_PATH = File.expand_path("../../../qa/settings.yml", __dir__)
|
|
84
|
+
|
|
85
|
+
class << self
|
|
86
|
+
def load(path = DEFAULT_PATH)
|
|
87
|
+
raise ArgumentError, "qa settings file not found: #{path}" unless File.file?(path)
|
|
88
|
+
|
|
89
|
+
raw = begin
|
|
90
|
+
YAML.safe_load_file(path, symbolize_names: true)
|
|
91
|
+
rescue Psych::SyntaxError => e
|
|
92
|
+
raise ArgumentError, "#{path} is not valid YAML: #{e.message}"
|
|
93
|
+
end
|
|
94
|
+
raise ArgumentError, "#{path} must be a YAML mapping at the top level, got #{raw.class}" unless raw.is_a?(Hash)
|
|
95
|
+
|
|
96
|
+
new(raw, path)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def initialize(raw, path)
|
|
101
|
+
missing = EXPECTED_TYPES.keys - raw.keys
|
|
102
|
+
raise ArgumentError, "#{path} is missing #{missing.sort.join(', ')}" if missing.any?
|
|
103
|
+
|
|
104
|
+
extra = raw.keys - EXPECTED_TYPES.keys
|
|
105
|
+
if extra.any?
|
|
106
|
+
raise ArgumentError,
|
|
107
|
+
"#{path} declares unknown key(s) #{extra.sort.join(', ')} — " \
|
|
108
|
+
"Hecks::Fuzzing::QaSettings::EXPECTED_TYPES doesn't recognise them"
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
EXPECTED_TYPES.each do |key, expected|
|
|
112
|
+
value = raw.fetch(key)
|
|
113
|
+
expected_classes = Array(expected)
|
|
114
|
+
unless expected_classes.any? { |klass| value.is_a?(klass) }
|
|
115
|
+
raise ArgumentError,
|
|
116
|
+
"#{path}: #{key} must be a #{expected_classes.map(&:name).join(' or ')}, " \
|
|
117
|
+
"got #{value.class} (#{value.inspect})"
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
instance_variable_set(:"@#{key}", value)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
symbolize_adapter_parity_pairs!(path)
|
|
124
|
+
freeze_values!
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
private
|
|
128
|
+
|
|
129
|
+
# `left:`/`right:` name adapters `IsolatedBoot` case-matches by
|
|
130
|
+
# symbol (`case adapter when :memory ...`), and YAML has no way to
|
|
131
|
+
# spell a bare Ruby Symbol as a mapping value — only
|
|
132
|
+
# `symbolize_names:` turns a key into one. So `adapter_parity_
|
|
133
|
+
# pairs` is the one dial that needs a coercion step after the
|
|
134
|
+
# type check above, rather than every dial growing one.
|
|
135
|
+
def symbolize_adapter_parity_pairs!(path)
|
|
136
|
+
@adapter_parity_pairs = @adapter_parity_pairs.to_h do |mode, pair|
|
|
137
|
+
unless pair.is_a?(Hash) && pair.key?(:left) && pair.key?(:right)
|
|
138
|
+
raise ArgumentError,
|
|
139
|
+
"#{path}: adapter_parity_pairs.#{mode} must have both left and right, got #{pair.inspect}"
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
[mode, { left: pair[:left].to_sym, right: pair[:right].to_sym }]
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def freeze_values!
|
|
147
|
+
EXPECTED_TYPES.each_key { |key| instance_variable_get(:"@#{key}").freeze }
|
|
148
|
+
freeze
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|