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
|
@@ -7,7 +7,7 @@ require_relative "../../ports/query/in_memory"
|
|
|
7
7
|
module Hecks
|
|
8
8
|
module Runtime
|
|
9
9
|
class CommandRules
|
|
10
|
-
# A reference must point at something that
|
|
10
|
+
# A reference must point at something that exists.
|
|
11
11
|
#
|
|
12
12
|
# `reference_to Customer` is the one guarantee an aggregate reference is
|
|
13
13
|
# for, and it was declared 14 times across banking and enforced nowhere :
|
|
@@ -16,7 +16,7 @@ module Hecks
|
|
|
16
16
|
# no corpus step ever passed a dangling reference.
|
|
17
17
|
module References
|
|
18
18
|
# Resolved here rather than in coercion because coercion is pure — it
|
|
19
|
-
# holds no repository. A reference
|
|
19
|
+
# holds no repository. A reference into another domain is left alone : a
|
|
20
20
|
# cross-domain target may legitimately not be loaded, which is the same
|
|
21
21
|
# reading `across` policies already get.
|
|
22
22
|
#
|
|
@@ -83,7 +83,7 @@ module Hecks
|
|
|
83
83
|
"#{attribute.type.target_name} identity, got nil"
|
|
84
84
|
end
|
|
85
85
|
|
|
86
|
-
# The reference
|
|
86
|
+
# The reference resolves itself — through the chapter's own IR, so the
|
|
87
87
|
# bluebook's declared heads are the index. This used to regex the target's
|
|
88
88
|
# name out of "Reference<Customer>" and then search
|
|
89
89
|
# `registry.bluebook(domain).aggregates` for it — and later reached the
|
|
@@ -101,33 +101,33 @@ module Hecks
|
|
|
101
101
|
next if @registry.repository(domain, target).find(key)
|
|
102
102
|
|
|
103
103
|
raise NotFound,
|
|
104
|
-
RefusalWording.
|
|
105
|
-
|
|
106
|
-
|
|
104
|
+
RefusalWording.render_site("NotFound", "reference_target_missing",
|
|
105
|
+
target: target.name, heads: target.identity_heads.join(", "),
|
|
106
|
+
key: key)
|
|
107
107
|
end
|
|
108
108
|
end
|
|
109
109
|
|
|
110
|
-
#
|
|
111
|
-
# tenant_scope.rb) — the
|
|
110
|
+
# Angle-8's own write-side half of `TenantScope.apply` (runtime/
|
|
111
|
+
# tenant_scope.rb) — the query-side mechanism this mirrors. That
|
|
112
112
|
# module turns a declared `authorize policy, tenant: :field` into a
|
|
113
|
-
# synthetic where-clause checked against the
|
|
113
|
+
# synthetic where-clause checked against the caller's own supplied
|
|
114
114
|
# tenant argument; there is no caller-identity/session system this
|
|
115
|
-
# runtime has to check a
|
|
115
|
+
# runtime has to check a write's caller against (TenantScope's own
|
|
116
116
|
# header names that as a separate, still-open gap), so this checks
|
|
117
|
-
# the one thing that
|
|
117
|
+
# the one thing that is available without one: whether the record
|
|
118
118
|
# being written and the record it references agree about which
|
|
119
119
|
# tenant they belong to. `lib/hecks/fuzzing/properties/guards.rb`'s
|
|
120
120
|
# `commands_respect_tenant_scope` states the identical claim,
|
|
121
121
|
# read off `history[:instances]` after the fact — this is what
|
|
122
|
-
# makes that claim hold
|
|
122
|
+
# makes that claim hold by construction (a refused write is never
|
|
123
123
|
# stored) rather than merely checked for regression.
|
|
124
124
|
#
|
|
125
125
|
# Hooked into `resolve_state_references` rather than a new
|
|
126
126
|
# DISPATCH_ORDER step deliberately: that method already walks
|
|
127
|
-
# every `reference_to`-typed attribute against the
|
|
127
|
+
# every `reference_to`-typed attribute against the settled,
|
|
128
128
|
# post-mutation state (the same moment `commands_respect_tenant_
|
|
129
129
|
# scope` itself inspects), already resolves the referenced record
|
|
130
|
-
# through the repository right above, and already runs from
|
|
130
|
+
# through the repository right above, and already runs from both
|
|
131
131
|
# `CommandInterpreter#step_save` and `EntityInterpreter#step_save`
|
|
132
132
|
# — one change, both interpreters covered, no new vocabulary step
|
|
133
133
|
# to keep in sync with `Vocabulary::AggregateDispatchOrder`/
|
|
@@ -152,20 +152,20 @@ module Hecks
|
|
|
152
152
|
next if target_tenant == own_tenant
|
|
153
153
|
|
|
154
154
|
raise Unauthorized,
|
|
155
|
-
RefusalWording.
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
155
|
+
RefusalWording.render_site("Unauthorized", "cross_tenant_reference",
|
|
156
|
+
aggregate: construct.hecks_name, field: own_tenant_field,
|
|
157
|
+
tenant: Rendering.describe(state[own_tenant_field]),
|
|
158
|
+
attribute: attribute.name, target: target.name,
|
|
159
|
+
target_field: target_tenant_field,
|
|
160
|
+
other: Rendering.describe(record.state[target_tenant_field]))
|
|
161
161
|
end
|
|
162
162
|
end
|
|
163
163
|
|
|
164
|
-
#
|
|
164
|
+
# The field an aggregate's own query names as tenant-scoping — the
|
|
165
165
|
# exact same lookup `Fuzzing::Properties::Guards#tenant_field_for`
|
|
166
166
|
# already established for the property that found this gap, reused
|
|
167
167
|
# here rather than reinvented: an aggregate's own declared tenant
|
|
168
|
-
# field is whichever field
|
|
168
|
+
# field is whichever field one of its own queries names in
|
|
169
169
|
# `authorize policy, tenant: :field`. `nil` for a construct that
|
|
170
170
|
# declares no such query — not every aggregate is tenant-scoped,
|
|
171
171
|
# and an entity never declares a query of its own at all today
|
|
@@ -177,25 +177,25 @@ module Hecks
|
|
|
177
177
|
authorization&.tenant&.to_sym
|
|
178
178
|
end
|
|
179
179
|
|
|
180
|
-
# `value` is the referenced record's own id,
|
|
180
|
+
# `value` is the referenced record's own id, exactly as `Identity.of`
|
|
181
181
|
# would build it for that record — a bare scalar for a single-field
|
|
182
182
|
# identity (the overwhelming common case; Banking's own plain
|
|
183
183
|
# `reference_to Customer` holds one already, so `Value.
|
|
184
184
|
# materialize_unwrapped` is a no-op passthrough here), or a
|
|
185
185
|
# `Naming.identity`-joined string for a compound one
|
|
186
186
|
# (`belongs_to Translation, as: :translation_ref` — Translation's
|
|
187
|
-
# own `identified_by :domain, :from, :to`,
|
|
187
|
+
# own `identified_by :domain, :from, :to`, three fields). Before
|
|
188
188
|
# this, plain `value.to_s` on that compound case's own coerced
|
|
189
189
|
# Value hit Ruby's default `Object#to_s` (a raw, run-to-run-random
|
|
190
190
|
# memory address) instead of joining the record's real id — found
|
|
191
191
|
# live via bin/fuzz on the self-hosted "translation" domain
|
|
192
|
-
# (replay_is_deterministic), the
|
|
192
|
+
# (replay_is_deterministic), the same class of gap `Identity.from`
|
|
193
193
|
# already had for a compound `identified_by`'s own bare (undotted)
|
|
194
194
|
# attribute paths. `materialize_unwrapped` recurses a multi-
|
|
195
195
|
# attribute value object to a plain Hash keyed by attribute name,
|
|
196
196
|
# in declaration order — `Naming.identity` on `.values` reproduces
|
|
197
197
|
# the identical join `Identity.of` itself would produce for the
|
|
198
|
-
#
|
|
198
|
+
# same fields.
|
|
199
199
|
def reference_key(value)
|
|
200
200
|
unwrapped = Value.materialize_unwrapped(value)
|
|
201
201
|
return Naming.identity(unwrapped.values).to_s if unwrapped.is_a?(Hash)
|
|
@@ -203,35 +203,35 @@ module Hecks
|
|
|
203
203
|
unwrapped.to_s
|
|
204
204
|
end
|
|
205
205
|
|
|
206
|
-
# A
|
|
206
|
+
# A command argument's own related record, reachable by name from
|
|
207
207
|
# `given`/`ensures` — `disputed_by.status`, say, `CardPayment
|
|
208
208
|
# .Dispute`'s own fresh `Reference<Customer>` argument — without
|
|
209
209
|
# teaching the pure expression evaluator anything about
|
|
210
|
-
# repositories. The lookup happens
|
|
210
|
+
# repositories. The lookup happens here, once, before evaluation;
|
|
211
211
|
# `Resolver#lookup` just digs into a plain Hash exactly as it
|
|
212
212
|
# always has.
|
|
213
213
|
#
|
|
214
|
-
# `owner`
|
|
214
|
+
# `owner` narrowed to `command` only (S12, ADR 0025 — "rules
|
|
215
215
|
# confined to their own aggregate boundary"): dereferencing the
|
|
216
|
-
#
|
|
216
|
+
# declaring aggregate/entity's own stored `reference_to` used to
|
|
217
217
|
# be the other half of this method's job — a live query against
|
|
218
218
|
# another aggregate's own repository, every time a `given`/
|
|
219
219
|
# `ensures`/`invariant` ran. That half is gone; a cross-aggregate
|
|
220
|
-
# fact a rule needs now has to be a `projects`-maintained
|
|
220
|
+
# fact a rule needs now has to be a `projects`-maintained local
|
|
221
221
|
# field (`AggregateBuilder#projects_impl`'s own comment), already
|
|
222
222
|
# present in `subject`'s own state, no hydration needed. A
|
|
223
|
-
# reference-typed
|
|
223
|
+
# reference-typed command argument stays in bounds, though — the
|
|
224
224
|
# ADR's own boundary list names "its command arguments" as
|
|
225
225
|
# readable, and nothing is stored yet for a fresh argument to
|
|
226
|
-
# project from; resolving it once here, synchronous with
|
|
226
|
+
# project from; resolving it once here, synchronous with this
|
|
227
227
|
# command's own admission, is a different shape from a live query
|
|
228
|
-
# against an
|
|
228
|
+
# against an already-persisted reference. `enforce_givens`/
|
|
229
229
|
# `enforce_ensures` are this method's only two remaining callers,
|
|
230
230
|
# both passing `command`/`args`, never a `subject`'s own
|
|
231
231
|
# aggregate — verified before this comment was written, not
|
|
232
232
|
# assumed.
|
|
233
233
|
#
|
|
234
|
-
#
|
|
234
|
+
# Recurses into what it finds, so a chain deeper than one hop
|
|
235
235
|
# still resolves in one pass. Depth-bounded rather than cycle-
|
|
236
236
|
# detected — nothing in this corpus dots more than two hops on a
|
|
237
237
|
# fresh argument, and a bound is simpler than tracking visited
|
|
@@ -20,6 +20,9 @@ module Hecks
|
|
|
20
20
|
|
|
21
21
|
attr_reader :registry
|
|
22
22
|
|
|
23
|
+
# @param registry [Runtime::Registry, nil] the booted registry the rules read bluebooks,
|
|
24
|
+
# repositories and the event log from; nil serves only the rules that read no
|
|
25
|
+
# registry, such as `sign_of`
|
|
23
26
|
def initialize(registry)
|
|
24
27
|
@registry = registry
|
|
25
28
|
end
|
|
@@ -74,12 +74,12 @@ module Hecks
|
|
|
74
74
|
STATEFUL_MUTATIONS = %i[append increment decrement multiply clamp remove].freeze
|
|
75
75
|
|
|
76
76
|
# `root_aggregate:` — Wave 8's own audit surfaced a real bug here,
|
|
77
|
-
# not merely a missing feature: for an
|
|
77
|
+
# not merely a missing feature: for an entity-owned command,
|
|
78
78
|
# `EntityInterpreter` calls this with `aggregate:` set to the
|
|
79
|
-
#
|
|
79
|
+
# entity itself (`element_interpreter.rb`'s own `Analyzer.call
|
|
80
80
|
# (aggregate: entity, command:)`), so `owner_fields` was always
|
|
81
81
|
# the entity's own attribute set. A `given`/`ensures` reading
|
|
82
|
-
# `parent.X` legitimately means the
|
|
82
|
+
# `parent.X` legitimately means the root aggregate's own field —
|
|
83
83
|
# a genuinely different owner — but `classify_path`'s `:parent`
|
|
84
84
|
# branch checked that read against `owner_fields` (the entity's),
|
|
85
85
|
# which can never contain a root-level field, so every entity
|
|
@@ -96,10 +96,10 @@ module Hecks
|
|
|
96
96
|
@owner_fields << aggregate.lifecycle.field.to_sym if aggregate.lifecycle
|
|
97
97
|
@root_owner_fields = root_aggregate.attributes.to_set(&:name)
|
|
98
98
|
@root_owner_fields << root_aggregate.lifecycle.field.to_sym if root_aggregate.lifecycle
|
|
99
|
-
# `projects`
|
|
99
|
+
# `projects` fields (S12, ADR 0025) are owner state too — a
|
|
100
100
|
# `given`/`ensures` reading one (e.g. `customer_status ==
|
|
101
101
|
# "active"`) is reading this record's own stored field, same
|
|
102
|
-
# as any attribute, even though nothing here
|
|
102
|
+
# as any attribute, even though nothing here writes it via a
|
|
103
103
|
# declared mutation (`CommandInterpreter#seed_projected_fields`
|
|
104
104
|
# populates it outside this analysis entirely). Left out of
|
|
105
105
|
# `known_writes` deliberately: `add_preservation_reads` then
|
|
@@ -107,7 +107,7 @@ module Hecks
|
|
|
107
107
|
# a partial mutation, which is exactly right — a projected
|
|
108
108
|
# field's freshness comes from the interpreter reseeding it on
|
|
109
109
|
# save, not from anything a caller-supplied write set carries.
|
|
110
|
-
# Applies to
|
|
110
|
+
# Applies to both `owner_fields` and `root_owner_fields` — an
|
|
111
111
|
# entity's own `parent.*` read can name the root aggregate's
|
|
112
112
|
# projected field just as easily as one of its real attributes
|
|
113
113
|
# (`Banking::Withdrawal.Dispute`'s own `parent.account_customer_
|
|
@@ -237,7 +237,7 @@ module Hecks
|
|
|
237
237
|
end
|
|
238
238
|
end
|
|
239
239
|
|
|
240
|
-
#
|
|
240
|
+
# Known, harmless gap: `corrects ..., as: :name`'s bound name
|
|
241
241
|
# (admissibility.rb's `enforce_correction_target`/`enforce_givens`/
|
|
242
242
|
# `enforce_ensures`) isn't special-cased here the way `:old`/
|
|
243
243
|
# `:parent` are — a given/ensures referencing it falls through to
|
|
@@ -247,7 +247,7 @@ module Hecks
|
|
|
247
247
|
# `hydrate_existing` path instead of the `ATOMIC_PUT` fast path.
|
|
248
248
|
# Not a correctness bug — `as:`'s runtime binding (a plain `attrs`
|
|
249
249
|
# merge, exactly like `old:`'s) resolves and evaluates correctly
|
|
250
|
-
# regardless of what this
|
|
250
|
+
# regardless of what this static analysis concludes — just a real,
|
|
251
251
|
# deliberately-left optimization gap: closing it would mean
|
|
252
252
|
# threading "which names this command declares as correction
|
|
253
253
|
# bindings" into the Analyzer, which doesn't have that per-command
|
|
@@ -258,9 +258,9 @@ module Hecks
|
|
|
258
258
|
name = head.to_sym
|
|
259
259
|
|
|
260
260
|
if name == :parent
|
|
261
|
-
# `root_owner_fields` —
|
|
262
|
-
# command `owner_fields` is the
|
|
263
|
-
# `parent.X` always means the
|
|
261
|
+
# `root_owner_fields` — not `owner_fields`. For an entity-owned
|
|
262
|
+
# command `owner_fields` is the entity's own attribute set;
|
|
263
|
+
# `parent.X` always means the root aggregate's own field, a
|
|
264
264
|
# genuinely different owner (`root_aggregate:`'s own header,
|
|
265
265
|
# above, has the full bug this fixes). Identical for a plain
|
|
266
266
|
# aggregate command, where root_aggregate defaults to aggregate
|