hecks 0.2.0 → 1.0.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 +5 -5
- data/lib/hecks/adapters/driven/claude_code.adapter +3 -0
- data/lib/hecks/adapters/driven/claude_code.rb +127 -0
- data/lib/hecks/adapters/driven/d1.adapter +12 -0
- data/lib/hecks/adapters/driven/d1.rb +427 -0
- data/lib/hecks/adapters/driven/folder.adapter +3 -0
- data/lib/hecks/adapters/driven/folder.rb +199 -0
- data/lib/hecks/adapters/driven/google_authentication.adapter +3 -0
- data/lib/hecks/adapters/driven/google_authentication.rb +100 -0
- data/lib/hecks/adapters/driven/governance_authorization.adapter +3 -0
- data/lib/hecks/adapters/driven/governance_authorization.rb +101 -0
- data/lib/hecks/adapters/driven/heki/journal.rb +56 -0
- data/lib/hecks/adapters/driven/heki/saga_store.rb +99 -0
- data/lib/hecks/adapters/driven/heki/snapshot.rb +65 -0
- data/lib/hecks/adapters/driven/heki.adapter +4 -0
- data/lib/hecks/adapters/driven/heki.rb +179 -0
- data/lib/hecks/adapters/driven/identity_registry.adapter +3 -0
- data/lib/hecks/adapters/driven/identity_registry.rb +26 -0
- data/lib/hecks/adapters/driven/in_memory_ordering.rb +51 -0
- data/lib/hecks/adapters/driven/lambda/client.rb +63 -0
- data/lib/hecks/adapters/driven/lambda.adapter +4 -0
- data/lib/hecks/adapters/driven/lambda.rb +145 -0
- data/lib/hecks/adapters/driven/memory.adapter +3 -0
- data/lib/hecks/adapters/driven/memory.rb +103 -0
- data/lib/hecks/adapters/driven/mock_stripe_adapter.adapter +3 -0
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +28 -0
- data/lib/hecks/adapters/driven/postgres/codec.rb +88 -0
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +207 -0
- data/lib/hecks/adapters/driven/postgres.adapter +5 -0
- data/lib/hecks/adapters/driven/postgres.rb +438 -0
- data/lib/hecks/adapters/driven/postgres_era.adapter +17 -0
- data/lib/hecks/adapters/driven/prism.adapter +3 -0
- data/lib/hecks/adapters/driven/prism.rb +80 -0
- data/lib/hecks/adapters/driven/secure_random_identity.adapter +3 -0
- data/lib/hecks/adapters/driven/secure_random_identity.rb +14 -0
- data/lib/hecks/adapters/driven/sql_query_builder.rb +221 -0
- data/lib/hecks/adapters/driven/sqlite/codec.rb +80 -0
- data/lib/hecks/adapters/driven/sqlite/projection.rb +172 -0
- data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +192 -0
- data/lib/hecks/adapters/driven/sqlite.adapter +9 -0
- data/lib/hecks/adapters/driven/sqlite.rb +306 -0
- data/lib/hecks/adapters/driven/system_clock.adapter +3 -0
- data/lib/hecks/adapters/driven/system_clock.rb +14 -0
- data/lib/hecks/adapters/driven.rb +54 -0
- data/lib/hecks/adapters.rb +6 -0
- data/lib/hecks/behaviors/dsl.rb +125 -0
- data/lib/hecks/behaviors/expectations.rb +340 -0
- data/lib/hecks/behaviors/ir.rb +31 -0
- data/lib/hecks/behaviors/rspec.rb +42 -0
- data/lib/hecks/behaviors/runner.rb +96 -0
- data/lib/hecks/behaviors.rb +25 -0
- data/lib/hecks/bluebook/aggregate.rb +108 -0
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +134 -0
- data/lib/hecks/bluebook/assembly/build.rb +48 -0
- data/lib/hecks/bluebook/assembly/contract.rb +112 -0
- data/lib/hecks/bluebook/assembly/contracts.rb +438 -0
- data/lib/hecks/bluebook/assembly/marks.rb +228 -0
- data/lib/hecks/bluebook/assembly/specializer.rb +70 -0
- data/lib/hecks/bluebook/assembly.rb +91 -0
- data/lib/hecks/bluebook/attribute.rb +96 -0
- data/lib/hecks/bluebook/behaviour/aggregate.rb +83 -0
- data/lib/hecks/bluebook/behaviour/attribute.rb +27 -0
- data/lib/hecks/bluebook/behaviour/chapter.rb +72 -0
- data/lib/hecks/bluebook/behaviour/command.rb +116 -0
- data/lib/hecks/bluebook/behaviour/domain_port.rb +25 -0
- data/lib/hecks/bluebook/behaviour/entity.rb +59 -0
- data/lib/hecks/bluebook/behaviour/hexagon.rb +50 -0
- data/lib/hecks/bluebook/behaviour/lifecycle.rb +68 -0
- data/lib/hecks/bluebook/behaviour/policy.rb +52 -0
- data/lib/hecks/bluebook/behaviour/process_manager.rb +51 -0
- data/lib/hecks/bluebook/behaviour/query.rb +10 -0
- data/lib/hecks/bluebook/behaviour/read_model.rb +29 -0
- data/lib/hecks/bluebook/behaviour/traits.rb +81 -0
- data/lib/hecks/bluebook/behaviour/value_object.rb +33 -0
- data/lib/hecks/bluebook/chapter.rb +78 -0
- data/lib/hecks/bluebook/command.rb +124 -0
- data/lib/hecks/bluebook/domain_port.rb +102 -0
- data/lib/hecks/bluebook/dsl/adapter_builder.rb +34 -0
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +1018 -0
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +348 -0
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +71 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +1087 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +714 -0
- data/lib/hecks/bluebook/dsl/const_shim.rb +81 -0
- data/lib/hecks/bluebook/dsl/domain_port_builder.rb +79 -0
- data/lib/hecks/bluebook/dsl/entity_builder.rb +430 -0
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +366 -0
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +163 -0
- data/lib/hecks/bluebook/dsl/identity_declaration.rb +191 -0
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +44 -0
- data/lib/hecks/bluebook/dsl/malformed.rb +7 -0
- data/lib/hecks/bluebook/dsl/policy_builder.rb +135 -0
- data/lib/hecks/bluebook/dsl/port_builder.rb +39 -0
- data/lib/hecks/bluebook/dsl/port_operation_builder.rb +142 -0
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +306 -0
- data/lib/hecks/bluebook/dsl/query_builder.rb +113 -0
- data/lib/hecks/bluebook/dsl/read_model_builder.rb +233 -0
- data/lib/hecks/bluebook/dsl/rule_reference.rb +173 -0
- data/lib/hecks/bluebook/dsl/translation_builder.rb +243 -0
- data/lib/hecks/bluebook/dsl/value_object_builder.rb +178 -0
- data/lib/hecks/bluebook/dsl/word_gate.rb +228 -0
- data/lib/hecks/bluebook/dsl/world_builder.rb +117 -0
- data/lib/hecks/bluebook/dsl.rb +45 -0
- data/lib/hecks/bluebook/entity.rb +103 -0
- data/lib/hecks/bluebook/expression/canonical_form.rb +123 -0
- data/lib/hecks/bluebook/expression/evaluator.rb +304 -0
- data/lib/hecks/bluebook/expression/projection.json +218 -0
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +233 -0
- data/lib/hecks/bluebook/expression/resolver.rb +781 -0
- data/lib/hecks/bluebook/expression.rb +13 -0
- data/lib/hecks/bluebook/hexagon.rb +60 -0
- data/lib/hecks/bluebook/lifecycle.rb +42 -0
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +54 -0
- data/lib/hecks/bluebook/meta_validator/judge.rb +621 -0
- data/lib/hecks/bluebook/meta_validator/plan.rb +332 -0
- data/lib/hecks/bluebook/meta_validator/port_judge.rb +51 -0
- data/lib/hecks/bluebook/meta_validator/readings.rb +360 -0
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +351 -0
- data/lib/hecks/bluebook/meta_validator/shapes.rb +266 -0
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +255 -0
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +138 -0
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +78 -0
- data/lib/hecks/bluebook/meta_validator.rb +542 -0
- data/lib/hecks/bluebook/model_check.rb +445 -0
- data/lib/hecks/bluebook/pattern_subset.rb +184 -0
- data/lib/hecks/bluebook/policy.rb +41 -0
- data/lib/hecks/bluebook/process_manager.rb +128 -0
- data/lib/hecks/bluebook/project_discovery.rb +30 -0
- data/lib/hecks/bluebook/project_loader.rb +40 -0
- data/lib/hecks/bluebook/project_register.rb +82 -0
- data/lib/hecks/bluebook/query.rb +61 -0
- data/lib/hecks/bluebook/read_model.rb +109 -0
- data/lib/hecks/bluebook/reference.rb +74 -0
- data/lib/hecks/bluebook/smoke_test.rb +166 -0
- data/lib/hecks/bluebook/synthesizer.rb +95 -0
- data/lib/hecks/bluebook/translation.rb +92 -0
- data/lib/hecks/bluebook/value_object.rb +66 -0
- data/lib/hecks/bluebook.rb +74 -0
- data/lib/hecks/codemod.rb +342 -0
- data/lib/hecks/construct.rb +71 -0
- data/lib/hecks/deploy/bluebook/deploy.bluebook +219 -0
- data/lib/hecks/deploy/bluebook/deploy.hecksagon +4 -0
- data/lib/hecks/deploy/oidc.json +18 -0
- data/lib/hecks/doc/reference.rb +410 -0
- data/lib/hecks/embryonaut_bluebook.rb +75 -0
- data/lib/hecks/facade/cli_door.rb +119 -0
- data/lib/hecks/facade/cli_runner.rb +190 -0
- data/lib/hecks/facade/command_request.rb +105 -0
- data/lib/hecks/facade/handle.rb +173 -0
- data/lib/hecks/facade/json_door.rb +166 -0
- data/lib/hecks/facade/surface/aggregate_door.rb +185 -0
- data/lib/hecks/facade/surface/chapter.rb +107 -0
- data/lib/hecks/facade/surface.rb +48 -0
- data/lib/hecks/facade.rb +44 -0
- data/lib/hecks/forms/app.rb +341 -0
- data/lib/hecks/forms/command_form_renderer.rb +113 -0
- data/lib/hecks/forms/examples/banking_console.bluebook +3 -0
- data/lib/hecks/forms/field_renderer.rb +177 -0
- data/lib/hecks/forms/field_shape.rb +232 -0
- data/lib/hecks/forms/html.rb +84 -0
- data/lib/hecks/forms/index_renderer.rb +35 -0
- data/lib/hecks/forms/page.rb +157 -0
- data/lib/hecks/forms/params.rb +161 -0
- data/lib/hecks/forms/port_argument.rb +46 -0
- data/lib/hecks/forms/query_form_renderer.rb +114 -0
- data/lib/hecks/forms/record_renderer.rb +119 -0
- data/lib/hecks/forms/record_table.rb +68 -0
- data/lib/hecks/forms/reference_options.rb +30 -0
- data/lib/hecks/forms/value_object_shape.rb +46 -0
- data/lib/hecks/forms.rb +54 -0
- data/lib/hecks/fqn.rb +94 -0
- data/lib/hecks/framework/bluebook/compliance.bluebook +1 -0
- data/lib/hecks/framework/bluebook/console_settings.bluebook +489 -0
- data/lib/hecks/framework/bluebook/framework.hecksagon +32 -0
- data/lib/hecks/framework/bluebook/governance.bluebook +145 -0
- data/lib/hecks/framework/bluebook/identity.bluebook +90 -0
- data/lib/hecks/framework/oidc.json +39 -0
- data/lib/hecks/framework.rb +90 -0
- data/lib/hecks/freezer.rb +67 -0
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +527 -0
- data/lib/hecks/fuzzing/invalid_value_generator.rb +86 -0
- data/lib/hecks/fuzzing/isolated_boot.rb +286 -0
- data/lib/hecks/fuzzing/properties.rb +1192 -0
- data/lib/hecks/fuzzing/replay.rb +668 -0
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +93 -0
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +80 -0
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +96 -0
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +250 -0
- data/lib/hecks/fuzzing/sequence_generator.rb +131 -0
- data/lib/hecks/fuzzing/value_generator.rb +200 -0
- data/lib/hecks/fuzzing.rb +12 -0
- data/lib/hecks/grammar/evolve.rb +324 -0
- data/lib/hecks/grammar/expression.bluebook +420 -0
- data/lib/hecks/grammar/expression_operators.json +1648 -0
- data/lib/hecks/grammar/grammar.hecksagon +20 -0
- data/lib/hecks/grammar/oidc.json +69 -0
- data/lib/hecks/grammar/translation.bluebook +203 -0
- data/lib/hecks/grammar.rb +178 -0
- data/lib/hecks/ir.rb +126 -0
- data/lib/hecks/language/adapter.bluebook +116 -0
- data/lib/hecks/language/bluebook/aggregate.bluebook +581 -0
- data/lib/hecks/language/bluebook/attaches/paging.bluebook +76 -0
- data/lib/hecks/language/bluebook/bluebook.bluebook +256 -0
- data/lib/hecks/language/bluebook/bluebook.hecksagon +24 -0
- data/lib/hecks/language/bluebook/command.bluebook +471 -0
- data/lib/hecks/language/bluebook/entity.bluebook +392 -0
- data/lib/hecks/language/bluebook/policy.bluebook +189 -0
- data/lib/hecks/language/bluebook/process_manager.bluebook +381 -0
- data/lib/hecks/language/bluebook/projection.bluebook +267 -0
- data/lib/hecks/language/bluebook/query.bluebook +245 -0
- data/lib/hecks/language/bluebook/shape.bluebook +292 -0
- data/lib/hecks/language/bluebook/syntax.bluebook +448 -0
- data/lib/hecks/language/bluebook/vocabulary.bluebook +379 -0
- data/lib/hecks/language/hecksagon/adapter_binding.bluebook +51 -0
- data/lib/hecks/language/hecksagon/domain_port.bluebook +76 -0
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +131 -0
- data/lib/hecks/language/hecksagon/port_operation.bluebook +102 -0
- data/lib/hecks/language/oidc.json +333 -0
- data/lib/hecks/language/port.bluebook +120 -0
- data/lib/hecks/language/translation/translation.bluebook +110 -0
- data/lib/hecks/language/translation/translation_aggregate.bluebook +267 -0
- data/lib/hecks/language/world/wiring.bluebook +62 -0
- data/lib/hecks/language/world/world.bluebook +84 -0
- data/lib/hecks/literal.rb +125 -0
- data/lib/hecks/naming.rb +174 -0
- data/lib/hecks/ports/access_control.port +9 -0
- data/lib/hecks/ports/access_control.rb +62 -0
- data/lib/hecks/ports/agent/answers.rb +104 -0
- data/lib/hecks/ports/agent.port +8 -0
- data/lib/hecks/ports/agent.rb +167 -0
- data/lib/hecks/ports/authentication.port +6 -0
- data/lib/hecks/ports/authentication.rb +50 -0
- data/lib/hecks/ports/authorization.port +7 -0
- data/lib/hecks/ports/authorization.rb +62 -0
- data/lib/hecks/ports/clock.port +5 -0
- data/lib/hecks/ports/clock.rb +62 -0
- data/lib/hecks/ports/extraction.port +5 -0
- data/lib/hecks/ports/extraction.rb +37 -0
- data/lib/hecks/ports/identity_assignment.port +5 -0
- data/lib/hecks/ports/identity_assignment.rb +45 -0
- data/lib/hecks/ports/identity_generation.port +5 -0
- data/lib/hecks/ports/identity_generation.rb +49 -0
- data/lib/hecks/ports/identity_resolution.port +5 -0
- data/lib/hecks/ports/identity_resolution.rb +40 -0
- data/lib/hecks/ports/loading.port +4 -0
- data/lib/hecks/ports/loading.rb +13 -0
- data/lib/hecks/ports/persistence/append_only.rb +138 -0
- data/lib/hecks/ports/persistence/binding_policy.rb +56 -0
- data/lib/hecks/ports/persistence/execution.rb +23 -0
- data/lib/hecks/ports/persistence/null_saga_store.rb +25 -0
- data/lib/hecks/ports/persistence/plugin.rb +54 -0
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +169 -0
- data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +128 -0
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +161 -0
- data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +61 -0
- data/lib/hecks/ports/persistence/plugins/era/lineage.rb +304 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +171 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +190 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +478 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +166 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +314 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +168 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +170 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +134 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +137 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +89 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +85 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +43 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +132 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +74 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +758 -0
- data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +120 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +31 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +46 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +102 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +46 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +70 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +72 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +120 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +183 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +41 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +28 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +30 -0
- data/lib/hecks/ports/persistence/plugins/era/translation.rb +11 -0
- data/lib/hecks/ports/persistence/plugins/era.rb +48 -0
- data/lib/hecks/ports/persistence/remote_runtime.rb +42 -0
- data/lib/hecks/ports/persistence/repository_factory.rb +30 -0
- data/lib/hecks/ports/persistence.port +4 -0
- data/lib/hecks/ports/persistence.rb +39 -0
- data/lib/hecks/ports/projection.port +4 -0
- data/lib/hecks/ports/projection.rb +96 -0
- data/lib/hecks/ports/query/in_memory.rb +60 -0
- data/lib/hecks/ports/query/ordering.rb +41 -0
- data/lib/hecks/ports/query.rb +36 -0
- data/lib/hecks/ports.rb +27 -0
- data/lib/hecks/projections/diagrams.rb +642 -0
- data/lib/hecks/projections/ir.rb +18 -0
- data/lib/hecks/projections/model/deviations.rb +98 -0
- data/lib/hecks/projections/model.rb +145 -0
- data/lib/hecks/projections/oidc.rb +110 -0
- data/lib/hecks/projections/parser_table.rb +159 -0
- data/lib/hecks/projections/reference.rb +38 -0
- data/lib/hecks/projections/shape.rb +44 -0
- data/lib/hecks/projections/statements.rb +110 -0
- data/lib/hecks/projections/vocabulary.rb +100 -0
- data/lib/hecks/projections.rb +32 -0
- data/lib/hecks/projector/cli_projector.rb +446 -0
- data/lib/hecks/projector/docs_projector.rb +321 -0
- data/lib/hecks/projector/exporter.rb +158 -0
- data/lib/hecks/projector/ir_projector.rb +18 -0
- data/lib/hecks/projector/narrate_projector.rb +243 -0
- data/lib/hecks/projector/target.rb +97 -0
- data/lib/hecks/projector.rb +186 -0
- data/lib/hecks/query_ir.rb +411 -0
- data/lib/hecks/query_specification/common/authorization_spec.rb +9 -0
- data/lib/hecks/query_specification/common/comparators.rb +25 -0
- data/lib/hecks/query_specification/common/comparison.rb +174 -0
- data/lib/hecks/query_specification/common/cursor_spec.rb +9 -0
- data/lib/hecks/query_specification/common/dsl.rb +58 -0
- data/lib/hecks/query_specification/common/inspection_spec.rb +9 -0
- data/lib/hecks/query_specification/common/limit_spec.rb +9 -0
- data/lib/hecks/query_specification/common/null_policy.rb +92 -0
- data/lib/hecks/query_specification/common/null_semantics.rb +11 -0
- data/lib/hecks/query_specification/common/offset_spec.rb +9 -0
- data/lib/hecks/query_specification/common/options.rb +32 -0
- data/lib/hecks/query_specification/common/order_by.rb +9 -0
- data/lib/hecks/query_specification/common/specification.rb +10 -0
- data/lib/hecks/query_specification/common/where_clause.rb +9 -0
- data/lib/hecks/query_specification/field_path.rb +107 -0
- data/lib/hecks/query_specification/hop_path.rb +132 -0
- data/lib/hecks/query_specification/read_model/specification.rb +18 -0
- data/lib/hecks/query_specification.rb +14 -0
- data/lib/hecks/rendering.rb +48 -0
- data/lib/hecks/router/namespace_installer.rb +157 -0
- data/lib/hecks/router.rb +70 -0
- data/lib/hecks/runtime/aggregate_lock.rb +45 -0
- data/lib/hecks/runtime/boot_gates.rb +41 -0
- data/lib/hecks/runtime/caller.rb +66 -0
- data/lib/hecks/runtime/capability_graph.rb +44 -0
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +135 -0
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +260 -0
- data/lib/hecks/runtime/command_interpreter.rb +497 -0
- data/lib/hecks/runtime/command_rules/admissibility.rb +357 -0
- data/lib/hecks/runtime/command_rules/arithmetic.rb +260 -0
- data/lib/hecks/runtime/command_rules/authorization.rb +65 -0
- data/lib/hecks/runtime/command_rules/emission.rb +34 -0
- data/lib/hecks/runtime/command_rules/references.rb +189 -0
- data/lib/hecks/runtime/command_rules.rb +28 -0
- data/lib/hecks/runtime/dependency_planning.rb +245 -0
- data/lib/hecks/runtime/dispatcher.rb +301 -0
- data/lib/hecks/runtime/entity_element.rb +253 -0
- data/lib/hecks/runtime/entity_interpreter.rb +299 -0
- data/lib/hecks/runtime/errors.rb +122 -0
- data/lib/hecks/runtime/event.rb +51 -0
- data/lib/hecks/runtime/identity.rb +156 -0
- data/lib/hecks/runtime/instance.rb +175 -0
- data/lib/hecks/runtime/interpreting.rb +90 -0
- data/lib/hecks/runtime/loader.rb +184 -0
- data/lib/hecks/runtime/policy_interpreter.rb +366 -0
- data/lib/hecks/runtime/port_operation_interpreter.rb +210 -0
- data/lib/hecks/runtime/query_interpreter.rb +286 -0
- data/lib/hecks/runtime/reaction_invocation.rb +253 -0
- data/lib/hecks/runtime/read_model_interpreter.rb +341 -0
- data/lib/hecks/runtime/rebuild_sweep.rb +74 -0
- data/lib/hecks/runtime/reference_hop.rb +99 -0
- data/lib/hecks/runtime/refusal_wording.rb +126 -0
- data/lib/hecks/runtime/registry/saga_persistence.rb +142 -0
- data/lib/hecks/runtime/registry/verification.rb +246 -0
- data/lib/hecks/runtime/registry.rb +279 -0
- data/lib/hecks/runtime/remote_dispatcher.rb +143 -0
- data/lib/hecks/runtime/routing.rb +96 -0
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +97 -0
- data/lib/hecks/runtime/saga_interpreter.rb +503 -0
- data/lib/hecks/runtime/saga_pending_dispatch.rb +45 -0
- data/lib/hecks/runtime/tenant_check.rb +84 -0
- data/lib/hecks/runtime/tenant_scope.rb +55 -0
- data/lib/hecks/runtime/value/admission.rb +130 -0
- data/lib/hecks/runtime/value/coercion.rb +565 -0
- data/lib/hecks/runtime/value/invariant_violation.rb +5 -0
- data/lib/hecks/runtime/value.rb +125 -0
- data/lib/hecks/runtime.rb +107 -0
- data/lib/hecks/storehouse.rb +632 -0
- data/lib/hecks/version.rb +16 -0
- data/lib/hecks/vocabulary.rb +218 -0
- data/lib/hecks.rb +123 -6
- data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +90 -0
- data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +128 -0
- data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +160 -0
- metadata +412 -222
- data/bin/hecks +0 -7
- data/bin/hecks-package +0 -65
- data/bin/hecks_console +0 -12
- data/bin/hecks_serverless +0 -6
- data/lib/cli/build.rb +0 -14
- data/lib/cli/command_runner.rb +0 -28
- data/lib/cli/console.rb +0 -10
- data/lib/cli/generate.rb +0 -37
- data/lib/cli/hecks-cli.rb +0 -27
- data/lib/cli/test.rb +0 -57
- data/lib/console/commands.rb +0 -8
- data/lib/console/hecks-console.rb +0 -1
- data/lib/packager/README.md +0 -0
- data/lib/packager/app_runner.rb +0 -21
- data/lib/packager/args.rb +0 -26
- data/lib/packager/compatibility/fixnum.rb +0 -6
- data/lib/packager/hecks.rb +0 -39
- data/lib/packager/query_runner.rb +0 -21
- data/lib/packager/resources/Dockerfile +0 -11
- data/lib/packager/resources/app_binary +0 -7
- data/lib/packager/resources/bundle_config +0 -3
- data/lib/packager/resources/traveling-ruby-20150715-2.2.2-linux-x86_64.tar.gz +0 -0
- data/lib/packager/resources/traveling-ruby-20150715-2.2.2-osx.tar.gz +0 -0
- data/lib/serverless/Domain +0 -32
- data/lib/serverless/cli.rb +0 -75
- data/lib/serverless/resources/command_name.js +0 -5
- data/lib/serverless/resources/environment.js +0 -7
- data/lib/serverless/resources/handler.js.tt +0 -28
- data/lib/serverless/resources/run_binary.js +0 -22
- data/lib/serverless/resources/serverless.yml +0 -20
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
require_relative "dispatcher"
|
|
2
|
+
require_relative "instance"
|
|
3
|
+
require_relative "event"
|
|
4
|
+
require_relative "errors"
|
|
5
|
+
require_relative "../naming"
|
|
6
|
+
require_relative "../adapters/driven/lambda/client"
|
|
7
|
+
require_relative "../ports/persistence/binding_policy"
|
|
8
|
+
require_relative "../ports/persistence/remote_runtime"
|
|
9
|
+
|
|
10
|
+
module Hecks
|
|
11
|
+
module Runtime
|
|
12
|
+
# THE WRITE-SIDE HALF OF LAMBDA ROUTING — `Runtime::Loader.boot`
|
|
13
|
+
# constructs this INSTEAD OF `Dispatcher` when the booted domain's
|
|
14
|
+
# own `.world` declares Lambda routing (see loader.rb's own
|
|
15
|
+
# `dispatcher_class_for`). Matches `Dispatcher`'s public shape
|
|
16
|
+
# closely enough that everything built ON TOP of a dispatcher —
|
|
17
|
+
# `Handle`, `AggregateDoor`, `Facade::Surface` — needs no changes
|
|
18
|
+
# at all: `Handle#run`'s entire contract is
|
|
19
|
+
# `@dispatcher.dispatch("#{fqn}.#{command}", **identity, **args).instance.state`,
|
|
20
|
+
# and both classes answer that identically.
|
|
21
|
+
#
|
|
22
|
+
# READS DELEGATE, WRITES DON'T. `query`/`reference_query` hand off
|
|
23
|
+
# to a REAL `Dispatcher` built over the SAME registry — since that
|
|
24
|
+
# registry's own repositories are ALREADY Lambda-backed
|
|
25
|
+
# (`Adapters::Lambda`, `persisted_by("Lambda")`, Phase 2's other
|
|
26
|
+
# half), the inherited query machinery (`QueryInterpreter`,
|
|
27
|
+
# `Ports::Query::InMemory.execute`) works completely unchanged, no
|
|
28
|
+
# query logic duplicated here. `dispatch` can't delegate the same
|
|
29
|
+
# way: command validation (givens, constraints) has to actually
|
|
30
|
+
# run in Rust for a Lambda-routed domain, not get pre-checked here
|
|
31
|
+
# against incomplete local state and then merely persisted.
|
|
32
|
+
class RemoteDispatcher
|
|
33
|
+
Result = Struct.new(:verb, :instance, :events, keyword_init: true) do
|
|
34
|
+
def id = instance.id
|
|
35
|
+
def state = instance.to_h
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
attr_reader :registry
|
|
39
|
+
|
|
40
|
+
def initialize(registry, region: "us-east-1")
|
|
41
|
+
@registry = registry
|
|
42
|
+
# `File.basename(registry.root)`, not `bluebooks.keys.first` —
|
|
43
|
+
# matches `Adapters::Lambda`'s own function-name resolution
|
|
44
|
+
# exactly (see its own comment on why: one merged Lambda per
|
|
45
|
+
# deploy, not one per attached chapter, and `root` is the one
|
|
46
|
+
# signal every bluebook in this registry shares regardless of
|
|
47
|
+
# which one attached it) — INCLUDING that same adapter's own
|
|
48
|
+
# `ENV["DOMAIN_NAME"]`-first fix: `root` is always `/var/task`
|
|
49
|
+
# inside a deployed Lambda, giving "task" instead of the real
|
|
50
|
+
# domain name (a real, live AccessDeniedException on
|
|
51
|
+
# "hecks-task" caught this).
|
|
52
|
+
@client = Adapters::Lambda::Client.new(domain: ENV["DOMAIN_NAME"] || File.basename(registry.root), region: region)
|
|
53
|
+
# READ-SIDE DELEGATE ONLY (see class comment) — never dispatched
|
|
54
|
+
# through; a real Dispatcher's own `query`/`reference_query`
|
|
55
|
+
# already resolve generically via `registry.repository(...)`,
|
|
56
|
+
# so building one here reuses that instead of duplicating it.
|
|
57
|
+
@local = Dispatcher.new(registry)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def dispatch(verb, saga_correlation: nil, **args)
|
|
61
|
+
domain, aggregate_name, = Naming.split_verb(verb) ||
|
|
62
|
+
raise(UnknownVerb,
|
|
63
|
+
RefusalWording.render("UnknownVerb", "not_fully_qualified", verb: verb.inspect))
|
|
64
|
+
aggregate = @registry.bluebook(domain)&.aggregate(aggregate_name) ||
|
|
65
|
+
raise(UnknownVerb,
|
|
66
|
+
RefusalWording.render("UnknownVerb", "no_aggregate", domain: domain, aggregate: aggregate_name.inspect))
|
|
67
|
+
|
|
68
|
+
# NOT EVERY AGGREGATE IN A LAMBDA-ROUTED DOMAIN IS ITSELF
|
|
69
|
+
# LAMBDA-BOUND — Member's real name->email rekey carries a
|
|
70
|
+
# `compute` rule (era_check.rb's own `check_compute_rules!`),
|
|
71
|
+
# which can only ever run against Postgres, permanently. Its
|
|
72
|
+
# OWN `.hecksagon` bind stays "Postgres" even when
|
|
73
|
+
# `dispatched_by("Lambda")` is on for everything else — checked
|
|
74
|
+
# here by real CAPABILITY (`Ports::Persistence::RemoteRuntime`,
|
|
75
|
+
# §1), not by comparing the adapter's own name to the string
|
|
76
|
+
# "Lambda" — a bind resolves to whatever adapter CLASS actually
|
|
77
|
+
# backs it, and only a class shaped like "the real interpreter
|
|
78
|
+
# lives behind a call boundary" forwards here; anything else
|
|
79
|
+
# (Postgres, Memory, any future local adapter) falls through to
|
|
80
|
+
# the real local Dispatcher instead of being forwarded to a
|
|
81
|
+
# Lambda that has no way to represent its lineage history at
|
|
82
|
+
# all.
|
|
83
|
+
adapter_name = Ports::Persistence::BindingPolicy.resolve(@registry, domain, aggregate).adapter
|
|
84
|
+
return @local.dispatch(verb, saga_correlation: saga_correlation, **args) unless @registry.adapter_class(adapter_name) <= Ports::Persistence::RemoteRuntime
|
|
85
|
+
|
|
86
|
+
response = @client.dispatch(verb, args)
|
|
87
|
+
|
|
88
|
+
refusal = response.fetch("refusals", []).find { |r| r["verb"] == verb }
|
|
89
|
+
raise RemoteRefusal, "#{verb} refused: #{refusal['error']}" if refusal
|
|
90
|
+
|
|
91
|
+
# THIS STEP'S OWN mutations — `mutations` is one entry per
|
|
92
|
+
# replayed step (rust/host's rehydrate-and-replay design,
|
|
93
|
+
# Phase 1), so `.last` is exactly the step just dispatched.
|
|
94
|
+
# Matched by fully-qualified aggregate name, not just "the
|
|
95
|
+
# first mutation" — a command whose reaction ALSO mutates a
|
|
96
|
+
# different aggregate (a policy, a saga leg) puts more than
|
|
97
|
+
# one mutation in the same step, and the direct effect of
|
|
98
|
+
# THIS verb is the one this dispatch's own caller expects
|
|
99
|
+
# `.instance` to be.
|
|
100
|
+
fqn = "#{domain}::#{aggregate.hecks_name}"
|
|
101
|
+
mutation = response.fetch("mutations", []).last&.find { |m| m["aggregate"] == fqn } ||
|
|
102
|
+
raise(WiringError,
|
|
103
|
+
"#{verb} was accepted but rust/host reported no mutation for #{fqn} — response: #{response.inspect}")
|
|
104
|
+
|
|
105
|
+
instance = Instance.new(aggregate: aggregate, id: mutation["id"],
|
|
106
|
+
state: JSON.parse(JSON.generate(mutation["state"]), symbolize_names: true))
|
|
107
|
+
|
|
108
|
+
Result.new(verb: verb, instance: instance, events: step_events(response))
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def query(verb, **args) = @local.query(verb, **args)
|
|
112
|
+
def reference_query(verb, **args) = @local.reference_query(verb, **args)
|
|
113
|
+
|
|
114
|
+
# THE FULL DOMAIN'S EVENT HISTORY, on every call — `{"read":
|
|
115
|
+
# true}` replays the whole journal (Phase 1's `dispatch::read`),
|
|
116
|
+
# so its own `events` array already IS the complete log, the
|
|
117
|
+
# same thing `@registry.event_log` would answer for a local
|
|
118
|
+
# dispatch. Not cached: `AggregateDoor.events`/`Handle#events`
|
|
119
|
+
# are not called in this codebase's own hot paths today: if that
|
|
120
|
+
# changes, caching belongs here, not in every caller.
|
|
121
|
+
def events
|
|
122
|
+
@client.read.fetch("events", []).map { |e| build_event(e) }
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
private
|
|
126
|
+
|
|
127
|
+
def step_events(response)
|
|
128
|
+
response.fetch("events", []).map { |e| build_event(e) }
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Rust's own event JSON (kernel/cli.rs's `event_to_json`) carries
|
|
132
|
+
# `name`/`aggregate`/`id`/`payload` only — no `occurred_at`
|
|
133
|
+
# (nothing in the kernel tracks wall-clock time; every
|
|
134
|
+
# replay is deterministic and timestamp-free by design). `nil`
|
|
135
|
+
# here, not a synthesized `Time.now` that would silently lie
|
|
136
|
+
# about when something actually happened.
|
|
137
|
+
def build_event(json)
|
|
138
|
+
Event.new(name: json["name"], aggregate: json["aggregate"], id: json["id"],
|
|
139
|
+
payload: JSON.parse(JSON.generate(json["payload"]), symbolize_names: true), occurred_at: nil)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
require_relative "errors"
|
|
2
|
+
require_relative "refusal_wording"
|
|
3
|
+
|
|
4
|
+
module Hecks
|
|
5
|
+
module Runtime
|
|
6
|
+
# The invocation address is not part of a command's domain payload.
|
|
7
|
+
# Aggregate commands carry one receiver identity; entity commands carry
|
|
8
|
+
# the aggregate receiver followed by one identity for every entity hop.
|
|
9
|
+
module Routing
|
|
10
|
+
Envelope = Struct.new(:aggregate, :entities, keyword_init: true) do
|
|
11
|
+
def initialize(aggregate:, entities: [])
|
|
12
|
+
super(aggregate: aggregate.to_s, entities: Array(entities).map(&:to_s).freeze)
|
|
13
|
+
freeze
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
module_function
|
|
18
|
+
|
|
19
|
+
def envelope(to, entity_depth: 0)
|
|
20
|
+
return nil if to.nil?
|
|
21
|
+
|
|
22
|
+
aggregate, entities = if to.is_a?(Hash)
|
|
23
|
+
hash = to.transform_keys(&:to_sym)
|
|
24
|
+
unknown = hash.keys - %i[aggregate entity entities]
|
|
25
|
+
unless unknown.empty?
|
|
26
|
+
raise TypeMismatch, "to: does not recognize #{unknown.sort.join(', ')}"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
[hash[:aggregate], entity_identities(hash)]
|
|
30
|
+
else
|
|
31
|
+
[to, []]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
if aggregate.nil? || aggregate.to_s.empty?
|
|
35
|
+
raise TypeMismatch, "to: must name the receiving aggregate identity"
|
|
36
|
+
end
|
|
37
|
+
if entities.size != entity_depth
|
|
38
|
+
raise TypeMismatch,
|
|
39
|
+
"to: for an entity command needs #{entity_depth} entity " \
|
|
40
|
+
"#{entity_depth == 1 ? 'identity' : 'identities'} after the aggregate — got #{entities.size}"
|
|
41
|
+
end
|
|
42
|
+
if entities.any? { |identity| identity.nil? || identity.to_s.empty? }
|
|
43
|
+
raise TypeMismatch, "to: contains a blank entity identity"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
Envelope.new(aggregate: aggregate, entities: entities)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# `with:` is deliberately strict. Compatibility-only calls still pass
|
|
50
|
+
# loose keyword arguments through the old addressing gate, but a caller
|
|
51
|
+
# choosing the explicit envelope cannot smuggle receiver identity back
|
|
52
|
+
# into the payload.
|
|
53
|
+
def payload(command, with:, legacy:)
|
|
54
|
+
if with && !legacy.empty?
|
|
55
|
+
raise TypeMismatch, "dispatch takes command facts in with:, not both with: and loose keyword arguments"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
return legacy unless with
|
|
59
|
+
unless with.is_a?(Hash)
|
|
60
|
+
raise TypeMismatch, "with: must be a hash of command facts"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
offered = with.transform_keys(&:to_sym)
|
|
64
|
+
declared = command.attributes.map { |attribute| attribute.name.to_sym }
|
|
65
|
+
unknown = (offered.keys - declared).sort
|
|
66
|
+
unless unknown.empty?
|
|
67
|
+
reading = declared.empty? ? "none" : declared.join(", ")
|
|
68
|
+
raise UnknownArgument,
|
|
69
|
+
RefusalWording.render("UnknownArgument", "unknown_args",
|
|
70
|
+
command: command.hecks_name, unknown: unknown.join(", "),
|
|
71
|
+
declared: reading)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
absent = command.attributes.reject(&:optional?).map { |attribute| attribute.name.to_sym } - offered.keys
|
|
75
|
+
unless absent.empty?
|
|
76
|
+
reading = declared.empty? ? "none" : declared.join(", ")
|
|
77
|
+
raise AbsentArgument,
|
|
78
|
+
RefusalWording.render("AbsentArgument", "absent_args",
|
|
79
|
+
command: command.hecks_name, absent: absent.sort.join(", "),
|
|
80
|
+
declared: reading)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
offered
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def entity_identities(hash)
|
|
87
|
+
if hash.key?(:entities) && hash.key?(:entity)
|
|
88
|
+
raise TypeMismatch, "to: takes entity: or entities:, not both"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
hash.key?(:entities) ? Array(hash[:entities]) : Array(hash[:entity])
|
|
92
|
+
end
|
|
93
|
+
private_class_method :entity_identities
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
require_relative "../value"
|
|
2
|
+
|
|
3
|
+
module Hecks
|
|
4
|
+
module Runtime
|
|
5
|
+
class SagaInterpreter
|
|
6
|
+
# How a saga decides WHICH CONVERSATION an event belongs to — three
|
|
7
|
+
# tiers, each one a lesson.
|
|
8
|
+
module Correlation
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
# A DOTTED PATH NAMES THE SCALAR FIELD, rather than asking a value object
|
|
12
|
+
# to stand in for one. `correlates_by :end_to_end` would key a saga on
|
|
13
|
+
# the whole ExternalTransfer::EndToEndReference — and what a non-scalar
|
|
14
|
+
# correlation key even IS is representation-dependent (the object
|
|
15
|
+
# itself? its serialised text?). `:"end_to_end.value"` reads the one
|
|
16
|
+
# field with a single unambiguous rendering.
|
|
17
|
+
def saga_correlation(pm, event)
|
|
18
|
+
path = pm.correlates_by.to_s.split(".")
|
|
19
|
+
# A LATER EVENT MAY ALREADY HOLD THE SCALAR. `reference.value` digs a
|
|
20
|
+
# value object's field out of a FRESH declaration (TransferRequested's
|
|
21
|
+
# `reference` IS a TransferReference) — but a downstream event this
|
|
22
|
+
# same value was smuggled through as a passthrough argument
|
|
23
|
+
# (AccountDebited's `reference:`, resolved by `dispatch_args` to the
|
|
24
|
+
# bare correlation string) carries it as a scalar already, with
|
|
25
|
+
# nothing left to dig. `"xfer-1".respond_to?(:[])` is true — String
|
|
26
|
+
# has its OWN `[]` (substring indexing) — so checking for keyed
|
|
27
|
+
# lookup explicitly, rather than "responds to `[]` at all", is what
|
|
28
|
+
# stops the second segment from being read as a symbol index into a
|
|
29
|
+
# string that has already arrived.
|
|
30
|
+
value = path.reduce(event.payload) do |held, segment|
|
|
31
|
+
held.is_a?(Hash) || held.is_a?(Value) ? held[segment.to_sym] : held
|
|
32
|
+
end
|
|
33
|
+
return value unless value.to_s.empty?
|
|
34
|
+
|
|
35
|
+
# THE STAMP — `deliver_saga_dispatch` marks its own event before this
|
|
36
|
+
# saga's next step ever asks, for a leg whose command declares
|
|
37
|
+
# NEITHER the correlation field itself nor the emitting aggregate's
|
|
38
|
+
# own reference key (the two tiers above). command_interpreter/
|
|
39
|
+
# argument_gate.rb names the old payload-only lookup "the weakest
|
|
40
|
+
# part of the gate" : a correlation key arriving on a command only
|
|
41
|
+
# because `correlation_keys` widens the undeclared-argument
|
|
42
|
+
# allow-list domain-wide. This is the additive fix — a leg that
|
|
43
|
+
# carries nothing correlation-shaped at all still correlates,
|
|
44
|
+
# because the saga that dispatched it already knows the answer.
|
|
45
|
+
# Keyed by `correlation_head`
|
|
46
|
+
# rather than a bare scalar so an event stamped by one saga cannot be
|
|
47
|
+
# misread by an unrelated one correlating on a different field.
|
|
48
|
+
stamped = event.correlation && event.correlation[pm.correlation_head.to_s]
|
|
49
|
+
return stamped unless stamped.nil? || stamped.to_s.empty?
|
|
50
|
+
|
|
51
|
+
# A SELF-REFERENCING LEG carries the correlation forward under its
|
|
52
|
+
# own emitting record's identity — `event.id`, not a field dug back
|
|
53
|
+
# out of the payload. This used to read `event.payload[own_key]`
|
|
54
|
+
# (`own_key` the aggregate's own reference-key convention, "wire",
|
|
55
|
+
# "transfer"), which only ever held a value because LEGACY dispatch
|
|
56
|
+
# left the self-addressing key riding along in the payload
|
|
57
|
+
# unfiltered. Routing separated from payload (`to:`/`with:`, the
|
|
58
|
+
# facade's own `Handle#run` always uses it) closed exactly that
|
|
59
|
+
# leak — correctly, since an addressing key is not a fact the
|
|
60
|
+
# payload should carry — which left this tier reading an empty
|
|
61
|
+
# Hash for any self-referencing leg with no OTHER declared
|
|
62
|
+
# attributes (`OnboardingCase.Clear`, `.Decline` — no `attribute`
|
|
63
|
+
# lines at all): the saga silently stopped advancing, forever, for
|
|
64
|
+
# exactly the leg this tier exists to correlate.
|
|
65
|
+
#
|
|
66
|
+
# `event.id` says the identical thing this tier always meant —
|
|
67
|
+
# "the record that just emitted this event, by its own identity" —
|
|
68
|
+
# and unlike a payload dig it is populated by the record itself,
|
|
69
|
+
# not by which dispatch convention the caller happened to use.
|
|
70
|
+
#
|
|
71
|
+
# GATED, still — a manually-dispatched command on a wholly
|
|
72
|
+
# UNRELATED aggregate can share an event NAME this pm happens to
|
|
73
|
+
# handle (`Drawer.Take` also emits "Taken", the same name a
|
|
74
|
+
# SAGA-DISPATCHED leg uses) with nothing this saga should read as
|
|
75
|
+
# its own conversation. What makes a leg genuinely
|
|
76
|
+
# self-referencing — the one fact worth trusting `event.id`
|
|
77
|
+
# for — is that `correlates_by`'s own head field IS this event's
|
|
78
|
+
# OWN aggregate's declared identity, not merely a same-shaped
|
|
79
|
+
# name: `OnboardingCase.identity_heads` really does include
|
|
80
|
+
# `:reference`, `correlates_by :"reference.value"`'s own head ;
|
|
81
|
+
# `Drawer.identity_heads` is `[:number]`, nowhere close.
|
|
82
|
+
self_identified?(pm, event) ? event.id : nil
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def self_identified?(pm, event)
|
|
86
|
+
domain, bare_name = event.aggregate.to_s.split("::", 2)
|
|
87
|
+
return false unless bare_name
|
|
88
|
+
|
|
89
|
+
construct = @registry.bluebook(domain)&.aggregate(bare_name)
|
|
90
|
+
return false unless construct
|
|
91
|
+
|
|
92
|
+
construct.identity_heads.map(&:to_s).include?(pm.correlation_head.to_s)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|