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
|
@@ -16,9 +16,9 @@ module Hecks
|
|
|
16
16
|
|
|
17
17
|
# Vendored addition, not (yet) upstream hecks (migration plan
|
|
18
18
|
# task 4): a sentinel for "this keyword was never passed", distinct
|
|
19
|
-
# from Ruby's own nil/false. `then_set`'s
|
|
19
|
+
# from Ruby's own nil/false. `then_set`'s original default (`to:
|
|
20
20
|
# nil`) could not tell "not given" apart from "given, and the
|
|
21
|
-
# value
|
|
21
|
+
# value is false" — `to || from` silently treats `to: false` the
|
|
22
22
|
# same as an absent `to:` and falls through to `from` (also
|
|
23
23
|
# absent), so `then_set :accepted, to: false` raised "names no
|
|
24
24
|
# operation" for the one value most likely to be written that way
|
|
@@ -40,14 +40,14 @@ module Hecks
|
|
|
40
40
|
@named_givens = named_givens
|
|
41
41
|
@owner_attributes = owner_attributes
|
|
42
42
|
@owner_constructs = owner_constructs
|
|
43
|
-
#
|
|
43
|
+
# The aggregate-wide cross-entity pool — see
|
|
44
44
|
# `AggregateBuilder#entity`'s own comment and `EntityBuilder#
|
|
45
|
-
# given`'s. Empty (never populated) for an
|
|
45
|
+
# given`'s. Empty (never populated) for an aggregate-owned
|
|
46
46
|
# command, which already checks its own owner's `named_givens`
|
|
47
47
|
# directly and has no siblings to reach across; real only for
|
|
48
|
-
# an
|
|
48
|
+
# an entity-owned command's own bare reference.
|
|
49
49
|
@entity_shared_givens = entity_shared_givens
|
|
50
|
-
#
|
|
50
|
+
# Normalized the exact same way `StateTransition#from` already
|
|
51
51
|
# is — one state or several, a single spelling either way,
|
|
52
52
|
# both read back through `Array(...)` at check time.
|
|
53
53
|
@from = case from
|
|
@@ -57,14 +57,14 @@ module Hecks
|
|
|
57
57
|
end
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
-
# A command carries
|
|
61
|
-
# declared an
|
|
60
|
+
# A command carries one responsibility role — the language never
|
|
61
|
+
# declared an or between two roles, so a second `role` call would
|
|
62
62
|
# otherwise silently win while the first still looked declared,
|
|
63
63
|
# exactly the failure mode `reference_to`'s own duplicate guard
|
|
64
64
|
# (below) already exists to prevent for a command's root.
|
|
65
65
|
#
|
|
66
|
-
#
|
|
67
|
-
# (slice 4). This is a uniqueness gate on
|
|
66
|
+
# Renamed from `role` — item #13's full metaprogrammed dispatch
|
|
67
|
+
# (slice 4). This is a uniqueness gate on prior state (`@role`
|
|
68
68
|
# already set), not a pure function of the argument's own value —
|
|
69
69
|
# a genuinely different shape than a plain fill, so it stays
|
|
70
70
|
# hand-written and is reached through `calls:` like `attribute`
|
|
@@ -86,25 +86,25 @@ module Hecks
|
|
|
86
86
|
|
|
87
87
|
# See AggregateBuilder#provenance's own comment — identical shape,
|
|
88
88
|
# one level down.
|
|
89
|
-
#
|
|
89
|
+
# Renamed from `provenance` — item #13's full metaprogrammed
|
|
90
90
|
# dispatch (slice 4c). Bootstrap-reachable, in
|
|
91
91
|
# GenericDispatch::BOOTSTRAP_CALLS_FALLBACK.
|
|
92
92
|
def provenance_impl(from:) = @provenance = from
|
|
93
93
|
|
|
94
94
|
# `optional:` rides here as well as on a plain attribute : `as:` makes a
|
|
95
|
-
# reference into a
|
|
95
|
+
# reference into a named argument, and a named argument is exactly the kind
|
|
96
96
|
# of fact that may or may not be given. The meta-domain's Verb.Declare
|
|
97
97
|
# points at the Entity a command belongs to — and most commands belong to no
|
|
98
98
|
# entity at all.
|
|
99
|
-
#
|
|
99
|
+
# Renamed from `reference_to` — item #13's full metaprogrammed
|
|
100
100
|
# dispatch (slice 4b). Bootstrap-reachable, in
|
|
101
101
|
# GenericDispatch::BOOTSTRAP_CALLS_FALLBACK.
|
|
102
102
|
def reference_to_impl(type, as: nil, optional: false)
|
|
103
103
|
demodulised = Naming.demodulise(type)
|
|
104
104
|
# moved to the language: given "a command names what it acts on", on Verb.ActsOn
|
|
105
105
|
|
|
106
|
-
# `as:`
|
|
107
|
-
# can point at another instance of its
|
|
106
|
+
# `as:` means "a named attribute", not "the root I act on" — so a command
|
|
107
|
+
# can point at another instance of its own kind. Without this,
|
|
108
108
|
# `reference_to Aggregate, as: :points_at` on a command owned by Aggregate
|
|
109
109
|
# read as a second self-reference and was refused as naming two roots,
|
|
110
110
|
# which is how the meta-domain's own Aggregate.Reference could not say the
|
|
@@ -131,18 +131,18 @@ module Hecks
|
|
|
131
131
|
|
|
132
132
|
public
|
|
133
133
|
|
|
134
|
-
#
|
|
134
|
+
# No block is a reference, not a fresh declaration (S10, ADR
|
|
135
135
|
# 0025 — "a precondition shared across commands is declared
|
|
136
136
|
# once. An aggregate declares it by name and commands
|
|
137
|
-
# reference it"): the
|
|
137
|
+
# reference it"): the same word, the same shape
|
|
138
138
|
# (`AggregateBuilder#given`, block required there), so naming a
|
|
139
139
|
# precondition back is spelled exactly like declaring one would
|
|
140
140
|
# be, minus the block — one idea, one word, never a second
|
|
141
141
|
# spelling ("requires"/"precondition") for "use the one already
|
|
142
|
-
# named". Resolved against whatever the
|
|
142
|
+
# named". Resolved against whatever the owning aggregate has
|
|
143
143
|
# declared so far — see `AggregateBuilder#command`'s own
|
|
144
144
|
# comment on why that means declaration order matters here.
|
|
145
|
-
#
|
|
145
|
+
# Renamed from `given` — item #13's full metaprogrammed dispatch
|
|
146
146
|
# (slice 4b), same reasoning as reference_to_impl above.
|
|
147
147
|
def given_impl(description, &predicate)
|
|
148
148
|
return reference_named_given(description) unless predicate
|
|
@@ -155,10 +155,10 @@ module Hecks
|
|
|
155
155
|
|
|
156
156
|
private
|
|
157
157
|
|
|
158
|
-
#
|
|
159
|
-
# command's own owner (as always),
|
|
160
|
-
# command, where it is real — a
|
|
161
|
-
# declaration under the
|
|
158
|
+
# Primitive 1 (RuleReference#resolve_hash_chain) — first this
|
|
159
|
+
# command's own owner (as always), then — only for a piece-owned
|
|
160
|
+
# command, where it is real — a sibling piece's own entity-level
|
|
161
|
+
# declaration under the same aggregate (`@entity_shared_givens`,
|
|
162
162
|
# threaded from `EntityBuilder#given`'s own write-through).
|
|
163
163
|
# "customer is active" declared once on `Visit`, referenced bare
|
|
164
164
|
# by `KeyIssuance.Return` — two different pieces, same aggregate,
|
|
@@ -179,7 +179,7 @@ module Hecks
|
|
|
179
179
|
|
|
180
180
|
public
|
|
181
181
|
|
|
182
|
-
# The
|
|
182
|
+
# The postcondition — a given for the far side of the mutations,
|
|
183
183
|
# evaluated against the settled record with `old` naming the state
|
|
184
184
|
# as it stood before them: `ensures("...") { old.balance.cents ==
|
|
185
185
|
# balance.cents + amount.cents }`. Same extraction, same Rule
|
|
@@ -212,7 +212,7 @@ module Hecks
|
|
|
212
212
|
# the matching Float-support widening this required). `clamp:`
|
|
213
213
|
# is a genuinely different shape -- its source is always a literal
|
|
214
214
|
# `[min, max]` pair, never an argument reference, and it bounds
|
|
215
|
-
# the
|
|
215
|
+
# the current value rather than combining it with an amount -- so
|
|
216
216
|
# it does not reuse `arithmetic`/`arithmetic_value_object` at all;
|
|
217
217
|
# see MutationApplier#apply's own `:clamp` branch.
|
|
218
218
|
#
|
|
@@ -222,7 +222,7 @@ module Hecks
|
|
|
222
222
|
# commands: "the runtime list-remove primitive (then_set remove:)
|
|
223
223
|
# drops it from the list element-wise, with no read-modify-write
|
|
224
224
|
# -- so a concurrent Add can never be lost"). Matches an element
|
|
225
|
-
# by
|
|
225
|
+
# by value equality against `mutation.source` (resolved and
|
|
226
226
|
# Value-coerced the same way increment/decrement/multiply already
|
|
227
227
|
# coerce their own amount -- see MutationApplier#removed).
|
|
228
228
|
#
|
|
@@ -238,20 +238,20 @@ module Hecks
|
|
|
238
238
|
# UNSET-sentinel discipline the `to: false` fix already
|
|
239
239
|
# established (a positional `false` must read as "set to
|
|
240
240
|
# false," not "absent," same as the keyword form). Only applied
|
|
241
|
-
# when `to:` itself was
|
|
241
|
+
# when `to:` itself was not also given, so an explicit `to:`
|
|
242
242
|
# keyword always wins over a stray positional.
|
|
243
243
|
#
|
|
244
244
|
# `sets` is the word (ADR 0025 reverts `then_set` — the grammar
|
|
245
245
|
# already declared `sets`, `was: "then_set"`, and 143 of 143 live
|
|
246
246
|
# call sites are `then_set`, so this method was the one thing
|
|
247
|
-
# still backwards). `to:` is
|
|
247
|
+
# still backwards). `to:` is omittable when it would only repeat
|
|
248
248
|
# the target — `sets :number` alone already means `to: :number`
|
|
249
|
-
# — and the
|
|
249
|
+
# — and the redundant explicit spelling is refused outright
|
|
250
250
|
# (principle 1, "one idea, one spelling": `sets :number, to:
|
|
251
251
|
# :number` says nothing `sets :number` doesn't). `from:` — a
|
|
252
252
|
# pure synonym for `to:` the language's own refusal message had
|
|
253
253
|
# already forgotten about — is gone; write `to:`.
|
|
254
|
-
#
|
|
254
|
+
# The op each kwarg selects — `spec/syntax_conformance_spec.rb`'s own
|
|
255
255
|
# "selects the same op..." check holds this constant to the self-
|
|
256
256
|
# hosted table's own `Argument#selects` column (`"op=set"`,
|
|
257
257
|
# `"op=append"`, ...; whole-project table-unification survey, item
|
|
@@ -262,13 +262,13 @@ module Hecks
|
|
|
262
262
|
KWARG_TO_OP = { to: :set, append: :append, increment: :increment, decrement: :decrement,
|
|
263
263
|
multiply: :multiply, clamp: :clamp, remove: :remove }.freeze
|
|
264
264
|
|
|
265
|
-
#
|
|
265
|
+
# Renamed from `sets` — item #13's full metaprogrammed dispatch
|
|
266
266
|
# (slice 4c). The `KWARG_TO_OP` op-selection mapping is already
|
|
267
267
|
# table-verified (`Argument#selects`), but the REST (UNSET-
|
|
268
268
|
# sentinel discipline, redundant-spelling refusal, omittable-
|
|
269
269
|
# `to:` fallback, one-mutation-only refusal, the position-
|
|
270
|
-
# preserving `resolve_*!` reinsertion) is keyed off
|
|
271
|
-
#
|
|
270
|
+
# preserving `resolve_*!` reinsertion) is keyed off runtime
|
|
271
|
+
# state, not a pure function of a static row — stays hand-
|
|
272
272
|
# written, reached through `calls:` like everything else here.
|
|
273
273
|
# Bootstrap-reachable, in BOOTSTRAP_CALLS_FALLBACK.
|
|
274
274
|
def sets_impl(target, positional_to = UNSET, to: UNSET, append: UNSET,
|
|
@@ -277,9 +277,9 @@ module Hecks
|
|
|
277
277
|
|
|
278
278
|
to = positional_to if to.equal?(UNSET) && !positional_to.equal?(UNSET)
|
|
279
279
|
|
|
280
|
-
# `to:` only ever
|
|
280
|
+
# `to:` only ever repeats the target when it's a Symbol naming a
|
|
281
281
|
# field — a literal (`to: false`, the bare positional-boolean
|
|
282
|
-
# shorthand, a String, ...) is a
|
|
282
|
+
# shorthand, a String, ...) is a value, never a redundant name,
|
|
283
283
|
# so it never has `.to_sym` to compare in the first place.
|
|
284
284
|
if to.is_a?(Symbol) && to == target.to_sym
|
|
285
285
|
raise Malformed,
|
|
@@ -292,7 +292,7 @@ module Hecks
|
|
|
292
292
|
.reject { |_, source| source.equal?(UNSET) }
|
|
293
293
|
named = given.to_h { |kwarg, source| [KWARG_TO_OP.fetch(kwarg), source] }
|
|
294
294
|
|
|
295
|
-
#
|
|
295
|
+
# **The omittable case**. No operation was named at all — not even a
|
|
296
296
|
# bare `to:` — so this is `sets :field` alone, which means
|
|
297
297
|
# exactly what the redundant, refused spelling above would have.
|
|
298
298
|
named = { set: target } if named.empty?
|
|
@@ -307,10 +307,10 @@ module Hecks
|
|
|
307
307
|
@mutations << Mutation.new(target: target.to_sym, op: op, source: normalize_append_source(op, source))
|
|
308
308
|
end
|
|
309
309
|
|
|
310
|
-
#
|
|
310
|
+
# Legacy under shadow-parsing (S0a's own bridge) — frozen era text
|
|
311
311
|
# minted before this rename still parses; live source refuses it,
|
|
312
312
|
# naming the replacement.
|
|
313
|
-
#
|
|
313
|
+
# Renamed from `then_set` — item #13's full metaprogrammed
|
|
314
314
|
# dispatch (slice 5). Not bootstrap-reachable. Now has its own
|
|
315
315
|
# dedicated, `status: "deprecated"` Keyword row (syntax.bluebook)
|
|
316
316
|
# rather than living only as `sets`'s own `was:` — see that
|
|
@@ -323,15 +323,15 @@ module Hecks
|
|
|
323
323
|
|
|
324
324
|
# No raise here. "an event is named" is declared in the language itself —
|
|
325
325
|
# language/bluebook/behavior.bluebook, on Command.Announce — and MetaValidator is what
|
|
326
|
-
# enforces it. This is the first rule to move
|
|
326
|
+
# enforces it. This is the first rule to move across rather than be
|
|
327
327
|
# duplicated : delete the declaration and an unnamed event is accepted,
|
|
328
328
|
# which is what makes the meta-domain load-bearing rather than decorative.
|
|
329
329
|
#
|
|
330
|
-
#
|
|
330
|
+
# Bare constant accepted (ADR 0025, S6 — "events first-class"),
|
|
331
331
|
# `emits Account::AccountFrozen`, resolved through `ConstShim` the
|
|
332
332
|
# same way `trigger`/`dispatch` already resolve a command
|
|
333
|
-
# reference (`Naming.event_ref`, that method's own header).
|
|
334
|
-
# yet a
|
|
333
|
+
# reference (`Naming.event_ref`, that method's own header). Not
|
|
334
|
+
# yet a required spelling, deliberately, unlike `trigger`/
|
|
335
335
|
# `dispatch`'s own quoted-text refusal: those were safe to refuse
|
|
336
336
|
# only because command references are already 100% migrated
|
|
337
337
|
# across the live corpus (verified 2026-08-27) — `emits`/`on`
|
|
@@ -345,23 +345,23 @@ module Hecks
|
|
|
345
345
|
@emits << Naming.event_ref(event_name)
|
|
346
346
|
end
|
|
347
347
|
|
|
348
|
-
#
|
|
348
|
+
# The record's own value as a mutation source — `sets :positions,
|
|
349
349
|
# append: { ply: state(:ply), knights: state(:knights) }` copies
|
|
350
|
-
# what the record holds
|
|
350
|
+
# what the record holds now into the new element; `sets :last,
|
|
351
351
|
# to: state(:current)` copies one field onto another. A bare
|
|
352
352
|
# Symbol always names an argument (see `resolve_append_fields!`),
|
|
353
353
|
# so without this a command could not snapshot its own state at
|
|
354
354
|
# all. `Literal::StateRef`'s own comment has the wire spelling.
|
|
355
355
|
def state(name) = StateRef.new(name.to_sym)
|
|
356
356
|
|
|
357
|
-
#
|
|
358
|
-
# that hands its own dispatch to
|
|
359
|
-
# and applied within the
|
|
357
|
+
# The synchronous cousin of `trigger` — an aggregate-level command
|
|
358
|
+
# that hands its own dispatch to one nested entity command, checked
|
|
359
|
+
# and applied within the same atomic dispatch rather than a second
|
|
360
360
|
# one. Built because `trigger`/`saga`'s own dispatch (`Dispatcher
|
|
361
|
-
# #reenter`) is a
|
|
361
|
+
# #reenter`) is a reaction — the triggering command has already
|
|
362
362
|
# committed by the time it runs, and both `PolicyInterpreter#deliver`
|
|
363
363
|
# and `SagaInterpreter#deliver_saga_dispatch` rescue a target's own
|
|
364
|
-
# refusal and
|
|
364
|
+
# refusal and record it rather than raising it back to the original
|
|
365
365
|
# caller. That is correct for what those two exist for (an
|
|
366
366
|
# eventually-consistent process that can compensate), and wrong for
|
|
367
367
|
# a caller who needs a synchronous yes/no on whether the thing they
|
|
@@ -370,54 +370,54 @@ module Hecks
|
|
|
370
370
|
# project. `delegates_to` fills exactly that gap: the target
|
|
371
371
|
# entity command's own `given`/`ensures` are enforced as real,
|
|
372
372
|
# unrescued Ruby exceptions, so a refusal deep in the entity's own
|
|
373
|
-
# rules is the
|
|
373
|
+
# rules is the delegating command's own refusal too, and nothing
|
|
374
374
|
# from either side is saved unless both sides pass.
|
|
375
375
|
#
|
|
376
|
-
# `target` is always
|
|
376
|
+
# `target` is always one hop, `"Entity.Command"` — an aggregate
|
|
377
377
|
# names the entity it owns directly, same reach a bare `given`
|
|
378
378
|
# reference already has (see `Knight`'s own comment on this
|
|
379
379
|
# domain's shared givens), not a multi-segment dispatch chain.
|
|
380
|
-
# `with:` resolves the
|
|
380
|
+
# `with:` resolves the same way `sets ..., append: {...}`'s own
|
|
381
381
|
# field map and a policy's own `trigger ..., with: {...}` already
|
|
382
|
-
# do: each value names one of
|
|
382
|
+
# do: each value names one of this command's own declared/implicit
|
|
383
383
|
# arguments, read at dispatch time and handed to the target under
|
|
384
384
|
# its own key.
|
|
385
385
|
#
|
|
386
|
-
#
|
|
386
|
+
# Mutually exclusive with `sets`/`emits` on the same command — a
|
|
387
387
|
# delegating command is a pure passthrough by design (see this
|
|
388
|
-
# method's own header), so it declares no
|
|
389
|
-
# its own; its result
|
|
388
|
+
# method's own header), so it declares no other mutation or event of
|
|
389
|
+
# its own; its result is whatever the delegated entity command's own
|
|
390
390
|
# `sets`/`emits` produced. Enforced in `build`, once every builder
|
|
391
391
|
# call has already run, so declaration order does not matter.
|
|
392
392
|
#
|
|
393
|
-
#
|
|
393
|
+
# Stored as a mutation, not a new Command field — a real, deliberate
|
|
394
394
|
# choice, not a shortcut. `Command`'s own shape (givens/ensures/
|
|
395
395
|
# mutations/emits/...) is not just Ruby: it round-trips through this
|
|
396
|
-
# language's
|
|
396
|
+
# language's own self-hosted meta-domain (`Bluebook::MetaValidator`
|
|
397
397
|
# dispatches every declaration into a "Bluebook" domain describing
|
|
398
|
-
# itself, then
|
|
398
|
+
# itself, then rebuilds the real runtime graph from what that domain
|
|
399
399
|
# holds — `Hecks.bluebook` registers what `MetaValidator.call`
|
|
400
400
|
# returns, never the builder's own object graph directly, confirmed
|
|
401
401
|
# by reading `meta_validator.rb`'s own `self.call`/`self.hold`).
|
|
402
|
-
# A genuinely
|
|
402
|
+
# A genuinely new top-level Command field needs the meta-domain's
|
|
403
403
|
# own grammar (`language/bluebook/behavior.bluebook` or wherever
|
|
404
404
|
# Verb.Rule/Ensure/Change live) taught to carry it too — the same
|
|
405
405
|
# scale of change as the real "item #13" migration this file's own
|
|
406
|
-
# comments document throughout. A
|
|
407
|
-
# own `mutations:` field is
|
|
406
|
+
# comments document throughout. A new mutation op does not: `sets`'s
|
|
407
|
+
# own `mutations:` field is already a fully round-tripped part of
|
|
408
408
|
# that contract (`Assembly::CONTRACTS["Command"].fields[:mutations]`),
|
|
409
|
-
# and an append-shaped mutation
|
|
409
|
+
# and an append-shaped mutation already carries a multi-key `fields:`
|
|
410
410
|
# hash the exact shape `with:` needs — so `delegates_to` rides that
|
|
411
411
|
# existing, already-correct wire format under a new `op: :delegate`
|
|
412
412
|
# instead of inventing a parallel one. `MutationOp`'s own closed set
|
|
413
413
|
# (vocabulary.bluebook) gained `"delegate"` alongside `"append"`
|
|
414
|
-
# for exactly this reason, and the
|
|
414
|
+
# for exactly this reason, and the three meta-domain touch points
|
|
415
415
|
# that hard-coded `op == "append"` for the multi-binding shape
|
|
416
416
|
# (`meta_validator/readings.rb#mutation_rows`,
|
|
417
417
|
# `meta_validator/shapes.rb#mutation`, `assembly/marks.rb#mutation`)
|
|
418
418
|
# now check for `:delegate` alongside it, each with a comment
|
|
419
419
|
# pointing back here.
|
|
420
|
-
#
|
|
420
|
+
# Renamed from `delegates_to` to `delegates_to_impl` on declaration
|
|
421
421
|
# — matches `sets_impl`/`given_impl`/`reference_to_impl`'s own
|
|
422
422
|
# convention (language/bluebook/syntax.bluebook's own Keyword row
|
|
423
423
|
# for this word names `calls: "delegates_to_impl"`), the same
|
|
@@ -434,10 +434,10 @@ module Hecks
|
|
|
434
434
|
@mutations << Mutation.new(target: target.to_s, op: :delegate, source: with)
|
|
435
435
|
end
|
|
436
436
|
|
|
437
|
-
# A
|
|
437
|
+
# A command declaring what past fact it amends — the append-only
|
|
438
438
|
# answer to "what if this record's history turns out to have been
|
|
439
439
|
# wrong": never rewrite the original event (the log stays exactly
|
|
440
|
-
# what it was), always append a
|
|
440
|
+
# what it was), always append a new fact on top. `event` names the
|
|
441
441
|
# event this command corrects; `as:` optionally binds the located
|
|
442
442
|
# instance for a `given`/`ensures` to reference, the same shape
|
|
443
443
|
# `ensures`'s own `old` binding already has; `reason:` is not
|
|
@@ -446,27 +446,27 @@ module Hecks
|
|
|
446
446
|
# here is why"), refused when blank the same way a `given`'s own
|
|
447
447
|
# description is required to say something.
|
|
448
448
|
#
|
|
449
|
-
#
|
|
449
|
+
# Stored as a mutation, not a new Command field — see the
|
|
450
450
|
# KeywordSeed row's own comment (command.bluebook) for why: this
|
|
451
451
|
# is the exact same choice `delegates_to` already made, for the
|
|
452
|
-
# exact same reason. Rides the
|
|
452
|
+
# exact same reason. Rides the same multi-binding wire shape
|
|
453
453
|
# `append`/`delegate` use — `as:`/`reason:`/`reverses:` assembled
|
|
454
454
|
# by hand into one `source` hash, the way `sets_impl` assembles up
|
|
455
455
|
# to seven kwargs into one `named` hash above.
|
|
456
456
|
#
|
|
457
|
-
# `reverses: true`
|
|
457
|
+
# `reverses: true` names an intent to auto-derive the corrective
|
|
458
458
|
# `sets` from the original event's own mutations, rather than the
|
|
459
459
|
# author writing it — see `AggregateBuilder#seal_correction_targets`,
|
|
460
460
|
# where that derivation actually happens (it needs every sibling
|
|
461
461
|
# command in the aggregate already known, which this builder alone
|
|
462
|
-
# cannot see).
|
|
462
|
+
# cannot see). Mutually exclusive with an explicit `sets` on the
|
|
463
463
|
# same command — two ways of saying the same thing is exactly the
|
|
464
464
|
# redundancy `sets`'s own omittable-`to:` rule refuses elsewhere.
|
|
465
465
|
#
|
|
466
|
-
# `as:`
|
|
466
|
+
# `as:` is always stored as text, never left a bare Symbol —
|
|
467
467
|
# `Mutation#classified_source`/`#appended_fields` (Behaviour::
|
|
468
468
|
# Mutation) classify any bare Symbol field as `kind: "argument"`,
|
|
469
|
-
# meaning "resolve this against one of
|
|
469
|
+
# meaning "resolve this against one of this command's own declared
|
|
470
470
|
# attributes at dispatch time" (append/delegate's own meaning for a
|
|
471
471
|
# Symbol). `as:` names no such thing — it is a plain label, not yet
|
|
472
472
|
# wired into the expression evaluator (a future round's work, once
|
|
@@ -485,7 +485,7 @@ module Hecks
|
|
|
485
485
|
source: { as: as&.to_s, reason: reason.to_s, reverses: reverses })
|
|
486
486
|
end
|
|
487
487
|
|
|
488
|
-
#
|
|
488
|
+
# The effects that write a field of the record — `delegate` and
|
|
489
489
|
# `corrects` name a command and an event, never a field.
|
|
490
490
|
FIELD_EFFECTS = %i[set append remove increment decrement multiply clamp].freeze
|
|
491
491
|
|
|
@@ -528,7 +528,7 @@ module Hecks
|
|
|
528
528
|
private
|
|
529
529
|
|
|
530
530
|
# C4.2 (docs/semantics/bluebook-semantics.md) — a command's effects
|
|
531
|
-
# are
|
|
531
|
+
# are one update set over the pre-dispatch state, so a field
|
|
532
532
|
# written twice has no meaning to give: last-wins would make
|
|
533
533
|
# declaration order significant, which the update set says it is
|
|
534
534
|
# not. Refused here, where the declaration can still be read whole.
|
|
@@ -548,21 +548,21 @@ module Hecks
|
|
|
548
548
|
end
|
|
549
549
|
end
|
|
550
550
|
|
|
551
|
-
#
|
|
551
|
+
# **Resolution rules** — see `docs/resolution-rules/README.md` for the
|
|
552
552
|
# precise, language-agnostic algorithm each of `resolve_bare_set!`/
|
|
553
553
|
# `resolve_append_fields!` implements (`implicit-command-attributes.md`
|
|
554
554
|
# / `implicit-append-fields.md`) — the contract a Rust mirror is
|
|
555
555
|
# written from, not inferred from this comment.
|
|
556
556
|
#
|
|
557
|
-
# `sets :field`
|
|
557
|
+
# `sets :field` alone (S5's own bare form — no `to:`, meaning
|
|
558
558
|
# `to: :field`) already says the command accepts an argument
|
|
559
|
-
# named `:field`; requiring a
|
|
559
|
+
# named `:field`; requiring a separate `attribute :field, Type`
|
|
560
560
|
# line that retypes what the owning aggregate/entity already
|
|
561
561
|
# declared is the same redundancy S10's `given` reference already
|
|
562
562
|
# killed for preconditions ("a precondition shared across
|
|
563
563
|
# commands is declared once... a command references it by
|
|
564
564
|
# name"). Same move here, one level down: when the command
|
|
565
|
-
# hasn't declared its own `:field`, import the
|
|
565
|
+
# hasn't declared its own `:field`, import the owner's
|
|
566
566
|
# already-built `Attribute` verbatim (same type, pattern,
|
|
567
567
|
# optional, admits) instead of retyping it.
|
|
568
568
|
#
|
|
@@ -576,7 +576,7 @@ module Hecks
|
|
|
576
576
|
#
|
|
577
577
|
# Declaration order matters here the same way it already does
|
|
578
578
|
# for `identified_by`/`given` — the owner's own attribute must
|
|
579
|
-
# exist by the time
|
|
579
|
+
# exist by the time this builder's `build` runs, which every
|
|
580
580
|
# real bluebook already satisfies (the aggregate/entity always
|
|
581
581
|
# declares its attributes before the commands that act on them).
|
|
582
582
|
def resolve_implicit_attributes!
|
|
@@ -587,9 +587,9 @@ module Hecks
|
|
|
587
587
|
end
|
|
588
588
|
refuse_unknown_state_sources!(mutation)
|
|
589
589
|
end
|
|
590
|
-
# A
|
|
590
|
+
# A second, separate pass — not folded into the loop above — so
|
|
591
591
|
# every mutation's own self-referential import (resolve_bare_set!)
|
|
592
|
-
# has already landed before any mutation's
|
|
592
|
+
# has already landed before any mutation's source is checked
|
|
593
593
|
# against the final `attributes` list. `sets :a, to: :b` declared
|
|
594
594
|
# before `sets :b` (bare, importing :b from the owner) is real
|
|
595
595
|
# and legal; checking inline, mutation by mutation, would refuse
|
|
@@ -601,8 +601,8 @@ module Hecks
|
|
|
601
601
|
@mutations.each { |mutation| refuse_unknown_argument_sources!(mutation) }
|
|
602
602
|
end
|
|
603
603
|
|
|
604
|
-
#
|
|
605
|
-
#
|
|
604
|
+
# The ones `resolve_source` (CommandRules::Arithmetic) only ever
|
|
605
|
+
# reads from `args` — never a fallback to the record's own current
|
|
606
606
|
# state the way `append`'s own per-field resolution legitimately
|
|
607
607
|
# can (`MutationApplier#resolve_append_source`'s own `instance
|
|
608
608
|
# [source]` fallback, a real, intentional second meaning this
|
|
@@ -612,8 +612,8 @@ module Hecks
|
|
|
612
612
|
# runtime, not merely optional: no caller can ever supply a value
|
|
613
613
|
# under a name the command never declared (ArgumentGate's own
|
|
614
614
|
# `refuse_unknown_arguments` already refuses that), so the source
|
|
615
|
-
# resolves to nil
|
|
616
|
-
# absent
|
|
615
|
+
# resolves to nil forever, indistinguishable from a legitimately
|
|
616
|
+
# absent optional argument until this check existed to tell them
|
|
617
617
|
# apart. Mirrors `AggregateBuilder#seal_query_argument`'s
|
|
618
618
|
# identical shape for a query's own where-clause argument —
|
|
619
619
|
# same mistake, one construct over.
|
|
@@ -626,9 +626,9 @@ module Hecks
|
|
|
626
626
|
# The bare self-referential shape (`sets :field` alone, `source
|
|
627
627
|
# == target`) is `resolve_bare_set!`'s own territory, not this
|
|
628
628
|
# check's — when neither the command nor the owner declares
|
|
629
|
-
# that name, the
|
|
629
|
+
# that name, the more specific, pre-existing refusal one level
|
|
630
630
|
# up (`AggregateBuilder#seal_mutation_targets`, checking the
|
|
631
|
-
# mutation's
|
|
631
|
+
# mutation's target against the aggregate's own fields) is the
|
|
632
632
|
# one that should fire, naming the field as a target problem,
|
|
633
633
|
# not — confusingly — as a source problem this check would
|
|
634
634
|
# otherwise misreport it as.
|
|
@@ -642,7 +642,7 @@ module Hecks
|
|
|
642
642
|
"caller actually sent"
|
|
643
643
|
end
|
|
644
644
|
|
|
645
|
-
# `state(:name)` names one of the
|
|
645
|
+
# `state(:name)` names one of the owner's own fields — a snapshot
|
|
646
646
|
# of something the record actually holds. Refused at build, by
|
|
647
647
|
# name, the way an unknown `given` reference is; nothing here can
|
|
648
648
|
# read a field the aggregate never declared.
|
|
@@ -657,7 +657,7 @@ module Hecks
|
|
|
657
657
|
end
|
|
658
658
|
|
|
659
659
|
def resolve_bare_set!(mutation)
|
|
660
|
-
# A
|
|
660
|
+
# A symbol naming its own target — never a literal that merely
|
|
661
661
|
# spells the same word. `sets :moved, to: "moved"` (a chess rook
|
|
662
662
|
# recording that it has moved, into a closed set whose member is
|
|
663
663
|
# literally "moved") used to read as the shorthand and import
|
|
@@ -673,9 +673,9 @@ module Hecks
|
|
|
673
673
|
attributes << owner_attr if owner_attr
|
|
674
674
|
end
|
|
675
675
|
|
|
676
|
-
#
|
|
676
|
+
# One hop deeper than `resolve_bare_set!` — an `append:` mutation
|
|
677
677
|
# (`sets :ledger, append: { narrative: :narrative, ... }`) builds
|
|
678
|
-
# a
|
|
678
|
+
# a new element of a list field, not the command's own root
|
|
679
679
|
# record, so a bare self-referential field inside it (the hash
|
|
680
680
|
# key equals its own value, same shorthand `resolve_bare_set!`
|
|
681
681
|
# already reads) can't resolve against `@owner_attributes` — the
|
|
@@ -683,7 +683,7 @@ module Hecks
|
|
|
683
683
|
# element's own construct does (`attribute :ledger,
|
|
684
684
|
# list_of(LedgerEntry)`, and `LedgerEntry` is what actually
|
|
685
685
|
# declares `:narrative`). Resolves the list field's own element
|
|
686
|
-
#
|
|
686
|
+
# type first (`element_type_for`), then that construct's own
|
|
687
687
|
# attribute of the same name — same verbatim-import, one level
|
|
688
688
|
# further down the same reasoning `resolve_bare_set!`'s own
|
|
689
689
|
# comment already gives.
|
|
@@ -693,21 +693,21 @@ module Hecks
|
|
|
693
693
|
# its own key ever qualifies, identical to `resolve_bare_set!`'s
|
|
694
694
|
# own target/source text comparison.
|
|
695
695
|
#
|
|
696
|
-
#
|
|
696
|
+
# Position-preserving, not appended at the end — the exported IR
|
|
697
697
|
# is array-order-sensitive (attributes carry their own declared
|
|
698
698
|
# order onto the wire), so an append's fields are resolved as
|
|
699
|
-
#
|
|
700
|
-
# reinserted at whichever position the group's leftmost
|
|
701
|
-
#
|
|
699
|
+
# one contiguous group, in the mutation's own hash order,
|
|
700
|
+
# reinserted at whichever position the group's leftmost still-
|
|
701
|
+
# declared member already occupies (or the end, if every member
|
|
702
702
|
# of the group is resolved). A plain `attributes << owner_attr`
|
|
703
703
|
# here would only ever reproduce the original order when the
|
|
704
704
|
# missing field happened to already be last — real, live
|
|
705
705
|
# evidence: `Keyword#was`/`Argument#variadic` (both genuinely
|
|
706
706
|
# last in their own append hash) round-tripped correctly under
|
|
707
|
-
# the naive append; every
|
|
707
|
+
# the naive append; every other field in the same hash did not,
|
|
708
708
|
# caught by this codemod's own reboot-and-diff safety net rather
|
|
709
709
|
# than silently landing wrong.
|
|
710
|
-
# `anchor` is a snapshot of `present`'s position, taken
|
|
710
|
+
# `anchor` is a snapshot of `present`'s position, taken before
|
|
711
711
|
# `attributes.reject!` mutates the array below it — see this
|
|
712
712
|
# method's own header comment for why: a naive append-at-end
|
|
713
713
|
# silently scrambled real corpus field order (Keyword#was/
|
|
@@ -735,7 +735,7 @@ module Hecks
|
|
|
735
735
|
attributes.insert(anchor, *group)
|
|
736
736
|
end
|
|
737
737
|
|
|
738
|
-
# The owner's own
|
|
738
|
+
# The owner's own list attribute names its element type as text
|
|
739
739
|
# (`Attribute#type`, unwrapped from `list_of(...)` at declare
|
|
740
740
|
# time) — resolved against `@owner_constructs` (the owner's own
|
|
741
741
|
# value objects and entities, the only two kinds an element can
|
|
@@ -749,7 +749,7 @@ module Hecks
|
|
|
749
749
|
@owner_constructs.find { |construct| construct.hecks_name.to_s == list_attr.type.to_s }
|
|
750
750
|
end
|
|
751
751
|
|
|
752
|
-
#
|
|
752
|
+
# Legacy — see `then_set`'s own comment. The original implementation,
|
|
753
753
|
# verbatim: `from:` still a synonym for `to:`, no omittable-`to:`
|
|
754
754
|
# shorthand, no refusal for the redundant `to: target` spelling —
|
|
755
755
|
# frozen era text was minted under this reading, and a legacy
|
|
@@ -780,11 +780,11 @@ module Hecks
|
|
|
780
780
|
@mutations << Mutation.new(target: target.to_sym, op: op, source: normalize_append_source(op, source))
|
|
781
781
|
end
|
|
782
782
|
|
|
783
|
-
# `append:`
|
|
783
|
+
# `append:` normally binds several fields at once (`append: {
|
|
784
784
|
# name: :name, amount: :amount }`) — `Mutation#appended_fields`/
|
|
785
785
|
# `MutationApplier#appended`/the meta-validator Judge's own
|
|
786
786
|
# `mutation_rows` all read `mutation.source` as a Hash
|
|
787
|
-
# unconditionally. A
|
|
787
|
+
# unconditionally. A bare value (`append: :single_field`, or any
|
|
788
788
|
# non-Hash literal) is the one-field shorthand: exactly what an
|
|
789
789
|
# explicit `append: { value: :single_field }` would have meant,
|
|
790
790
|
# named the same way a single-field value object's own implicit
|