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
|
@@ -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,31 +105,45 @@ 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
|
|
118
132
|
end
|
|
119
133
|
|
|
120
|
-
#
|
|
134
|
+
# The receiver, spelled the way a real caller addresses it.
|
|
121
135
|
#
|
|
122
136
|
# `receiver` is an internal accumulator — it tracks the aggregate this
|
|
123
|
-
# walk is inside
|
|
137
|
+
# walk is inside and, once it crosses into a real entity-owned category
|
|
124
138
|
# (Member/Handler/Dispatch — S17, ADR 0026), every entity hop on top of
|
|
125
139
|
# it. But `Routing.envelope`/`parse_envelope_hash` do not want that
|
|
126
140
|
# shape restated when there is no entity to route to: a plain aggregate
|
|
127
141
|
# command is addressed by its bare id (`Facade::Handle#dispatch` — "to:
|
|
128
142
|
# @id" — and `CommandRequest`'s own header: "aggregate command: { to:
|
|
129
143
|
# "record-id", ... }"), never `{aggregate:, entities: []}` — that hash
|
|
130
|
-
# is the
|
|
144
|
+
# is the entity route's own shape, degenerate with nothing in it.
|
|
131
145
|
#
|
|
132
|
-
# So
|
|
146
|
+
# So this is the one place `receiver` turns into a `to:` value: bare
|
|
133
147
|
# when there is no entity hop (the overwhelming common case — every
|
|
134
148
|
# category but those three), the full envelope only when there
|
|
135
149
|
# genuinely is one.
|
|
@@ -144,19 +158,19 @@ module Hecks
|
|
|
144
158
|
detail_node("Bluebook", @bluebook, nil, 0)
|
|
145
159
|
end
|
|
146
160
|
|
|
147
|
-
#
|
|
161
|
+
# Declared before detailed, for every set of siblings.
|
|
148
162
|
#
|
|
149
163
|
# A node used to be offered whole — declared, then its lists, then its
|
|
150
164
|
# children — one sibling at a time. Which means an aggregate's attributes
|
|
151
165
|
# were offered before its later siblings existed, and an attribute that
|
|
152
|
-
#
|
|
166
|
+
# points at another aggregate could only resolve if that aggregate happened
|
|
153
167
|
# to be declared earlier in the file. Banking survives on luck: Customer is
|
|
154
168
|
# written above Account.
|
|
155
169
|
#
|
|
156
170
|
# So siblings are declared in one pass and detailed in a second. It is the
|
|
157
171
|
# same ordering the walk already used one level down — value objects before
|
|
158
172
|
# the attributes that name them — lifted to the level above, and it is what
|
|
159
|
-
# lets a reference be a
|
|
173
|
+
# lets a reference be a reference rather than a string nobody can check.
|
|
160
174
|
def declare_node(category, node, parent_id, index, extra = {}, receiver: nil)
|
|
161
175
|
plan = @plan.category(category)
|
|
162
176
|
return unless plan
|
|
@@ -169,34 +183,34 @@ module Hecks
|
|
|
169
183
|
return unless plan
|
|
170
184
|
|
|
171
185
|
id = identify(category, parent_id, node, index)
|
|
172
|
-
# `extra` is the
|
|
173
|
-
# 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
|
|
174
188
|
# ProcessManager's own `bluebook`/`name`, by the time Dispatch
|
|
175
189
|
# is reached — S17, ADR 0026's two-level chain). `identity`
|
|
176
|
-
# adds
|
|
190
|
+
# adds this node's own on top — computed for every category,
|
|
177
191
|
# entity-owned or not, because a node need not be entity-owned
|
|
178
|
-
# itself to
|
|
179
|
-
# 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
|
|
180
194
|
# `identified_by` resolves to, the same fields `identify` two
|
|
181
|
-
# lines up already derives the joined id
|
|
195
|
+
# lines up already derives the joined id from.
|
|
182
196
|
#
|
|
183
|
-
# `own` is the
|
|
184
|
-
# only when
|
|
197
|
+
# `own` is the subset actually spent on a dispatch payload —
|
|
198
|
+
# only when this category is itself entity-owned, since an
|
|
185
199
|
# ordinary category (Command's own "Rule"/"Argument", offered
|
|
186
|
-
# through the
|
|
200
|
+
# through the same `extra` slot for a different reason, see
|
|
187
201
|
# `within_entity` below) locates the record it attaches to
|
|
188
202
|
# through the parent id `id:` already carries, and merging
|
|
189
|
-
# unrecognized `aggregate:`/`entity_id:` into
|
|
203
|
+
# unrecognized `aggregate:`/`entity_id:` into their payload
|
|
190
204
|
# would have the runtime refuse them for an argument they
|
|
191
205
|
# never declared.
|
|
192
206
|
identity = extra.merge(node_identity(plan, category, node, index, parent_id))
|
|
193
207
|
receiver ||= { aggregate: id, entities: [] }
|
|
194
208
|
eager, later = children_of(category).partition { |child| eager?(category, child) }
|
|
195
|
-
#
|
|
209
|
+
# Ordered as `EAGER_CHILDREN` declares, not as `children_of` happens to
|
|
196
210
|
# list them — `children_of` reads `@plan.names`, whose own order is an
|
|
197
211
|
# accident of which .bluebook file registered which category first,
|
|
198
212
|
# never a promise about which of two eager children exists before the
|
|
199
|
-
# other. `EAGER_CHILDREN`'s own array
|
|
213
|
+
# other. `EAGER_CHILDREN`'s own array is that promise (ValueObject
|
|
200
214
|
# before Entity), so the walk keeps only what this parent actually
|
|
201
215
|
# has, in the order the constant states — see that constant's own
|
|
202
216
|
# comment for the bug this exact reordering fixes.
|
|
@@ -204,12 +218,12 @@ module Hecks
|
|
|
204
218
|
|
|
205
219
|
eager.each { |child| walk_all(child, node, id, entity_child_extra(child, identity), receiver: receiver) }
|
|
206
220
|
setters(plan, category, node, receiver)
|
|
207
|
-
#
|
|
208
|
-
# 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
|
|
209
223
|
# (M13): a piece nested inside a piece (Handler's own
|
|
210
224
|
# `dispatches, list_of(Dispatch)` — S17, ADR 0026) must exist
|
|
211
225
|
# before this piece's own attribute list can reference it as a
|
|
212
|
-
#
|
|
226
|
+
# held entity, the same way `Account#ledger` needs Account's own
|
|
213
227
|
# entities walked eagerly. `nest_entities` is a no-op for every
|
|
214
228
|
# category but "Entity" (its own early return), so reordering it
|
|
215
229
|
# ahead of `appends` costs nothing for anything else that walks
|
|
@@ -221,11 +235,11 @@ module Hecks
|
|
|
221
235
|
sealers(plan, category, receiver)
|
|
222
236
|
end
|
|
223
237
|
|
|
224
|
-
#
|
|
225
|
-
# 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
|
|
226
240
|
# exactly `identity` — already accumulated one level at a time by
|
|
227
241
|
# `detail_node` itself (regardless of whether each ancestor is
|
|
228
|
-
#
|
|
242
|
+
# itself entity-owned — ValueObject contributes its own `aggregate:
|
|
229
243
|
# `/`name:` to Member's payload despite being an ordinary top-
|
|
230
244
|
# level category), so there is nothing left to re-derive here. An
|
|
231
245
|
# ordinary child (one with a real top-level aggregate of its own
|
|
@@ -234,15 +248,15 @@ module Hecks
|
|
|
234
248
|
@plan.category(child)&.entity_owned ? identity : {}
|
|
235
249
|
end
|
|
236
250
|
|
|
237
|
-
#
|
|
251
|
+
# One node's own identity, read off its own declaration — S17,
|
|
238
252
|
# ADR 0026. Three cases, the same three `identify`/`identity_part`
|
|
239
253
|
# already resolve one level up, unified here because a chain now
|
|
240
254
|
# walks more than one level (Handler -> Dispatch) and each level
|
|
241
|
-
# needs the
|
|
255
|
+
# needs the same three answered about itself, not just the first:
|
|
242
256
|
#
|
|
243
257
|
# the parent link (plan.parent_key) -> `parent_id`, the id
|
|
244
258
|
# the walk already carries in from one level up
|
|
245
|
-
# a walk-minted one (POSITION) -> the walk
|
|
259
|
+
# a walk-minted one (POSITION) -> the walk index itself ;
|
|
246
260
|
# never a stored field (Member's own header:
|
|
247
261
|
# "position is not a mint — it is read straight
|
|
248
262
|
# out of the source file")
|
|
@@ -271,9 +285,9 @@ module Hecks
|
|
|
271
285
|
end
|
|
272
286
|
end
|
|
273
287
|
|
|
274
|
-
#
|
|
288
|
+
# The full dotted prefix a category's own verbs hang off — the
|
|
275
289
|
# plain name for an ordinary category (its own top-level
|
|
276
|
-
# aggregate reaches every verb bare), or its
|
|
290
|
+
# aggregate reaches every verb bare), or its parent's own prefix
|
|
277
291
|
# with this category's name appended, for an entity-owned one.
|
|
278
292
|
# Dispatch's own parent, Handler, is itself entity-owned (S17,
|
|
279
293
|
# ADR 0026's two-level chain — `ProcessManager.Handler.Dispatch`),
|
|
@@ -284,9 +298,9 @@ module Hecks
|
|
|
284
298
|
"#{dotted_prefix(@plan.category(plan.parent))}.#{plan.name}"
|
|
285
299
|
end
|
|
286
300
|
|
|
287
|
-
#
|
|
301
|
+
# Entity-owned categories have no top-level aggregate for the runtime
|
|
288
302
|
# to route a bare verb into any more — `Member`'s own "Pair" reaches
|
|
289
|
-
# the runtime as `ValueObject.Member.Pair`, and a
|
|
303
|
+
# the runtime as `ValueObject.Member.Pair`, and a nested one
|
|
290
304
|
# (`Dispatch`, inside `Handler`) reaches it as `ProcessManager.
|
|
291
305
|
# Handler.Dispatch.Bind` — the dotted shape `EntityInterpreter#call`
|
|
292
306
|
# already splits any real entity's own verb into, one hop per
|
|
@@ -312,12 +326,12 @@ module Hecks
|
|
|
312
326
|
end
|
|
313
327
|
end
|
|
314
328
|
|
|
315
|
-
# A piece's commands and queries, addressed under the
|
|
329
|
+
# A piece's commands and queries, addressed under the piece so two commands
|
|
316
330
|
# of the same name on an aggregate and on one of its entities cannot collide,
|
|
317
331
|
# while `aggregate` still names the aggregate the reference resolves
|
|
318
332
|
# against and `entity_id` says which piece declared it. `entity_id`
|
|
319
|
-
# keeps its own `_id` — an
|
|
320
|
-
# 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
|
|
321
335
|
# mint dropped the suffix; `aggregate` did precisely because
|
|
322
336
|
# `Command#reference_to Aggregate`/`Query#reference_to Aggregate`
|
|
323
337
|
# carry no `as:` of their own).
|
|
@@ -333,26 +347,26 @@ module Hecks
|
|
|
333
347
|
end
|
|
334
348
|
end
|
|
335
349
|
|
|
336
|
-
#
|
|
350
|
+
# An entity may nest further entities — S17, ADR 0026's own words:
|
|
337
351
|
# "That is what `entity` is for, and `entity` is declared by the
|
|
338
352
|
# language and used zero times in it." `Dispatch`, inside
|
|
339
|
-
# `Handler`, is the first real use. The
|
|
353
|
+
# `Handler`, is the first real use. The generic "Entity" category
|
|
340
354
|
# cannot express this through `children_of`/`EAGER_CHILDREN` the
|
|
341
355
|
# way Aggregate's own entities/value_objects can — there is only
|
|
342
|
-
#
|
|
356
|
+
# one "Entity" Plan category, describing what any entity looks
|
|
343
357
|
# like, not one per nesting level — so this recurses by hand,
|
|
344
358
|
# the same special case `within_entity` (above) already is for
|
|
345
359
|
# Command/Query.
|
|
346
360
|
#
|
|
347
361
|
# `owner` is the field this repurposes — `entity.bluebook`
|
|
348
362
|
# declares it (`attribute :owner, EntityText`) and it has held
|
|
349
|
-
# exactly one value since ADR 0025's rename: the
|
|
350
|
-
# `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,
|
|
351
365
|
# never read back anywhere else in this codebase (grep finds no
|
|
352
|
-
# second reference). For a
|
|
353
|
-
# diverge — `aggregate` stays the
|
|
366
|
+
# second reference). For a nested entity, the two finally
|
|
367
|
+
# diverge — `aggregate` stays the root (Dispatch resolves
|
|
354
368
|
# exactly the way any other Entity record does, by its root
|
|
355
|
-
# aggregate), and `owner` becomes
|
|
369
|
+
# aggregate), and `owner` becomes this entity's own direct
|
|
356
370
|
# parent (Handler, not ProcessManager) — which is exactly the
|
|
357
371
|
# fact `Reconstruction#direct_entities` needs to tell a
|
|
358
372
|
# root-level entity apart from a nested one sharing the same
|
|
@@ -367,13 +381,13 @@ module Hecks
|
|
|
367
381
|
})
|
|
368
382
|
end
|
|
369
383
|
|
|
370
|
-
#
|
|
384
|
+
# Where it sits among its siblings is a fact about the walk, not about the
|
|
371
385
|
# node : a command does not know it is the third command on its aggregate.
|
|
372
386
|
# The walk knows, so the walk supplies it, and every other field still
|
|
373
387
|
# comes from the node. Declaration order used to survive only because the
|
|
374
388
|
# meta store happened to iterate in insertion order — an accident that an
|
|
375
389
|
# ask ordered any other way would have taken away, and Reconstruction is
|
|
376
|
-
# the one reader that must have the
|
|
390
|
+
# the one reader that must have the source's order rather than a stable one.
|
|
377
391
|
# `private` above has no effect on a constant; kept here anyway,
|
|
378
392
|
# beside the method that reads it, for the narrative.
|
|
379
393
|
# rubocop:disable-next Lint/UselessConstantScoping
|
|
@@ -416,7 +430,7 @@ module Hecks
|
|
|
416
430
|
plan.appends.each do |list_name, append|
|
|
417
431
|
rows_for(category, list_name, node).each_with_index do |row, index|
|
|
418
432
|
chosen = append_for(category, list_name, append, row, node)
|
|
419
|
-
# `position`
|
|
433
|
+
# `position` is the walk index here exactly as it is in `declare` —
|
|
420
434
|
# an appended element that names its position (ValueObject.Member,
|
|
421
435
|
# S17) is ordered by where the walk found it, never by a field the
|
|
422
436
|
# row happens to hold.
|
|
@@ -436,15 +450,15 @@ module Hecks
|
|
|
436
450
|
end
|
|
437
451
|
end
|
|
438
452
|
|
|
439
|
-
#
|
|
453
|
+
# Which aggregate owns the value objects an attribute's type may
|
|
440
454
|
# resolve against. An aggregate owns its own — `id` already names
|
|
441
455
|
# it. An entity never has value objects of its own (Entity
|
|
442
456
|
# deliberately never answers `value_object` — see entity.rb's own
|
|
443
|
-
# comment on why); its attributes read the
|
|
457
|
+
# comment on why); its attributes read the same pool its
|
|
444
458
|
# enclosing aggregate declares, one level up the construct tree
|
|
445
459
|
# no matter how many entities deep this attribute is nested —
|
|
446
460
|
# `parent_id` names it because `detail_node`/`nest_entities`
|
|
447
|
-
# thread the
|
|
461
|
+
# thread the root aggregate's id down as `parent_id` at every
|
|
448
462
|
# entity level, never the direct (possibly entity) parent.
|
|
449
463
|
def owning_aggregate_ref(category, id, parent_id)
|
|
450
464
|
category == "Entity" ? parent_id : id
|
|
@@ -455,30 +469,30 @@ module Hecks
|
|
|
455
469
|
plan.sealers.each { |verb| send_to("Bluebook::#{verb_for(plan, verb)}", id, to: address(receiver)) }
|
|
456
470
|
end
|
|
457
471
|
|
|
458
|
-
# 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,
|
|
459
473
|
# and the language models that as a reference — so the type is offered as
|
|
460
474
|
# the value object's own id. This is the rule "attributes must use
|
|
461
475
|
# value-object types", enforced by reference resolution rather than by a
|
|
462
|
-
# predicate — for a
|
|
476
|
+
# predicate — for a head's own attributes, aggregate or entity alike: an
|
|
463
477
|
# entity is its own root, repeating the aggregate's whole shape one level
|
|
464
478
|
# down (entity.rb's own words), and an undeclared type on an entity's
|
|
465
479
|
# attribute must fail the same reference resolution an aggregate's own
|
|
466
480
|
# does, not go unchecked because only "Aggregate.attributes" was ever
|
|
467
481
|
# asked.
|
|
468
|
-
# 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
|
|
469
483
|
# language resolves it as a reference and "the type is declared" costs no
|
|
470
484
|
# predicate. Three kinds, three ids: a value object and an entity both hang
|
|
471
485
|
# off this aggregate, so they share its prefix; another aggregate's head
|
|
472
486
|
# hangs off the chapter.
|
|
473
487
|
def cell(category, list_name, row, field, id, append, aggregate_id)
|
|
474
488
|
value = row_value(row, field)
|
|
475
|
-
# A default keeps its
|
|
489
|
+
# A default keeps its type by being written as a literal — 0.0 rather than
|
|
476
490
|
# "0.0" — because the language holds it as text and text alone forgets.
|
|
477
491
|
return encode_literal(value) if field == :default
|
|
478
492
|
return value unless field == :type
|
|
479
|
-
# A
|
|
493
|
+
# A reference names another head wherever it is written — on a head, on
|
|
480
494
|
# a command, on a piece, on an ask — so it is offered as that head's
|
|
481
|
-
# id in all four. Only a
|
|
495
|
+
# id in all four. Only a head's own attributes additionally qualify
|
|
482
496
|
# an ordinary type into a value object's id ; a command argument's
|
|
483
497
|
# type is text and stays text.
|
|
484
498
|
return points_at(row, id) if append.verb == "Reference"
|
|
@@ -487,7 +501,7 @@ module Hecks
|
|
|
487
501
|
Naming.identity([owning_aggregate_id(aggregate_id, value), value])
|
|
488
502
|
end
|
|
489
503
|
|
|
490
|
-
# A
|
|
504
|
+
# A head's own attributes — an aggregate's, or an entity's (its own root,
|
|
491
505
|
# one level down). Every other "attributes" list belongs to something that
|
|
492
506
|
# is not a head at all (a command's arguments, a value object's own
|
|
493
507
|
# fields), and a type written there is a name, not a reference — the same
|
|
@@ -496,27 +510,27 @@ module Hecks
|
|
|
496
510
|
list_name.to_s == "attributes" && %w[Aggregate Entity].include?(category)
|
|
497
511
|
end
|
|
498
512
|
|
|
499
|
-
# `id`
|
|
513
|
+
# `id` names the attribute's own aggregate, not necessarily the
|
|
500
514
|
# value object's — Wave 7's own translation.bluebook/translation_
|
|
501
515
|
# aggregate.bluebook split proved the difference live:
|
|
502
516
|
# TranslationAggregate's own `was`/every rename-rule's own `from`/
|
|
503
|
-
# `to`/... all deliberately reuse the
|
|
517
|
+
# `to`/... all deliberately reuse the sibling "Translation"
|
|
504
518
|
# aggregate's own `TranslationName` (that file's own header:
|
|
505
519
|
# "the shared TranslationName every non-identity field below
|
|
506
520
|
# uses"), a real, intentional cross-aggregate reuse — not the
|
|
507
|
-
# local-only ownership every
|
|
521
|
+
# local-only ownership every other real domain in this corpus
|
|
508
522
|
# happens to have used until now.
|
|
509
523
|
#
|
|
510
524
|
# `id` (already `Naming.identity([chapter, aggregate])`-joined)
|
|
511
|
-
# only ever composes with the
|
|
525
|
+
# only ever composes with the local aggregate for real, non-
|
|
512
526
|
# entity-owned attributes — an entity's own `id` never matches
|
|
513
|
-
# any
|
|
527
|
+
# any top-level aggregate here, so `local` stays nil and this
|
|
514
528
|
# returns `id` unchanged, exactly the prior behavior. Same for
|
|
515
|
-
# every attribute whose type
|
|
529
|
+
# every attribute whose type is locally declared (the overwhelming
|
|
516
530
|
# common case, Banking's own Customer/Account included) — this
|
|
517
|
-
# only ever changes the answer when the local aggregate does
|
|
531
|
+
# only ever changes the answer when the local aggregate does not
|
|
518
532
|
# declare `value` itself, falling back to the first (declaration-
|
|
519
|
-
# order)
|
|
533
|
+
# order) other aggregate in the same chapter that does.
|
|
520
534
|
def owning_aggregate_id(id, value)
|
|
521
535
|
local = @bluebook.aggregates.find { |aggregate| Naming.identity([@bluebook.name, aggregate.name]) == id }
|
|
522
536
|
return id unless local
|
|
@@ -549,13 +563,13 @@ module Hecks
|
|
|
549
563
|
# Reference its type is Reference<X>, another aggregate's head
|
|
550
564
|
# Holds its type names an entity this aggregate declares
|
|
551
565
|
#
|
|
552
|
-
#
|
|
566
|
+
# Nothing is skipped any more. Reference and Holds did not exist, so the
|
|
553
567
|
# walk dropped both kinds and the meta-domain silently did not contain
|
|
554
568
|
# Account#customer_id or Account#ledger.
|
|
555
|
-
# Each alternate carries its
|
|
569
|
+
# Each alternate carries its own map, read from the language. Borrowing the
|
|
556
570
|
# primary's map dispatched `type:` where Reference declares `points_at:`,
|
|
557
571
|
# and the payload gate caught it — which is the gate paying for itself.
|
|
558
|
-
# `reference_to` can be written in
|
|
572
|
+
# `reference_to` can be written in four places — on a head, a command, a
|
|
559
573
|
# piece, an ask — and each keeps its own list of attributes, so each
|
|
560
574
|
# needs the Reference alternate. Only a head can hold a piece, so Holds
|
|
561
575
|
# stays where it was.
|
|
@@ -573,7 +587,7 @@ module Hecks
|
|
|
573
587
|
|
|
574
588
|
def reference_row?(row) = row.respond_to?(:reference?) && row.reference?
|
|
575
589
|
|
|
576
|
-
# Only a
|
|
590
|
+
# Only a head declares pieces, and now that every attribute list reaches
|
|
577
591
|
# this, the node may be a command, a piece or an ask — none of which
|
|
578
592
|
# answer `entities` at all.
|
|
579
593
|
def entity_row?(row, node)
|
|
@@ -582,7 +596,7 @@ module Hecks
|
|
|
582
596
|
Array(node.entities).any? { |entity| entity.hecks_name == row.type.to_s }
|
|
583
597
|
end
|
|
584
598
|
|
|
585
|
-
# A
|
|
599
|
+
# A record's ID is its declared identity, joined — the same join the runtime
|
|
586
600
|
# does, off the same declaration, because there is only one way to name a
|
|
587
601
|
# thing and it should be written once.
|
|
588
602
|
#
|
|
@@ -602,14 +616,14 @@ module Hecks
|
|
|
602
616
|
Naming.identity(plan.identity_paths.map { |path| identity_part(plan, path, parent_id, node, index, category) })
|
|
603
617
|
end
|
|
604
618
|
|
|
605
|
-
# "owner_id" is a
|
|
606
|
-
# 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
|
|
607
621
|
# alike, without saying which — Command and Query read it so an
|
|
608
622
|
# entity's verbs are the entity's own. It is never a declared
|
|
609
623
|
# attribute (declaring one for a field that names two different types
|
|
610
624
|
# would be a lie about which), so it cannot be read through
|
|
611
625
|
# `field_value` ; it is read the same way `plan.parent_key` already is,
|
|
612
|
-
# because it
|
|
626
|
+
# because it is that fact, spelled for the walk's immediate parent
|
|
613
627
|
# rather than for one specific kind of one.
|
|
614
628
|
# `private` above has no effect on a constant; kept here anyway,
|
|
615
629
|
# beside the method that reads it, for the narrative.
|