hecks 1.2.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 +60 -2
- 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/postgres_era.adapter +5 -0
- 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 +145 -0
- data/lib/hecks/behaviors/dsl.rb +2 -2
- data/lib/hecks/behaviors/expectations.rb +51 -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 +27 -3
- 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 +122 -86
- 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 +301 -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 +183 -20
- 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 +361 -0
- 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 +124 -0
- data/lib/hecks/fuzzing/form_census.rb +199 -0
- 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 +226 -38
- data/lib/hecks/fuzzing/nondeterministic.rb +67 -0
- data/lib/hecks/fuzzing/persistence_parity.rb +161 -0
- data/lib/hecks/fuzzing/properties/corrections.rb +100 -0
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +321 -41
- data/lib/hecks/fuzzing/properties/guards.rb +129 -26
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +32 -32
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +31 -11
- data/lib/hecks/fuzzing/properties/outbox.rb +142 -0
- data/lib/hecks/fuzzing/properties/querying.rb +17 -17
- data/lib/hecks/fuzzing/properties.rb +84 -39
- data/lib/hecks/fuzzing/qa_settings.rb +152 -0
- data/lib/hecks/fuzzing/replay.rb +224 -114
- data/lib/hecks/fuzzing/rotation_priority.rb +94 -0
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +113 -0
- data/lib/hecks/fuzzing/self_consistency.rb +676 -0
- data/lib/hecks/fuzzing/sequence_generator/adversary.rb +526 -0
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +101 -30
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +55 -8
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +31 -11
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +123 -32
- data/lib/hecks/fuzzing/sequence_generator.rb +152 -31
- data/lib/hecks/fuzzing/shrinker.rb +197 -0
- data/lib/hecks/fuzzing/structural_skips.rb +39 -0
- data/lib/hecks/fuzzing/sweep_depth.rb +53 -0
- data/lib/hecks/fuzzing/target_capabilities.rb +180 -0
- data/lib/hecks/fuzzing/value_generator.rb +66 -14
- data/lib/hecks/fuzzing.rb +11 -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 +365 -15
- data/lib/hecks/language/oidc.json +5 -0
- data/lib/hecks/literal.rb +9 -9
- data/lib/hecks/naming.rb +89 -21
- 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 +160 -58
- 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 +44 -6
- 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 +338 -83
- 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 +29 -6
- 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 +250 -0
- data/lib/hecks/projections/glossary/markdown.rb +105 -0
- data/lib/hecks/projections/glossary/mermaid.rb +110 -0
- data/lib/hecks/projections/glossary/page.css +271 -0
- data/lib/hecks/projections/glossary/page.js +72 -0
- data/lib/hecks/projections/glossary/sections.rb +17 -0
- data/lib/hecks/projections/glossary/sentences.rb +205 -0
- data/lib/hecks/projections/glossary.rb +214 -286
- 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 +15 -22
- 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 +132 -24
- 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 +64 -67
- 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 +94 -19
- 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 +282 -46
- data/lib/hecks/runtime/entity_interpreter.rb +160 -69
- 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 +111 -56
- data/lib/hecks/runtime/reaction_invocation.rb +76 -9
- 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 -112
- 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 +56 -27
- data/lib/hecks/runtime/remote_dispatcher.rb +38 -23
- data/lib/hecks/runtime/routing.rb +10 -88
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +17 -17
- data/lib/hecks/runtime/saga_interpreter.rb +93 -56
- 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 +379 -226
- data/lib/hecks/runtime/value/entity_list_coercion.rb +248 -0
- data/lib/hecks/runtime/value.rb +28 -23
- 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 +207 -5
- 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 +43 -2
|
@@ -6,31 +6,31 @@ module Hecks
|
|
|
6
6
|
# This used to be one hand-written branch per category, and the cost of that
|
|
7
7
|
# shape was fourteen verbs the language declared and the judge never offered
|
|
8
8
|
# — among them `Command.Argument` and `ValueObject.Field`, so a command's own
|
|
9
|
-
# arguments and a value object's own fields were
|
|
9
|
+
# arguments and a value object's own fields were never judged. Every rule
|
|
10
10
|
# hanging off them was decoration. Nothing went red, because a branch that
|
|
11
11
|
# does not exist cannot fail.
|
|
12
12
|
#
|
|
13
|
-
# So there are no branches. The judge
|
|
13
|
+
# So there are no branches. The judge walks: it reads the plan the language
|
|
14
14
|
# makes of itself (Plan), and for each node offers the creating command, then
|
|
15
15
|
# each list through the command that appends to it, then each child. A verb
|
|
16
16
|
# in the plan with no offer is now impossible — there is no branch left in
|
|
17
17
|
# which to forget one, and spec/judge_coverage_spec holds it to that.
|
|
18
18
|
#
|
|
19
|
-
# What is
|
|
19
|
+
# What is not uniform lives in Readings, and only where the IR's shape
|
|
20
20
|
# differs from the language's. Naming differences do not appear at all: the
|
|
21
21
|
# language spells its fields as the IR spells them.
|
|
22
22
|
#
|
|
23
|
-
# Only the
|
|
23
|
+
# Only the dispatch half of the round trip lives here. Reconstruction is the
|
|
24
24
|
# experiment's business ; judging does not need it.
|
|
25
25
|
class Judge
|
|
26
26
|
include Readings
|
|
27
27
|
|
|
28
|
-
# Children offered
|
|
28
|
+
# Children offered before the parent's own lists, in this order. An
|
|
29
29
|
# attribute's type is offered as the id of the thing it names, so the
|
|
30
30
|
# value objects have to exist before anything that can name one — an
|
|
31
|
-
# aggregate's own attributes,
|
|
31
|
+
# aggregate's own attributes, and an entity's own (M13: an entity is its
|
|
32
32
|
# own root, repeating the aggregate's whole shape one level down, so its
|
|
33
|
-
# attributes resolve against the
|
|
33
|
+
# attributes resolve against the same value-object pool). ValueObject
|
|
34
34
|
# first, Entity second, so an entity's own attributes are never offered
|
|
35
35
|
# before the value objects they may reference exist — a self-hosting
|
|
36
36
|
# casualty found live: the meta-grammar's own Handler/Dispatch/Member/
|
|
@@ -43,7 +43,7 @@ module Hecks
|
|
|
43
43
|
# see `detail_node`'s own use of this constant, below.
|
|
44
44
|
EAGER_CHILDREN = { "Aggregate" => %w[ValueObject Entity] }.freeze
|
|
45
45
|
|
|
46
|
-
# Categories an
|
|
46
|
+
# Categories an entity declares as well as an aggregate. The IR reuses
|
|
47
47
|
# Command and Query for a piece's own commands and queries, so the
|
|
48
48
|
# language reuses Command and Query — and the plan cannot express a second
|
|
49
49
|
# parent, because a category's parent is derived from the one `*_id` argument
|
|
@@ -52,9 +52,9 @@ module Hecks
|
|
|
52
52
|
|
|
53
53
|
attr_reader :refusals
|
|
54
54
|
|
|
55
|
-
#
|
|
55
|
+
# **The records survive the verdict**.
|
|
56
56
|
#
|
|
57
|
-
# Judging a bluebook and
|
|
57
|
+
# Judging a bluebook and holding one differ by exactly this: whether anyone
|
|
58
58
|
# keeps the runtime the declarations were dispatched into. Nobody did, so
|
|
59
59
|
# `spec/round_trip_spec` reached the records by `Judge.allocate` and four
|
|
60
60
|
# `instance_variable_set` calls. Reading the chapter back is the point now,
|
|
@@ -71,7 +71,7 @@ module Hecks
|
|
|
71
71
|
|
|
72
72
|
private
|
|
73
73
|
|
|
74
|
-
#
|
|
74
|
+
# Absent is not empty. The rules read "if you declare it, declare
|
|
75
75
|
# something" — a description never given is legal. Passing "" for a nil
|
|
76
76
|
# turns every one of them into "you must declare it".
|
|
77
77
|
#
|
|
@@ -85,7 +85,7 @@ module Hecks
|
|
|
85
85
|
{ value: text.to_s }
|
|
86
86
|
end
|
|
87
87
|
|
|
88
|
-
# A
|
|
88
|
+
# A reference is an ID, and an ID is a scalar.
|
|
89
89
|
#
|
|
90
90
|
# Every other field goes to the meta-domain as a one-field value object,
|
|
91
91
|
# because that is what it is. A reference is not: it carries the id of a
|
|
@@ -105,16 +105,52 @@ module Hecks
|
|
|
105
105
|
yield
|
|
106
106
|
rescue Runtime::GivenNotMet, Runtime::InvariantViolation,
|
|
107
107
|
Runtime::TypeMismatch, Runtime::NotFound => e
|
|
108
|
-
# NotFound is a
|
|
109
|
-
# its value object, so "no ValueObject with id …"
|
|
108
|
+
# NotFound is a verdict, not noise. An attribute's type is a reference to
|
|
109
|
+
# its value object, so "no ValueObject with id …" is the rule `attributes
|
|
110
110
|
# must use value-object types` refusing.
|
|
111
111
|
@refusals << "#{label}: #{e.message}"
|
|
112
112
|
rescue Runtime::UnknownVerb
|
|
113
113
|
nil
|
|
114
114
|
end
|
|
115
115
|
|
|
116
|
+
# QualityControl BUG#125 — every dispatch the judge makes into the
|
|
117
|
+
# meta-domain goes through here, and only here, so this is the one
|
|
118
|
+
# place `Runtime::Value.judge_bootstrapping` needs to wrap: it tells
|
|
119
|
+
# `Value::Coercion#check_scalar_shapes` this construction is the
|
|
120
|
+
# language's own self-hosted grammar walk, not a real domain's
|
|
121
|
+
# command, so a String-typed meta-grammar field (`Normalise`'s
|
|
122
|
+
# `position`, a `RuleText` — `appends`' generic walk-index handling
|
|
123
|
+
# collides with that field's own name, see the flag's own comment
|
|
124
|
+
# in coercion.rb) may still arrive as the raw Integer `appends`
|
|
125
|
+
# hands it. Scoped to exactly this method: nothing outside a judge's
|
|
126
|
+
# own dispatch ever runs inside it, so an ordinary domain command
|
|
127
|
+
# (a real caller's own PieceId, Money, …) is never affected.
|
|
116
128
|
def send_to(verb, label, to: nil, **payload)
|
|
117
|
-
|
|
129
|
+
Runtime::Value.judge_bootstrapping do
|
|
130
|
+
offer(label) { @runtime.dispatch(verb, to: to, with: args(payload)) }
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# The receiver, spelled the way a real caller addresses it.
|
|
135
|
+
#
|
|
136
|
+
# `receiver` is an internal accumulator — it tracks the aggregate this
|
|
137
|
+
# walk is inside and, once it crosses into a real entity-owned category
|
|
138
|
+
# (Member/Handler/Dispatch — S17, ADR 0026), every entity hop on top of
|
|
139
|
+
# it. But `Routing.envelope`/`parse_envelope_hash` do not want that
|
|
140
|
+
# shape restated when there is no entity to route to: a plain aggregate
|
|
141
|
+
# command is addressed by its bare id (`Facade::Handle#dispatch` — "to:
|
|
142
|
+
# @id" — and `CommandRequest`'s own header: "aggregate command: { to:
|
|
143
|
+
# "record-id", ... }"), never `{aggregate:, entities: []}` — that hash
|
|
144
|
+
# is the entity route's own shape, degenerate with nothing in it.
|
|
145
|
+
#
|
|
146
|
+
# So this is the one place `receiver` turns into a `to:` value: bare
|
|
147
|
+
# when there is no entity hop (the overwhelming common case — every
|
|
148
|
+
# category but those three), the full envelope only when there
|
|
149
|
+
# genuinely is one.
|
|
150
|
+
def address(receiver)
|
|
151
|
+
return receiver[:aggregate] if receiver[:entities].empty?
|
|
152
|
+
|
|
153
|
+
receiver
|
|
118
154
|
end
|
|
119
155
|
|
|
120
156
|
def judge!
|
|
@@ -122,19 +158,19 @@ module Hecks
|
|
|
122
158
|
detail_node("Bluebook", @bluebook, nil, 0)
|
|
123
159
|
end
|
|
124
160
|
|
|
125
|
-
#
|
|
161
|
+
# Declared before detailed, for every set of siblings.
|
|
126
162
|
#
|
|
127
163
|
# A node used to be offered whole — declared, then its lists, then its
|
|
128
164
|
# children — one sibling at a time. Which means an aggregate's attributes
|
|
129
165
|
# were offered before its later siblings existed, and an attribute that
|
|
130
|
-
#
|
|
166
|
+
# points at another aggregate could only resolve if that aggregate happened
|
|
131
167
|
# to be declared earlier in the file. Banking survives on luck: Customer is
|
|
132
168
|
# written above Account.
|
|
133
169
|
#
|
|
134
170
|
# So siblings are declared in one pass and detailed in a second. It is the
|
|
135
171
|
# same ordering the walk already used one level down — value objects before
|
|
136
172
|
# the attributes that name them — lifted to the level above, and it is what
|
|
137
|
-
# lets a reference be a
|
|
173
|
+
# lets a reference be a reference rather than a string nobody can check.
|
|
138
174
|
def declare_node(category, node, parent_id, index, extra = {}, receiver: nil)
|
|
139
175
|
plan = @plan.category(category)
|
|
140
176
|
return unless plan
|
|
@@ -147,34 +183,34 @@ module Hecks
|
|
|
147
183
|
return unless plan
|
|
148
184
|
|
|
149
185
|
id = identify(category, parent_id, node, index)
|
|
150
|
-
# `extra` is the
|
|
151
|
-
# ancestor above this node (Handler's own `event_type`
|
|
186
|
+
# `extra` is the cumulative identity of every entity-owned
|
|
187
|
+
# ancestor above this node (Handler's own `event_type` and
|
|
152
188
|
# ProcessManager's own `bluebook`/`name`, by the time Dispatch
|
|
153
189
|
# is reached — S17, ADR 0026's two-level chain). `identity`
|
|
154
|
-
# adds
|
|
190
|
+
# adds this node's own on top — computed for every category,
|
|
155
191
|
# entity-owned or not, because a node need not be entity-owned
|
|
156
|
-
# itself to
|
|
157
|
-
# its `aggregate:`/`name:`) — it is simply what
|
|
192
|
+
# itself to own one (ValueObject isn't, and Member still needs
|
|
193
|
+
# its `aggregate:`/`name:`) — it is simply what this node's own
|
|
158
194
|
# `identified_by` resolves to, the same fields `identify` two
|
|
159
|
-
# lines up already derives the joined id
|
|
195
|
+
# lines up already derives the joined id from.
|
|
160
196
|
#
|
|
161
|
-
# `own` is the
|
|
162
|
-
# only when
|
|
197
|
+
# `own` is the subset actually spent on a dispatch payload —
|
|
198
|
+
# only when this category is itself entity-owned, since an
|
|
163
199
|
# ordinary category (Command's own "Rule"/"Argument", offered
|
|
164
|
-
# through the
|
|
200
|
+
# through the same `extra` slot for a different reason, see
|
|
165
201
|
# `within_entity` below) locates the record it attaches to
|
|
166
202
|
# through the parent id `id:` already carries, and merging
|
|
167
|
-
# unrecognized `aggregate:`/`entity_id:` into
|
|
203
|
+
# unrecognized `aggregate:`/`entity_id:` into their payload
|
|
168
204
|
# would have the runtime refuse them for an argument they
|
|
169
205
|
# never declared.
|
|
170
206
|
identity = extra.merge(node_identity(plan, category, node, index, parent_id))
|
|
171
207
|
receiver ||= { aggregate: id, entities: [] }
|
|
172
208
|
eager, later = children_of(category).partition { |child| eager?(category, child) }
|
|
173
|
-
#
|
|
209
|
+
# Ordered as `EAGER_CHILDREN` declares, not as `children_of` happens to
|
|
174
210
|
# list them — `children_of` reads `@plan.names`, whose own order is an
|
|
175
211
|
# accident of which .bluebook file registered which category first,
|
|
176
212
|
# never a promise about which of two eager children exists before the
|
|
177
|
-
# other. `EAGER_CHILDREN`'s own array
|
|
213
|
+
# other. `EAGER_CHILDREN`'s own array is that promise (ValueObject
|
|
178
214
|
# before Entity), so the walk keeps only what this parent actually
|
|
179
215
|
# has, in the order the constant states — see that constant's own
|
|
180
216
|
# comment for the bug this exact reordering fixes.
|
|
@@ -182,12 +218,12 @@ module Hecks
|
|
|
182
218
|
|
|
183
219
|
eager.each { |child| walk_all(child, node, id, entity_child_extra(child, identity), receiver: receiver) }
|
|
184
220
|
setters(plan, category, node, receiver)
|
|
185
|
-
#
|
|
186
|
-
# walks an aggregate's
|
|
221
|
+
# Before `appends`, not after — the same reason `EAGER_CHILDREN`
|
|
222
|
+
# walks an aggregate's own entities before its own attributes
|
|
187
223
|
# (M13): a piece nested inside a piece (Handler's own
|
|
188
224
|
# `dispatches, list_of(Dispatch)` — S17, ADR 0026) must exist
|
|
189
225
|
# before this piece's own attribute list can reference it as a
|
|
190
|
-
#
|
|
226
|
+
# held entity, the same way `Account#ledger` needs Account's own
|
|
191
227
|
# entities walked eagerly. `nest_entities` is a no-op for every
|
|
192
228
|
# category but "Entity" (its own early return), so reordering it
|
|
193
229
|
# ahead of `appends` costs nothing for anything else that walks
|
|
@@ -199,11 +235,11 @@ module Hecks
|
|
|
199
235
|
sealers(plan, category, receiver)
|
|
200
236
|
end
|
|
201
237
|
|
|
202
|
-
#
|
|
203
|
-
# own dotted dispatch needs every
|
|
238
|
+
# What a child's own `extra` starts from. An entity-owned child's
|
|
239
|
+
# own dotted dispatch needs every ancestor's identity, which is
|
|
204
240
|
# exactly `identity` — already accumulated one level at a time by
|
|
205
241
|
# `detail_node` itself (regardless of whether each ancestor is
|
|
206
|
-
#
|
|
242
|
+
# itself entity-owned — ValueObject contributes its own `aggregate:
|
|
207
243
|
# `/`name:` to Member's payload despite being an ordinary top-
|
|
208
244
|
# level category), so there is nothing left to re-derive here. An
|
|
209
245
|
# ordinary child (one with a real top-level aggregate of its own
|
|
@@ -212,15 +248,15 @@ module Hecks
|
|
|
212
248
|
@plan.category(child)&.entity_owned ? identity : {}
|
|
213
249
|
end
|
|
214
250
|
|
|
215
|
-
#
|
|
251
|
+
# One node's own identity, read off its own declaration — S17,
|
|
216
252
|
# ADR 0026. Three cases, the same three `identify`/`identity_part`
|
|
217
253
|
# already resolve one level up, unified here because a chain now
|
|
218
254
|
# walks more than one level (Handler -> Dispatch) and each level
|
|
219
|
-
# needs the
|
|
255
|
+
# needs the same three answered about itself, not just the first:
|
|
220
256
|
#
|
|
221
257
|
# the parent link (plan.parent_key) -> `parent_id`, the id
|
|
222
258
|
# the walk already carries in from one level up
|
|
223
|
-
# a walk-minted one (POSITION) -> the walk
|
|
259
|
+
# a walk-minted one (POSITION) -> the walk index itself ;
|
|
224
260
|
# never a stored field (Member's own header:
|
|
225
261
|
# "position is not a mint — it is read straight
|
|
226
262
|
# out of the source file")
|
|
@@ -249,9 +285,9 @@ module Hecks
|
|
|
249
285
|
end
|
|
250
286
|
end
|
|
251
287
|
|
|
252
|
-
#
|
|
288
|
+
# The full dotted prefix a category's own verbs hang off — the
|
|
253
289
|
# plain name for an ordinary category (its own top-level
|
|
254
|
-
# aggregate reaches every verb bare), or its
|
|
290
|
+
# aggregate reaches every verb bare), or its parent's own prefix
|
|
255
291
|
# with this category's name appended, for an entity-owned one.
|
|
256
292
|
# Dispatch's own parent, Handler, is itself entity-owned (S17,
|
|
257
293
|
# ADR 0026's two-level chain — `ProcessManager.Handler.Dispatch`),
|
|
@@ -262,9 +298,9 @@ module Hecks
|
|
|
262
298
|
"#{dotted_prefix(@plan.category(plan.parent))}.#{plan.name}"
|
|
263
299
|
end
|
|
264
300
|
|
|
265
|
-
#
|
|
301
|
+
# Entity-owned categories have no top-level aggregate for the runtime
|
|
266
302
|
# to route a bare verb into any more — `Member`'s own "Pair" reaches
|
|
267
|
-
# the runtime as `ValueObject.Member.Pair`, and a
|
|
303
|
+
# the runtime as `ValueObject.Member.Pair`, and a nested one
|
|
268
304
|
# (`Dispatch`, inside `Handler`) reaches it as `ProcessManager.
|
|
269
305
|
# Handler.Dispatch.Bind` — the dotted shape `EntityInterpreter#call`
|
|
270
306
|
# already splits any real entity's own verb into, one hop per
|
|
@@ -290,12 +326,12 @@ module Hecks
|
|
|
290
326
|
end
|
|
291
327
|
end
|
|
292
328
|
|
|
293
|
-
# A piece's commands and queries, addressed under the
|
|
329
|
+
# A piece's commands and queries, addressed under the piece so two commands
|
|
294
330
|
# of the same name on an aggregate and on one of its entities cannot collide,
|
|
295
331
|
# while `aggregate` still names the aggregate the reference resolves
|
|
296
332
|
# against and `entity_id` says which piece declared it. `entity_id`
|
|
297
|
-
# keeps its own `_id` — an
|
|
298
|
-
# never touched by ADR 0025's rename (only the
|
|
333
|
+
# keeps its own `_id` — an explicit `as:` on `reference_to Entity`,
|
|
334
|
+
# never touched by ADR 0025's rename (only the default, un-aliased
|
|
299
335
|
# mint dropped the suffix; `aggregate` did precisely because
|
|
300
336
|
# `Command#reference_to Aggregate`/`Query#reference_to Aggregate`
|
|
301
337
|
# carry no `as:` of their own).
|
|
@@ -311,26 +347,26 @@ module Hecks
|
|
|
311
347
|
end
|
|
312
348
|
end
|
|
313
349
|
|
|
314
|
-
#
|
|
350
|
+
# An entity may nest further entities — S17, ADR 0026's own words:
|
|
315
351
|
# "That is what `entity` is for, and `entity` is declared by the
|
|
316
352
|
# language and used zero times in it." `Dispatch`, inside
|
|
317
|
-
# `Handler`, is the first real use. The
|
|
353
|
+
# `Handler`, is the first real use. The generic "Entity" category
|
|
318
354
|
# cannot express this through `children_of`/`EAGER_CHILDREN` the
|
|
319
355
|
# way Aggregate's own entities/value_objects can — there is only
|
|
320
|
-
#
|
|
356
|
+
# one "Entity" Plan category, describing what any entity looks
|
|
321
357
|
# like, not one per nesting level — so this recurses by hand,
|
|
322
358
|
# the same special case `within_entity` (above) already is for
|
|
323
359
|
# Command/Query.
|
|
324
360
|
#
|
|
325
361
|
# `owner` is the field this repurposes — `entity.bluebook`
|
|
326
362
|
# declares it (`attribute :owner, EntityText`) and it has held
|
|
327
|
-
# exactly one value since ADR 0025's rename: the
|
|
328
|
-
# `aggregate` already carries, kept as a wrapped-text
|
|
363
|
+
# exactly one value since ADR 0025's rename: the same id
|
|
364
|
+
# `aggregate` already carries, kept as a wrapped-text copy,
|
|
329
365
|
# never read back anywhere else in this codebase (grep finds no
|
|
330
|
-
# second reference). For a
|
|
331
|
-
# diverge — `aggregate` stays the
|
|
366
|
+
# second reference). For a nested entity, the two finally
|
|
367
|
+
# diverge — `aggregate` stays the root (Dispatch resolves
|
|
332
368
|
# exactly the way any other Entity record does, by its root
|
|
333
|
-
# aggregate), and `owner` becomes
|
|
369
|
+
# aggregate), and `owner` becomes this entity's own direct
|
|
334
370
|
# parent (Handler, not ProcessManager) — which is exactly the
|
|
335
371
|
# fact `Reconstruction#direct_entities` needs to tell a
|
|
336
372
|
# root-level entity apart from a nested one sharing the same
|
|
@@ -345,13 +381,13 @@ module Hecks
|
|
|
345
381
|
})
|
|
346
382
|
end
|
|
347
383
|
|
|
348
|
-
#
|
|
384
|
+
# Where it sits among its siblings is a fact about the walk, not about the
|
|
349
385
|
# node : a command does not know it is the third command on its aggregate.
|
|
350
386
|
# The walk knows, so the walk supplies it, and every other field still
|
|
351
387
|
# comes from the node. Declaration order used to survive only because the
|
|
352
388
|
# meta store happened to iterate in insertion order — an accident that an
|
|
353
389
|
# ask ordered any other way would have taken away, and Reconstruction is
|
|
354
|
-
# the one reader that must have the
|
|
390
|
+
# the one reader that must have the source's order rather than a stable one.
|
|
355
391
|
# `private` above has no effect on a constant; kept here anyway,
|
|
356
392
|
# beside the method that reads it, for the narrative.
|
|
357
393
|
# rubocop:disable-next Lint/UselessConstantScoping
|
|
@@ -384,7 +420,7 @@ module Hecks
|
|
|
384
420
|
end
|
|
385
421
|
next if payload.values.all?(&:nil?)
|
|
386
422
|
|
|
387
|
-
send_to("Bluebook::#{verb_for(plan, setter.verb)}", receiver[:aggregate], to: receiver, **payload)
|
|
423
|
+
send_to("Bluebook::#{verb_for(plan, setter.verb)}", receiver[:aggregate], to: address(receiver), **payload)
|
|
388
424
|
end
|
|
389
425
|
end
|
|
390
426
|
|
|
@@ -394,7 +430,7 @@ module Hecks
|
|
|
394
430
|
plan.appends.each do |list_name, append|
|
|
395
431
|
rows_for(category, list_name, node).each_with_index do |row, index|
|
|
396
432
|
chosen = append_for(category, list_name, append, row, node)
|
|
397
|
-
# `position`
|
|
433
|
+
# `position` is the walk index here exactly as it is in `declare` —
|
|
398
434
|
# an appended element that names its position (ValueObject.Member,
|
|
399
435
|
# S17) is ordered by where the walk found it, never by a field the
|
|
400
436
|
# row happens to hold.
|
|
@@ -409,20 +445,20 @@ module Hecks
|
|
|
409
445
|
end
|
|
410
446
|
|
|
411
447
|
send_to("Bluebook::#{verb_for(plan, chosen.verb)}", "#{id}##{list_name}[#{index}]",
|
|
412
|
-
to: receiver, **payload)
|
|
448
|
+
to: address(receiver), **payload)
|
|
413
449
|
end
|
|
414
450
|
end
|
|
415
451
|
end
|
|
416
452
|
|
|
417
|
-
#
|
|
453
|
+
# Which aggregate owns the value objects an attribute's type may
|
|
418
454
|
# resolve against. An aggregate owns its own — `id` already names
|
|
419
455
|
# it. An entity never has value objects of its own (Entity
|
|
420
456
|
# deliberately never answers `value_object` — see entity.rb's own
|
|
421
|
-
# comment on why); its attributes read the
|
|
457
|
+
# comment on why); its attributes read the same pool its
|
|
422
458
|
# enclosing aggregate declares, one level up the construct tree
|
|
423
459
|
# no matter how many entities deep this attribute is nested —
|
|
424
460
|
# `parent_id` names it because `detail_node`/`nest_entities`
|
|
425
|
-
# thread the
|
|
461
|
+
# thread the root aggregate's id down as `parent_id` at every
|
|
426
462
|
# entity level, never the direct (possibly entity) parent.
|
|
427
463
|
def owning_aggregate_ref(category, id, parent_id)
|
|
428
464
|
category == "Entity" ? parent_id : id
|
|
@@ -430,33 +466,33 @@ module Hecks
|
|
|
430
466
|
|
|
431
467
|
def sealers(plan, _category, receiver)
|
|
432
468
|
id = receiver[:entities].last || receiver[:aggregate]
|
|
433
|
-
plan.sealers.each { |verb| send_to("Bluebook::#{verb_for(plan, verb)}", id, to: receiver) }
|
|
469
|
+
plan.sealers.each { |verb| send_to("Bluebook::#{verb_for(plan, verb)}", id, to: address(receiver)) }
|
|
434
470
|
end
|
|
435
471
|
|
|
436
|
-
# An aggregate's or an entity's attribute names its value object by
|
|
472
|
+
# An aggregate's or an entity's attribute names its value object by type,
|
|
437
473
|
# and the language models that as a reference — so the type is offered as
|
|
438
474
|
# the value object's own id. This is the rule "attributes must use
|
|
439
475
|
# value-object types", enforced by reference resolution rather than by a
|
|
440
|
-
# predicate — for a
|
|
476
|
+
# predicate — for a head's own attributes, aggregate or entity alike: an
|
|
441
477
|
# entity is its own root, repeating the aggregate's whole shape one level
|
|
442
478
|
# down (entity.rb's own words), and an undeclared type on an entity's
|
|
443
479
|
# attribute must fail the same reference resolution an aggregate's own
|
|
444
480
|
# does, not go unchecked because only "Aggregate.attributes" was ever
|
|
445
481
|
# asked.
|
|
446
|
-
# An attribute's type is offered as the ID
|
|
482
|
+
# An attribute's type is offered as the ID of the thing it names, so the
|
|
447
483
|
# language resolves it as a reference and "the type is declared" costs no
|
|
448
484
|
# predicate. Three kinds, three ids: a value object and an entity both hang
|
|
449
485
|
# off this aggregate, so they share its prefix; another aggregate's head
|
|
450
486
|
# hangs off the chapter.
|
|
451
487
|
def cell(category, list_name, row, field, id, append, aggregate_id)
|
|
452
488
|
value = row_value(row, field)
|
|
453
|
-
# A default keeps its
|
|
489
|
+
# A default keeps its type by being written as a literal — 0.0 rather than
|
|
454
490
|
# "0.0" — because the language holds it as text and text alone forgets.
|
|
455
491
|
return encode_literal(value) if field == :default
|
|
456
492
|
return value unless field == :type
|
|
457
|
-
# A
|
|
493
|
+
# A reference names another head wherever it is written — on a head, on
|
|
458
494
|
# a command, on a piece, on an ask — so it is offered as that head's
|
|
459
|
-
# id in all four. Only a
|
|
495
|
+
# id in all four. Only a head's own attributes additionally qualify
|
|
460
496
|
# an ordinary type into a value object's id ; a command argument's
|
|
461
497
|
# type is text and stays text.
|
|
462
498
|
return points_at(row, id) if append.verb == "Reference"
|
|
@@ -465,7 +501,7 @@ module Hecks
|
|
|
465
501
|
Naming.identity([owning_aggregate_id(aggregate_id, value), value])
|
|
466
502
|
end
|
|
467
503
|
|
|
468
|
-
# A
|
|
504
|
+
# A head's own attributes — an aggregate's, or an entity's (its own root,
|
|
469
505
|
# one level down). Every other "attributes" list belongs to something that
|
|
470
506
|
# is not a head at all (a command's arguments, a value object's own
|
|
471
507
|
# fields), and a type written there is a name, not a reference — the same
|
|
@@ -474,27 +510,27 @@ module Hecks
|
|
|
474
510
|
list_name.to_s == "attributes" && %w[Aggregate Entity].include?(category)
|
|
475
511
|
end
|
|
476
512
|
|
|
477
|
-
# `id`
|
|
513
|
+
# `id` names the attribute's own aggregate, not necessarily the
|
|
478
514
|
# value object's — Wave 7's own translation.bluebook/translation_
|
|
479
515
|
# aggregate.bluebook split proved the difference live:
|
|
480
516
|
# TranslationAggregate's own `was`/every rename-rule's own `from`/
|
|
481
|
-
# `to`/... all deliberately reuse the
|
|
517
|
+
# `to`/... all deliberately reuse the sibling "Translation"
|
|
482
518
|
# aggregate's own `TranslationName` (that file's own header:
|
|
483
519
|
# "the shared TranslationName every non-identity field below
|
|
484
520
|
# uses"), a real, intentional cross-aggregate reuse — not the
|
|
485
|
-
# local-only ownership every
|
|
521
|
+
# local-only ownership every other real domain in this corpus
|
|
486
522
|
# happens to have used until now.
|
|
487
523
|
#
|
|
488
524
|
# `id` (already `Naming.identity([chapter, aggregate])`-joined)
|
|
489
|
-
# only ever composes with the
|
|
525
|
+
# only ever composes with the local aggregate for real, non-
|
|
490
526
|
# entity-owned attributes — an entity's own `id` never matches
|
|
491
|
-
# any
|
|
527
|
+
# any top-level aggregate here, so `local` stays nil and this
|
|
492
528
|
# returns `id` unchanged, exactly the prior behavior. Same for
|
|
493
|
-
# every attribute whose type
|
|
529
|
+
# every attribute whose type is locally declared (the overwhelming
|
|
494
530
|
# common case, Banking's own Customer/Account included) — this
|
|
495
|
-
# only ever changes the answer when the local aggregate does
|
|
531
|
+
# only ever changes the answer when the local aggregate does not
|
|
496
532
|
# declare `value` itself, falling back to the first (declaration-
|
|
497
|
-
# order)
|
|
533
|
+
# order) other aggregate in the same chapter that does.
|
|
498
534
|
def owning_aggregate_id(id, value)
|
|
499
535
|
local = @bluebook.aggregates.find { |aggregate| Naming.identity([@bluebook.name, aggregate.name]) == id }
|
|
500
536
|
return id unless local
|
|
@@ -527,13 +563,13 @@ module Hecks
|
|
|
527
563
|
# Reference its type is Reference<X>, another aggregate's head
|
|
528
564
|
# Holds its type names an entity this aggregate declares
|
|
529
565
|
#
|
|
530
|
-
#
|
|
566
|
+
# Nothing is skipped any more. Reference and Holds did not exist, so the
|
|
531
567
|
# walk dropped both kinds and the meta-domain silently did not contain
|
|
532
568
|
# Account#customer_id or Account#ledger.
|
|
533
|
-
# Each alternate carries its
|
|
569
|
+
# Each alternate carries its own map, read from the language. Borrowing the
|
|
534
570
|
# primary's map dispatched `type:` where Reference declares `points_at:`,
|
|
535
571
|
# and the payload gate caught it — which is the gate paying for itself.
|
|
536
|
-
# `reference_to` can be written in
|
|
572
|
+
# `reference_to` can be written in four places — on a head, a command, a
|
|
537
573
|
# piece, an ask — and each keeps its own list of attributes, so each
|
|
538
574
|
# needs the Reference alternate. Only a head can hold a piece, so Holds
|
|
539
575
|
# stays where it was.
|
|
@@ -551,7 +587,7 @@ module Hecks
|
|
|
551
587
|
|
|
552
588
|
def reference_row?(row) = row.respond_to?(:reference?) && row.reference?
|
|
553
589
|
|
|
554
|
-
# Only a
|
|
590
|
+
# Only a head declares pieces, and now that every attribute list reaches
|
|
555
591
|
# this, the node may be a command, a piece or an ask — none of which
|
|
556
592
|
# answer `entities` at all.
|
|
557
593
|
def entity_row?(row, node)
|
|
@@ -560,7 +596,7 @@ module Hecks
|
|
|
560
596
|
Array(node.entities).any? { |entity| entity.hecks_name == row.type.to_s }
|
|
561
597
|
end
|
|
562
598
|
|
|
563
|
-
# A
|
|
599
|
+
# A record's ID is its declared identity, joined — the same join the runtime
|
|
564
600
|
# does, off the same declaration, because there is only one way to name a
|
|
565
601
|
# thing and it should be written once.
|
|
566
602
|
#
|
|
@@ -580,14 +616,14 @@ module Hecks
|
|
|
580
616
|
Naming.identity(plan.identity_paths.map { |path| identity_part(plan, path, parent_id, node, index, category) })
|
|
581
617
|
end
|
|
582
618
|
|
|
583
|
-
# "owner_id" is a
|
|
584
|
-
# whichever record is walking
|
|
619
|
+
# "owner_id" is a second reserved head, beside `position` : it names
|
|
620
|
+
# whichever record is walking this one right now, aggregate or entity
|
|
585
621
|
# alike, without saying which — Command and Query read it so an
|
|
586
622
|
# entity's verbs are the entity's own. It is never a declared
|
|
587
623
|
# attribute (declaring one for a field that names two different types
|
|
588
624
|
# would be a lie about which), so it cannot be read through
|
|
589
625
|
# `field_value` ; it is read the same way `plan.parent_key` already is,
|
|
590
|
-
# because it
|
|
626
|
+
# because it is that fact, spelled for the walk's immediate parent
|
|
591
627
|
# rather than for one specific kind of one.
|
|
592
628
|
# `private` above has no effect on a constant; kept here anyway,
|
|
593
629
|
# beside the method that reads it, for the narrative.
|