hecks 2.7.0 → 2.9.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/exe/hecks +11 -0
- data/lib/hecks/adapters/driven/claude_code.rb +4 -104
- data/lib/hecks/adapters/driven/d1.rb +44 -237
- data/lib/hecks/adapters/driven/folder.rb +17 -76
- data/lib/hecks/adapters/driven/google_authentication.rb +15 -49
- data/lib/hecks/adapters/driven/governance_authorization.rb +23 -70
- data/lib/hecks/adapters/driven/heki/journal.rb +8 -41
- data/lib/hecks/adapters/driven/heki/saga_store.rb +12 -54
- data/lib/hecks/adapters/driven/heki/snapshot.rb +4 -12
- data/lib/hecks/adapters/driven/heki.rb +13 -42
- data/lib/hecks/adapters/driven/identity_registry.rb +3 -14
- data/lib/hecks/adapters/driven/in_memory_ordering.rb +9 -26
- data/lib/hecks/adapters/driven/in_process_key_vault.rb +2 -14
- data/lib/hecks/adapters/driven/lambda/client.rb +10 -51
- data/lib/hecks/adapters/driven/lambda.rb +10 -84
- data/lib/hecks/adapters/driven/local_storage.rb +5 -40
- data/lib/hecks/adapters/driven/memory.rb +18 -99
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +5 -21
- data/lib/hecks/adapters/driven/postgres/codec.rb +6 -28
- data/lib/hecks/adapters/driven/postgres/outbox.rb +3 -12
- data/lib/hecks/adapters/driven/postgres/reconnect.rb +4 -30
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +34 -108
- data/lib/hecks/adapters/driven/postgres.rb +145 -134
- data/lib/hecks/adapters/driven/postgres_era.adapter +4 -15
- data/lib/hecks/adapters/driven/prism.rb +7 -30
- data/lib/hecks/adapters/driven/sql_query_builder.rb +21 -121
- data/lib/hecks/adapters/driven/sqlite/codec.rb +8 -40
- data/lib/hecks/adapters/driven/sqlite/projection.rb +26 -82
- data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +40 -84
- data/lib/hecks/adapters/driven/sqlite.rb +128 -65
- data/lib/hecks/adapters/driven/tenant_provisioner.rb +15 -37
- data/lib/hecks/adapters/driven.rb +5 -36
- data/lib/hecks/adapters/driving/github_webhook.rb +8 -76
- data/lib/hecks/behaviors/dsl.rb +7 -25
- data/lib/hecks/behaviors/expectations.rb +32 -142
- data/lib/hecks/behaviors/ir.rb +7 -20
- data/lib/hecks/behaviors/rspec.rb +6 -17
- data/lib/hecks/behaviors/runner.rb +10 -34
- data/lib/hecks/behaviors.rb +4 -8
- data/lib/hecks/bluebook/aggregate.rb +9 -75
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +9 -38
- data/lib/hecks/bluebook/assembly/build.rb +4 -15
- data/lib/hecks/bluebook/assembly/contract.rb +15 -136
- data/lib/hecks/bluebook/assembly/contracts.rb +54 -174
- data/lib/hecks/bluebook/assembly/marks.rb +31 -223
- data/lib/hecks/bluebook/assembly/specializer.rb +6 -52
- data/lib/hecks/bluebook/assembly.rb +6 -45
- data/lib/hecks/bluebook/attribute.rb +12 -61
- data/lib/hecks/bluebook/behaviour/aggregate.rb +10 -39
- data/lib/hecks/bluebook/behaviour/attribute.rb +3 -14
- data/lib/hecks/bluebook/behaviour/chapter.rb +17 -42
- data/lib/hecks/bluebook/behaviour/command.rb +14 -66
- data/lib/hecks/bluebook/behaviour/domain_port.rb +4 -20
- data/lib/hecks/bluebook/behaviour/entity.rb +7 -27
- data/lib/hecks/bluebook/behaviour/hexagon.rb +23 -41
- data/lib/hecks/bluebook/behaviour/lifecycle.rb +15 -40
- data/lib/hecks/bluebook/behaviour/policy.rb +23 -52
- data/lib/hecks/bluebook/behaviour/process_manager.rb +30 -57
- data/lib/hecks/bluebook/behaviour/read_model.rb +38 -26
- data/lib/hecks/bluebook/behaviour/traits.rb +27 -64
- data/lib/hecks/bluebook/behaviour/value_object.rb +5 -24
- data/lib/hecks/bluebook/capabilities.rb +17 -49
- data/lib/hecks/bluebook/chapter.rb +10 -48
- data/lib/hecks/bluebook/command.rb +23 -81
- data/lib/hecks/bluebook/domain_port.rb +14 -63
- data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +50 -229
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +50 -377
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +33 -204
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +17 -65
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +86 -708
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +56 -170
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +1 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +74 -546
- data/lib/hecks/bluebook/dsl/const_shim.rb +8 -41
- data/lib/hecks/bluebook/dsl/domain_port_builder.rb +12 -87
- data/lib/hecks/bluebook/dsl/entity_builder.rb +44 -330
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +20 -269
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +26 -189
- data/lib/hecks/bluebook/dsl/identity_declaration.rb +13 -88
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +6 -20
- data/lib/hecks/bluebook/dsl/policy_builder.rb +16 -88
- data/lib/hecks/bluebook/dsl/port_builder.rb +2 -6
- data/lib/hecks/bluebook/dsl/port_operation_builder.rb +22 -96
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +31 -184
- data/lib/hecks/bluebook/dsl/query_builder.rb +11 -42
- data/lib/hecks/bluebook/dsl/read_model_builder.rb +75 -201
- data/lib/hecks/bluebook/dsl/rule_reference.rb +22 -163
- data/lib/hecks/bluebook/dsl/translation_builder.rb +28 -114
- data/lib/hecks/bluebook/dsl/value_object_builder.rb +10 -124
- data/lib/hecks/bluebook/dsl/word_gate.rb +16 -162
- data/lib/hecks/bluebook/dsl/world_builder.rb +19 -106
- data/lib/hecks/bluebook/entity.rb +13 -71
- data/lib/hecks/bluebook/expression/ast_json.rb +24 -190
- data/lib/hecks/bluebook/expression/ast_reader.rb +12 -54
- data/lib/hecks/bluebook/expression/canonical_form.rb +11 -88
- data/lib/hecks/bluebook/expression/evaluator.rb +47 -295
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +30 -147
- data/lib/hecks/bluebook/expression/resolver.rb +37 -660
- data/lib/hecks/bluebook/hexagon.rb +5 -28
- data/lib/hecks/bluebook/lifecycle.rb +5 -16
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -7
- data/lib/hecks/bluebook/meta_validator/judge.rb +111 -361
- data/lib/hecks/bluebook/meta_validator/plan.rb +33 -162
- data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -7
- data/lib/hecks/bluebook/meta_validator/readings.rb +56 -342
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +24 -176
- data/lib/hecks/bluebook/meta_validator/shapes.rb +54 -268
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +47 -308
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +7 -43
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -18
- data/lib/hecks/bluebook/meta_validator.rb +79 -349
- data/lib/hecks/bluebook/model_check/client_profile.rb +10 -91
- data/lib/hecks/bluebook/model_check.rb +102 -600
- data/lib/hecks/bluebook/pattern_subset.rb +11 -69
- data/lib/hecks/bluebook/process_manager.rb +13 -83
- data/lib/hecks/bluebook/project_loader.rb +3 -39
- data/lib/hecks/bluebook/project_register.rb +12 -60
- data/lib/hecks/bluebook/query.rb +9 -48
- data/lib/hecks/bluebook/read_model.rb +57 -81
- data/lib/hecks/bluebook/reference.rb +7 -41
- data/lib/hecks/bluebook/smoke_test.rb +8 -98
- data/lib/hecks/bluebook/synthesizer.rb +13 -62
- data/lib/hecks/bluebook/translation.rb +26 -62
- data/lib/hecks/bluebook/value_object.rb +11 -36
- data/lib/hecks/bluebook.rb +5 -22
- data/lib/hecks/cache_dir.rb +84 -0
- data/lib/hecks/cli/document.rb +86 -0
- data/lib/hecks/cli/ir.rb +45 -0
- data/lib/hecks/cli/mcp.rb +31 -0
- data/lib/hecks/cli/mcp_door.rb +366 -0
- data/lib/hecks/cli/model_check.rb +203 -0
- data/lib/hecks/cli/project_cli.rb +90 -0
- data/lib/hecks/cli/project_diagrams.rb +36 -0
- data/lib/hecks/cli/run.rb +173 -0
- data/lib/hecks/cli/smoke_test.rb +45 -0
- data/lib/hecks/cli/stores.rb +53 -0
- data/lib/hecks/cli.rb +160 -0
- data/lib/hecks/construct.rb +8 -34
- data/lib/hecks/deploy/bluebook/deploy.bluebook +33 -142
- data/lib/hecks/deploy/bluebook/deploy.hecksagon +2 -9
- data/lib/hecks/embryonaut_bluebook/lock.rb +3 -35
- data/lib/hecks/embryonaut_bluebook/shape.rb +1 -17
- data/lib/hecks/embryonaut_bluebook/vendor.rb +8 -53
- data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +4 -19
- data/lib/hecks/embryonaut_bluebook.rb +4 -71
- data/lib/hecks/facade/cli_door.rb +24 -106
- data/lib/hecks/facade/cli_runner.rb +28 -172
- data/lib/hecks/facade/command_request.rb +13 -33
- data/lib/hecks/facade/handle.rb +34 -121
- data/lib/hecks/facade/json_door.rb +31 -146
- data/lib/hecks/facade/surface/aggregate_door.rb +39 -104
- data/lib/hecks/facade/surface/chapter.rb +10 -54
- data/lib/hecks/facade/surface.rb +8 -23
- data/lib/hecks/facade.rb +10 -25
- data/lib/hecks/forms/app.rb +15 -70
- data/lib/hecks/forms/command_form_renderer.rb +10 -29
- data/lib/hecks/forms/field_renderer.rb +17 -156
- data/lib/hecks/forms/field_shape.rb +30 -222
- data/lib/hecks/forms/html.rb +12 -47
- data/lib/hecks/forms/index_renderer.rb +1 -4
- data/lib/hecks/forms/page.rb +3 -9
- data/lib/hecks/forms/params.rb +14 -60
- data/lib/hecks/forms/port_argument.rb +2 -19
- data/lib/hecks/forms/query_form_renderer.rb +4 -79
- data/lib/hecks/forms/record_renderer.rb +8 -75
- data/lib/hecks/forms/record_table.rb +7 -50
- data/lib/hecks/forms/reference_options.rb +3 -30
- data/lib/hecks/forms/value_object_shape.rb +8 -35
- data/lib/hecks/forms.rb +5 -33
- data/lib/hecks/fqn.rb +5 -12
- data/lib/hecks/framework/bluebook/compliance.bluebook +16 -65
- data/lib/hecks/framework/bluebook/console_settings.bluebook +47 -134
- data/lib/hecks/framework/bluebook/framework.hecksagon +5 -14
- data/lib/hecks/framework/bluebook/governance.bluebook +13 -34
- data/lib/hecks/framework/bluebook/identity.bluebook +11 -26
- data/lib/hecks/framework/bluebook/privacy.bluebook +8 -33
- data/lib/hecks/framework.rb +11 -80
- data/lib/hecks/freezer.rb +5 -39
- data/lib/hecks/grammar/expression.bluebook +15 -40
- data/lib/hecks/grammar/translation.bluebook +3 -6
- data/lib/hecks/grammar.rb +16 -41
- data/lib/hecks/ir.rb +14 -83
- data/lib/hecks/language/adapter.bluebook +2 -7
- data/lib/hecks/language/bluebook/aggregate.bluebook +56 -221
- data/lib/hecks/language/bluebook/attaches/paging.bluebook +6 -15
- data/lib/hecks/language/bluebook/bluebook.bluebook +15 -83
- data/lib/hecks/language/bluebook/bluebook.hecksagon +3 -15
- data/lib/hecks/language/bluebook/command.bluebook +27 -144
- data/lib/hecks/language/bluebook/entity.bluebook +24 -97
- data/lib/hecks/language/bluebook/policy.bluebook +16 -67
- data/lib/hecks/language/bluebook/process_manager.bluebook +28 -151
- data/lib/hecks/language/bluebook/projection.bluebook +126 -60
- data/lib/hecks/language/bluebook/query.bluebook +12 -43
- data/lib/hecks/language/bluebook/shape.bluebook +23 -73
- data/lib/hecks/language/bluebook/syntax.bluebook +51 -262
- data/lib/hecks/language/bluebook/vocabulary.bluebook +98 -197
- data/lib/hecks/language/hecksagon/adapter_binding.bluebook +3 -10
- data/lib/hecks/language/hecksagon/domain_port.bluebook +4 -19
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +6 -25
- data/lib/hecks/language/hecksagon/port_operation.bluebook +3 -14
- data/lib/hecks/language/oidc.json +35 -0
- data/lib/hecks/language/port.bluebook +4 -17
- data/lib/hecks/language/translation/translation.bluebook +3 -9
- data/lib/hecks/language/translation/translation_aggregate.bluebook +5 -24
- data/lib/hecks/language/world/wiring.bluebook +1 -3
- data/lib/hecks/language/world/world.bluebook +5 -7
- data/lib/hecks/literal.rb +8 -50
- data/lib/hecks/mcp_door_scope.rb +95 -0
- data/lib/hecks/mcp_stdio_guard.rb +4 -41
- data/lib/hecks/naming.rb +29 -137
- data/lib/hecks/ports/access_control.rb +7 -23
- data/lib/hecks/ports/agent/answers.rb +5 -23
- data/lib/hecks/ports/agent.rb +47 -172
- data/lib/hecks/ports/authentication.rb +12 -39
- data/lib/hecks/ports/authorization.rb +16 -43
- data/lib/hecks/ports/clock.rb +5 -45
- data/lib/hecks/ports/extraction.rb +7 -12
- data/lib/hecks/ports/identity_assignment.rb +8 -29
- data/lib/hecks/ports/identity_generation.rb +6 -29
- data/lib/hecks/ports/identity_resolution.rb +2 -10
- data/lib/hecks/ports/key_vault.rb +9 -45
- data/lib/hecks/ports/persistence/append_only.rb +62 -65
- data/lib/hecks/ports/persistence/binding_policy.rb +4 -14
- data/lib/hecks/ports/persistence/codec_boundary.rb +20 -80
- data/lib/hecks/ports/persistence/null_saga_store.rb +4 -20
- data/lib/hecks/ports/persistence/plugin.rb +13 -42
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +38 -141
- data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +15 -115
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +16 -84
- data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +7 -26
- data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +3 -22
- data/lib/hecks/ports/persistence/plugins/era/lineage.rb +55 -181
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/events.rb +77 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +12 -122
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +28 -128
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +73 -474
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +31 -124
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +45 -219
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +13 -108
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +18 -75
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +9 -49
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +6 -123
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +23 -55
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +14 -72
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +7 -16
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +14 -115
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +13 -45
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +127 -554
- data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +13 -63
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +2 -17
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +3 -14
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +13 -58
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -17
- data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +9 -26
- data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +9 -25
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +22 -122
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +34 -123
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +5 -12
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +3 -9
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -14
- data/lib/hecks/ports/persistence/plugins/era.rb +4 -23
- data/lib/hecks/ports/persistence/postgres_dump/connection.rb +7 -23
- data/lib/hecks/ports/persistence/postgres_dump.rb +4 -35
- data/lib/hecks/ports/persistence/remote_runtime.rb +2 -24
- data/lib/hecks/ports/persistence/repository_factory.rb +8 -27
- data/lib/hecks/ports/persistence/state_codec.rb +23 -103
- data/lib/hecks/ports/persistence.rb +7 -14
- data/lib/hecks/ports/projection.rb +42 -84
- data/lib/hecks/ports/query/in_memory.rb +10 -58
- data/lib/hecks/ports/query/ordering.rb +11 -32
- data/lib/hecks/ports/query.rb +14 -37
- data/lib/hecks/ports.rb +2 -8
- data/lib/hecks/projections/bootstrap_table.rb +11 -43
- data/lib/hecks/projections/deploy/fargate/assembly.rb +2 -15
- data/lib/hecks/projections/deploy/fargate/cdn.rb +1 -48
- data/lib/hecks/projections/deploy/fargate/cdn_default.rb +2 -11
- data/lib/hecks/projections/deploy/fargate/check.rb +5 -14
- data/lib/hecks/projections/deploy/fargate/containers.rb +3 -78
- data/lib/hecks/projections/deploy/fargate/extras.rb +3 -44
- data/lib/hecks/projections/deploy/fargate/monitoring.rb +0 -44
- data/lib/hecks/projections/deploy/fargate/settings.rb +2 -54
- data/lib/hecks/projections/deploy/fargate/yaml.rb +13 -58
- data/lib/hecks/projections/deploy/fargate.rb +35 -202
- data/lib/hecks/projections/deploy/lambda.rb +151 -679
- data/lib/hecks/projections/deploy/preview/access_yaml.rb +1 -33
- data/lib/hecks/projections/deploy/preview/containers.rb +6 -111
- data/lib/hecks/projections/deploy/preview/routing_yaml.rb +4 -56
- data/lib/hecks/projections/deploy/preview/script.rb +2 -14
- data/lib/hecks/projections/deploy/preview/settings.rb +3 -33
- data/lib/hecks/projections/deploy/preview/task_yaml.rb +2 -38
- data/lib/hecks/projections/deploy/preview/template.rb +2 -58
- data/lib/hecks/projections/deploy/preview.rb +2 -67
- data/lib/hecks/projections/deploy/scripts/settings.rb +3 -25
- data/lib/hecks/projections/deploy/scripts.rb +4 -57
- data/lib/hecks/projections/deploy/shared.rb +47 -146
- data/lib/hecks/projections/deploy/smoke.rb +4 -61
- data/lib/hecks/projections/deploy/template_diff/comparer.rb +3 -25
- data/lib/hecks/projections/deploy/template_diff/loader.rb +2 -11
- data/lib/hecks/projections/deploy/template_diff.rb +5 -57
- data/lib/hecks/projections/diagrams.rb +20 -582
- data/lib/hecks/projections/glossary/html.rb +14 -130
- data/lib/hecks/projections/glossary/markdown.rb +8 -69
- data/lib/hecks/projections/glossary/mermaid.rb +9 -66
- data/lib/hecks/projections/glossary/sensitivity.rb +5 -34
- data/lib/hecks/projections/glossary/sentences.rb +14 -159
- data/lib/hecks/projections/glossary.rb +30 -222
- data/lib/hecks/projections/ir.rb +3 -10
- data/lib/hecks/projections/model/deviations.rb +15 -42
- data/lib/hecks/projections/model.rb +12 -51
- data/lib/hecks/projections/oidc.rb +12 -56
- data/lib/hecks/projections/parser_table.rb +9 -28
- data/lib/hecks/projections/reference.rb +9 -16
- data/lib/hecks/projections/rust_vocabulary.rb +12 -250
- data/lib/hecks/projections/shape.rb +3 -29
- data/lib/hecks/projections/statements.rb +7 -86
- data/lib/hecks/projections/vocabulary.rb +6 -22
- data/lib/hecks/projections.rb +2 -16
- data/lib/hecks/projector/cli_projector.rb +60 -375
- data/lib/hecks/projector/docs_projector.rb +10 -201
- data/lib/hecks/projector/exporter.rb +46 -138
- data/lib/hecks/projector/ir_projector.rb +2 -9
- data/lib/hecks/projector/narrate_projector.rb +15 -189
- data/lib/hecks/projector/target.rb +13 -76
- data/lib/hecks/projector.rb +30 -121
- data/lib/hecks/query_specification/common/comparators.rb +5 -26
- data/lib/hecks/query_specification/common/comparison.rb +35 -143
- data/lib/hecks/query_specification/common/dsl.rb +8 -24
- data/lib/hecks/query_specification/common/null_policy.rb +20 -70
- data/lib/hecks/query_specification/common/options.rb +2 -6
- data/lib/hecks/query_specification/common/where_clause.rb +2 -10
- data/lib/hecks/query_specification/field_path.rb +37 -77
- data/lib/hecks/query_specification/hop_path.rb +12 -76
- data/lib/hecks/release/gem_pin.rb +2 -26
- data/lib/hecks/release/runner/ci_publisher.rb +93 -0
- data/lib/hecks/release/runner/commands.rb +66 -0
- data/lib/hecks/release/runner/console.rb +52 -0
- data/lib/hecks/release/runner/gem_publisher.rb +43 -0
- data/lib/hecks/release/runner/git.rb +48 -0
- data/lib/hecks/release/runner/npm_publisher.rb +75 -0
- data/lib/hecks/release/runner/preflight.rb +104 -0
- data/lib/hecks/release/runner/published.rb +55 -0
- data/lib/hecks/release/runner/tagger.rb +80 -0
- data/lib/hecks/release/runner.rb +215 -0
- data/lib/hecks/rendering.rb +4 -26
- data/lib/hecks/router/namespace_installer.rb +12 -36
- data/lib/hecks/router.rb +4 -8
- data/lib/hecks/runtime/aggregate_lock.rb +8 -33
- data/lib/hecks/runtime/boot_gates.rb +3 -18
- data/lib/hecks/runtime/caller.rb +19 -59
- data/lib/hecks/runtime/capability_graph.rb +5 -21
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +16 -78
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +23 -160
- data/lib/hecks/runtime/command_interpreter.rb +125 -307
- data/lib/hecks/runtime/command_rules/admissibility.rb +95 -366
- data/lib/hecks/runtime/command_rules/arithmetic.rb +66 -196
- data/lib/hecks/runtime/command_rules/authorization.rb +13 -45
- data/lib/hecks/runtime/command_rules/emission.rb +8 -21
- data/lib/hecks/runtime/command_rules/references.rb +23 -202
- data/lib/hecks/runtime/dependency_planning.rb +30 -102
- data/lib/hecks/runtime/dispatcher.rb +82 -241
- data/lib/hecks/runtime/entity_element.rb +40 -462
- data/lib/hecks/runtime/entity_interpreter.rb +65 -220
- data/lib/hecks/runtime/errors.rb +32 -115
- data/lib/hecks/runtime/event.rb +3 -25
- data/lib/hecks/runtime/identity.rb +18 -154
- data/lib/hecks/runtime/instance.rb +18 -150
- data/lib/hecks/runtime/interpreting.rb +11 -70
- data/lib/hecks/runtime/invocation.rb +28 -164
- data/lib/hecks/runtime/loader.rb +48 -186
- data/lib/hecks/runtime/outbox.rb +38 -261
- data/lib/hecks/runtime/policy_interpreter.rb +38 -200
- data/lib/hecks/runtime/port_operation_interpreter.rb +26 -87
- data/lib/hecks/runtime/query_interpreter.rb +45 -187
- data/lib/hecks/runtime/reaction_invocation.rb +36 -138
- data/lib/hecks/runtime/read_model_interpreter.rb +139 -208
- data/lib/hecks/runtime/rebuild_sweep.rb +8 -54
- data/lib/hecks/runtime/reference_hop.rb +8 -81
- data/lib/hecks/runtime/refusal_wording.rb +8 -89
- data/lib/hecks/runtime/registry/saga_persistence.rb +10 -102
- data/lib/hecks/runtime/registry/verification.rb +52 -225
- data/lib/hecks/runtime/registry/world_defaults.rb +4 -53
- data/lib/hecks/runtime/registry.rb +103 -244
- data/lib/hecks/runtime/remote_dispatcher.rb +37 -152
- data/lib/hecks/runtime/routing.rb +4 -15
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +14 -61
- data/lib/hecks/runtime/saga_interpreter.rb +79 -263
- data/lib/hecks/runtime/saga_pending_dispatch.rb +2 -43
- data/lib/hecks/runtime/tenant_check.rb +6 -68
- data/lib/hecks/runtime/tenant_scope.rb +3 -28
- data/lib/hecks/runtime/value/admission.rb +16 -67
- data/lib/hecks/runtime/value/coercion.rb +155 -641
- data/lib/hecks/runtime/value/entity_list_coercion.rb +26 -219
- data/lib/hecks/runtime/value.rb +12 -84
- data/lib/hecks/runtime.rb +17 -65
- data/lib/hecks/storehouse.rb +146 -567
- data/lib/hecks/tenancy/bluebook/tenancy.bluebook +8 -32
- data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +6 -23
- data/lib/hecks/vendoring/git_environment.rb +2 -8
- data/lib/hecks/vendoring/git_source.rb +4 -10
- data/lib/hecks/vendoring.rb +7 -46
- data/lib/hecks/version.rb +3 -14
- data/lib/hecks/vocabulary.rb +5 -0
- data/lib/hecks.rb +32 -82
- data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +8 -46
- data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +11 -80
- data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +10 -99
- metadata +30 -59
- data/lib/hecks/bench/cli.rb +0 -74
- data/lib/hecks/bench/environment.rb +0 -100
- data/lib/hecks/bench/postgres_probe.rb +0 -41
- data/lib/hecks/bench/report.rb +0 -116
- data/lib/hecks/bench/ruby_runner.rb +0 -151
- data/lib/hecks/bench/run.rb +0 -55
- data/lib/hecks/bench/rust_runner.rb +0 -165
- data/lib/hecks/bench/stats.rb +0 -75
- data/lib/hecks/bench/suite.rb +0 -172
- data/lib/hecks/bench/workload.rb +0 -137
- data/lib/hecks/bench.rb +0 -28
- data/lib/hecks/codemod.rb +0 -443
- data/lib/hecks/corpus.rb +0 -479
- data/lib/hecks/doc/reference.rb +0 -585
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +0 -684
- data/lib/hecks/fuzzing/combination_miner.rb +0 -178
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +0 -469
- data/lib/hecks/fuzzing/coverage_campaign.rb +0 -161
- data/lib/hecks/fuzzing/differential.rb +0 -192
- data/lib/hecks/fuzzing/domain_generator.rb +0 -871
- data/lib/hecks/fuzzing/era_boundary.rb +0 -154
- data/lib/hecks/fuzzing/form_census.rb +0 -285
- data/lib/hecks/fuzzing/generated_domain_check.rb +0 -171
- data/lib/hecks/fuzzing/invalid_value_generator.rb +0 -125
- data/lib/hecks/fuzzing/isolated_boot.rb +0 -658
- data/lib/hecks/fuzzing/nondeterministic.rb +0 -79
- data/lib/hecks/fuzzing/persistence_parity.rb +0 -253
- data/lib/hecks/fuzzing/properties/corrections.rb +0 -125
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +0 -688
- data/lib/hecks/fuzzing/properties/guards.rb +0 -398
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +0 -399
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +0 -137
- data/lib/hecks/fuzzing/properties/outbox.rb +0 -180
- data/lib/hecks/fuzzing/properties/querying.rb +0 -260
- data/lib/hecks/fuzzing/properties.rb +0 -267
- data/lib/hecks/fuzzing/qa_settings.rb +0 -164
- data/lib/hecks/fuzzing/replay.rb +0 -930
- data/lib/hecks/fuzzing/rotation_priority.rb +0 -114
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +0 -139
- data/lib/hecks/fuzzing/self_consistency.rb +0 -825
- data/lib/hecks/fuzzing/sequence_generator/adversary.rb +0 -532
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +0 -171
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +0 -127
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +0 -116
- data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +0 -138
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +0 -344
- data/lib/hecks/fuzzing/sequence_generator.rb +0 -311
- data/lib/hecks/fuzzing/shrinker.rb +0 -309
- data/lib/hecks/fuzzing/structural_skips.rb +0 -53
- data/lib/hecks/fuzzing/sweep_depth.rb +0 -61
- data/lib/hecks/fuzzing/target_capabilities.rb +0 -255
- data/lib/hecks/fuzzing/value_generator.rb +0 -340
- data/lib/hecks/fuzzing.rb +0 -23
- data/lib/hecks/grammar/evolve.rb +0 -524
- data/lib/hecks/query_ir.rb +0 -482
|
@@ -14,36 +14,20 @@ require_relative "../naming"
|
|
|
14
14
|
|
|
15
15
|
module Hecks
|
|
16
16
|
module Runtime
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
# sub-interpreter (command, entity, port operation, query, read
|
|
20
|
-
# model), then runs every policy and saga reaction the resulting
|
|
21
|
-
# events trigger. Also the door reactions dispatch back through
|
|
22
|
-
# (#reenter), and the one place reaction-cascade depth is tracked, to
|
|
23
|
-
# keep a policy/saga loop from re-triggering itself without bound.
|
|
17
|
+
# Routes a "Domain::Aggregate.Command" verb to its interpreter, then runs the policy
|
|
18
|
+
# and saga reactions its events trigger; tracks reaction depth to bound cascades.
|
|
24
19
|
class Dispatcher
|
|
25
20
|
MAX_REACTION_DEPTH = 5
|
|
26
21
|
|
|
27
22
|
Result = Struct.new(:verb, :instance, :events, :execution_plan, :persistence_outcome, keyword_init: true) do
|
|
28
23
|
# Reads the identity of the record the dispatch settled on.
|
|
29
24
|
#
|
|
30
|
-
#
|
|
31
|
-
# — nothing was hydrated or saved, the same reason
|
|
32
|
-
# `PortOperationInterpreter#emit`'s own comment gives for sourcing
|
|
33
|
-
# `id:` off the operation's reference attribute instead. `&.`, not
|
|
34
|
-
# a raised error: a caller that dispatches a port verb and then
|
|
35
|
-
# asks this Result for `.id`/`.state` made a category error the
|
|
36
|
-
# domain itself already told it about (there is no record here),
|
|
37
|
-
# not a crash-worthy one.
|
|
38
|
-
#
|
|
39
|
-
# @return [String, nil] the record's identity; nil for a port operation, which
|
|
40
|
-
# hydrates no record
|
|
25
|
+
# @return [String, nil] the record's identity; nil for a port operation (no record)
|
|
41
26
|
def id = instance&.id
|
|
42
27
|
|
|
43
|
-
# Reads the settled record's attributes as one Hash
|
|
28
|
+
# Reads the settled record's attributes as one Hash.
|
|
44
29
|
#
|
|
45
|
-
# @return [Hash{Symbol => Object}, nil] the record's state
|
|
46
|
-
# last; nil for a port operation, which hydrates no record
|
|
30
|
+
# @return [Hash{Symbol => Object}, nil] the record's state; nil for a port operation
|
|
47
31
|
def state = instance&.to_h
|
|
48
32
|
|
|
49
33
|
def to_s
|
|
@@ -56,8 +40,7 @@ module Hecks
|
|
|
56
40
|
|
|
57
41
|
attr_reader :registry
|
|
58
42
|
|
|
59
|
-
# @param registry [Runtime::Registry] the booted registry every interpreter reads
|
|
60
|
-
# outbox is attached to this dispatcher's policy and saga interpreters
|
|
43
|
+
# @param registry [Runtime::Registry] the booted registry every interpreter reads
|
|
61
44
|
def initialize(registry)
|
|
62
45
|
@registry = registry
|
|
63
46
|
rules = CommandRules.new(registry)
|
|
@@ -68,108 +51,72 @@ module Hecks
|
|
|
68
51
|
@read_models = ReadModelInterpreter.new(registry)
|
|
69
52
|
@policies = PolicyInterpreter.new(registry, door: self)
|
|
70
53
|
@sagas = SagaInterpreter.new(registry, door: self)
|
|
71
|
-
#
|
|
72
|
-
# interpreters enqueue through `@registry.outbox` from inside
|
|
73
|
-
# the save transaction, and this dispatcher drains through the
|
|
74
|
-
# same object, so there is exactly one relay per registry no
|
|
75
|
-
# matter how many dispatchers front it. What it borrows from
|
|
76
|
-
# here is the pair of interpreters a consumer runs through.
|
|
54
|
+
# One relay per registry: interpreters enqueue through it inside the save transaction.
|
|
77
55
|
@registry.outbox.attach(policies: @policies, sagas: @sagas)
|
|
78
56
|
end
|
|
79
57
|
|
|
80
|
-
# Exposes the registry's outbox relay,
|
|
81
|
-
#
|
|
82
|
-
# `runtime.outbox.rows`, `.rows(status: "claimed")`, `.redrive!`,
|
|
83
|
-
# `.log` — see `Runtime::Outbox`.
|
|
58
|
+
# Exposes the registry's outbox relay, through which this dispatcher drains reactions.
|
|
84
59
|
#
|
|
85
|
-
# @return [Runtime::Outbox::Relay] the registry's one relay
|
|
86
|
-
# fronting that registry
|
|
60
|
+
# @return [Runtime::Outbox::Relay] the registry's one relay
|
|
87
61
|
def outbox = @registry.outbox
|
|
88
62
|
|
|
89
|
-
# Exposes every event emitted through this registry
|
|
63
|
+
# Exposes every event emitted through this registry, oldest first.
|
|
90
64
|
#
|
|
91
|
-
# @return [Array<Runtime::Event>]
|
|
65
|
+
# @return [Array<Runtime::Event>]
|
|
92
66
|
def events = @registry.event_log
|
|
93
67
|
|
|
94
|
-
# Exposes one record per policy reaction
|
|
68
|
+
# Exposes one record per policy reaction delivered, refused or left undelivered.
|
|
95
69
|
#
|
|
96
|
-
# @return [Array<Hash{Symbol => Object}>]
|
|
70
|
+
# @return [Array<Hash{Symbol => Object}>]
|
|
97
71
|
def reactions = @registry.reaction_log
|
|
98
72
|
|
|
99
73
|
# Exposes one record per process-manager step: a start, an advance, a delivery, a refusal.
|
|
100
74
|
#
|
|
101
|
-
# @return [Array<Hash{Symbol => Object}>]
|
|
75
|
+
# @return [Array<Hash{Symbol => Object}>]
|
|
102
76
|
def sagas = @registry.saga_log
|
|
103
77
|
|
|
104
|
-
# Exposes the raw inputs each saga dispatch bound its arguments from
|
|
78
|
+
# Exposes the raw inputs each saga dispatch bound its arguments from (Ruby-only).
|
|
105
79
|
#
|
|
106
|
-
# @return [Array<Hash{Symbol => Object}>]
|
|
80
|
+
# @return [Array<Hash{Symbol => Object}>]
|
|
107
81
|
def saga_dispatches = @registry.saga_dispatch_log
|
|
108
82
|
|
|
109
|
-
# Exposes the raw inputs each policy trigger bound its arguments from
|
|
83
|
+
# Exposes the raw inputs each policy trigger bound its arguments from (Ruby-only).
|
|
110
84
|
#
|
|
111
|
-
# @return [Array<Hash{Symbol => Object}>]
|
|
112
|
-
#
|
|
85
|
+
# @return [Array<Hash{Symbol => Object}>] entries keyed `:policy`, `:on`, `:payload`,
|
|
86
|
+
# `:with_spec` and `:args`
|
|
113
87
|
def policy_dispatches = @registry.policy_dispatch_log
|
|
114
88
|
|
|
115
89
|
# Lists every verb the loaded bluebooks declare.
|
|
116
90
|
#
|
|
117
|
-
# @return [Array<String>]
|
|
91
|
+
# @return [Array<String>] sorted
|
|
118
92
|
def verbs = @registry.verbs
|
|
119
93
|
|
|
120
|
-
# Runs one command, entity command or port operation, then
|
|
121
|
-
# its events are owed.
|
|
122
|
-
#
|
|
123
|
-
# The receiver in `to:`, the facts in `with:`, and nothing else.
|
|
124
|
-
# Loose keyword facts — `dispatch(verb, amount: 5)`, one bag holding
|
|
125
|
-
# both the route and the payload — were deprecated in 1.3.x and are
|
|
126
|
-
# gone: Ruby now refuses them itself, by name ("unknown keyword:
|
|
127
|
-
# :amount"). Code holding a bag of data rather than written keywords
|
|
128
|
-
# calls `dispatch_flat` below; that door is not going anywhere.
|
|
94
|
+
# Runs one command, entity command or port operation, then the reactions its events owe.
|
|
129
95
|
#
|
|
130
|
-
# @param verb [String]
|
|
131
|
-
#
|
|
132
|
-
# @param to [String, Hash, nil] the receiver: an aggregate identity, or an entity route
|
|
133
|
-
#
|
|
134
|
-
#
|
|
135
|
-
# @param
|
|
136
|
-
# @
|
|
137
|
-
#
|
|
138
|
-
# @
|
|
139
|
-
#
|
|
140
|
-
# @raise [Runtime::UnknownVerb] if the verb is not fully qualified, or names a domain,
|
|
141
|
-
# aggregate, command, entity or port operation that is not declared
|
|
142
|
-
# @raise [StandardError] any class in `Runtime::DOMAIN_REFUSALS` when the domain refuses
|
|
143
|
-
# the call (`GivenNotMet`, `TypeMismatch`, `Unauthorized`, `NotFound`, …)
|
|
144
|
-
# @raise [Runtime::StaleWrite] if concurrent writers beat this one through every retry
|
|
145
|
-
# @raise [Runtime::WiringError] if the aggregate's repository cannot be resolved
|
|
96
|
+
# @param verb [String] `"Domain::Aggregate.Command"`, `"Domain::Aggregate.Entity.Command"`
|
|
97
|
+
# or `"Domain::Aggregate.Port.Operation"`
|
|
98
|
+
# @param to [String, Hash, nil] the receiver: an aggregate identity, or an entity route Hash
|
|
99
|
+
# with `:aggregate` and `:entity`/`:entities`
|
|
100
|
+
# @param with [Hash, nil] the command's facts, keyed by argument name
|
|
101
|
+
# @param saga_correlation [Hash, nil] stamped on emitted events when a saga leg dispatches
|
|
102
|
+
# @return [Runtime::Dispatcher::Result] the instance is nil for a port operation
|
|
103
|
+
# @raise [Runtime::UnknownVerb] if the verb is malformed or names something undeclared
|
|
104
|
+
# @raise [StandardError] a `Runtime::DOMAIN_REFUSALS` class when the domain refuses
|
|
105
|
+
# @raise [Runtime::StaleWrite] if concurrent writers win every retry
|
|
146
106
|
def dispatch(verb, to: nil, with: nil, saga_correlation: nil)
|
|
147
107
|
dispatch_invocation(verb, to: to, with: with, saga_correlation: saga_correlation, flat: {})
|
|
148
108
|
end
|
|
149
109
|
|
|
150
110
|
# Dispatches a verb whose receiver and facts arrive together in one flat Hash.
|
|
151
111
|
#
|
|
152
|
-
#
|
|
153
|
-
# `
|
|
154
|
-
# reaction without a `with:` projection, and the self-hosted
|
|
155
|
-
# meta-domain all carry, where the receiver's identity is one of the
|
|
156
|
-
# keys because that is how the wire spells it. Routes exactly as the
|
|
157
|
-
# removed keyword door did: a Symbol `:to`, `:with` or
|
|
158
|
-
# `:saga_correlation` key is lifted out as that keyword, everything
|
|
159
|
-
# else is a fact (so a String "to" key stays a fact, as it did).
|
|
160
|
-
# Framework code that replays data calls this; application code
|
|
161
|
-
# calls `dispatch(verb, to:, with:)`.
|
|
112
|
+
# The wire form: Symbol keys `:to`, `:with` and `:saga_correlation` are lifted out as
|
|
113
|
+
# the keywords of `dispatch`; every other key, including a String "to", is a fact.
|
|
162
114
|
#
|
|
163
115
|
# @param verb [String] the fully qualified verb, in any shape `dispatch` accepts
|
|
164
|
-
# @param args [Hash] the facts
|
|
165
|
-
# `:saga_correlation`, read as `dispatch`'s keywords of the same names; not mutated
|
|
116
|
+
# @param args [Hash] the facts plus the optional Symbol keys above; not mutated
|
|
166
117
|
# @return [Runtime::Dispatcher::Result] the same result `dispatch` returns
|
|
167
|
-
# @raise [Runtime::UnknownVerb] if the verb is
|
|
168
|
-
#
|
|
169
|
-
# @raise [StandardError] any class in `Runtime::DOMAIN_REFUSALS` when the domain refuses
|
|
170
|
-
# the call
|
|
171
|
-
# @raise [Runtime::StaleWrite] if concurrent writers beat this one through every retry
|
|
172
|
-
# @raise [Runtime::WiringError] if the aggregate's repository cannot be resolved
|
|
118
|
+
# @raise [Runtime::UnknownVerb] if the verb is malformed or names something undeclared
|
|
119
|
+
# @raise [StandardError] a `Runtime::DOMAIN_REFUSALS` class when the domain refuses
|
|
173
120
|
def dispatch_flat(verb, args = {})
|
|
174
121
|
facts = args.dup
|
|
175
122
|
to = facts.delete(:to)
|
|
@@ -186,17 +133,8 @@ module Hecks
|
|
|
186
133
|
if command_name.include?(".")
|
|
187
134
|
head, sub = command_name.split(".", 2)
|
|
188
135
|
port = aggregate.port(head)
|
|
189
|
-
#
|
|
190
|
-
#
|
|
191
|
-
# are checked first, so an aggregate that ever declared both a
|
|
192
|
-
# port and an entity of the same name would resolve to the
|
|
193
|
-
# port; no domain in this corpus does, and `dispatch_port`'s
|
|
194
|
-
# own header already named this as an open wire-spelling
|
|
195
|
-
# question this resolves, not silently avoids. No `instance`
|
|
196
|
-
# comes back — nothing is hydrated or saved by a port
|
|
197
|
-
# operation (`PortOperationInterpreter`'s own header) — so
|
|
198
|
-
# `Result#id`/`#state` are nil-safe (above) for exactly this
|
|
199
|
-
# path.
|
|
136
|
+
# Ports are checked before entities, so a port wins a name an entity also declares.
|
|
137
|
+
# No instance comes back: a port operation hydrates and saves nothing.
|
|
200
138
|
if port
|
|
201
139
|
operation = port.operation(sub) ||
|
|
202
140
|
raise(UnknownVerb, RefusalWording.render_site("UnknownVerb", "port_no_operation",
|
|
@@ -218,37 +156,19 @@ module Hecks
|
|
|
218
156
|
@commands.call(domain, aggregate, command, invocation, saga_correlation)
|
|
219
157
|
end
|
|
220
158
|
|
|
221
|
-
# Correlation is
|
|
222
|
-
# here — it is part of the transaction, known from this method's
|
|
223
|
-
# own argument before a single event exists. Stamping it onto
|
|
224
|
-
# already-emitted events would keep an event mutable after it had
|
|
225
|
-
# happened.
|
|
226
|
-
#
|
|
227
|
-
# The ordering that depends on it holds for the same reason:
|
|
228
|
-
# `SagaInterpreter#advance` runs on this domain's `announced`
|
|
229
|
-
# events within this very call, and finds the correlation already
|
|
230
|
-
# there because it was never absent.
|
|
159
|
+
# Correlation is stamped as each event is built, so emitted events are never mutated.
|
|
231
160
|
|
|
232
161
|
react(announced, domain, aggregate, outbox_rows)
|
|
233
162
|
|
|
234
163
|
Result.new(verb: verb, instance: instance, events: announced,
|
|
235
164
|
execution_plan: execution_plan, persistence_outcome: persistence_outcome)
|
|
236
165
|
end
|
|
237
|
-
|
|
238
|
-
# **The one body both doors run** — `dispatch` (keywords) and
|
|
239
|
-
# `dispatch_flat` (one Hash) differ only in how the call's parts are
|
|
240
|
-
# spelled, never in what happens next.
|
|
241
166
|
private :dispatch_invocation
|
|
242
167
|
|
|
243
|
-
#
|
|
244
|
-
#
|
|
245
|
-
#
|
|
246
|
-
#
|
|
247
|
-
# run_dispatch_order`); a port operation saves nothing, so its
|
|
248
|
-
# rows are enqueued here, after the fact (`:enqueue`) — durable
|
|
249
|
-
# still, just not transactional with anything, because there is
|
|
250
|
-
# nothing for them to be transactional with. `nil` rows mean the
|
|
251
|
-
# repository has no outbox: react directly, exactly as before.
|
|
168
|
+
# Runs the policy and saga reactions owed because `announced` committed.
|
|
169
|
+
#
|
|
170
|
+
# A port operation saves nothing, so its outbox rows are enqueued here (`:enqueue`);
|
|
171
|
+
# nil rows mean the repository has no outbox and reactions run directly.
|
|
252
172
|
def react(announced, domain, aggregate, outbox_rows)
|
|
253
173
|
return if announced.empty?
|
|
254
174
|
|
|
@@ -260,38 +180,16 @@ module Hecks
|
|
|
260
180
|
|
|
261
181
|
# Answers whether a command would succeed right now, without saving, emitting or reacting.
|
|
262
182
|
#
|
|
263
|
-
#
|
|
264
|
-
#
|
|
265
|
-
# mutations applied in memory, ensures checked against the settled
|
|
266
|
-
# result), except `step_save`/`step_emit` never run, and neither do
|
|
267
|
-
# policies or sagas afterward: nothing here is committed, so nothing
|
|
268
|
-
# should react to it. Built for exactly the shape a whole-board
|
|
269
|
-
# postcondition needs to be tested against (a downstream project's
|
|
270
|
-
# own chess domain, checking "does this move leave my own king in
|
|
271
|
-
# check" — the alternative was dispatching a real, unrelated piece's
|
|
272
|
-
# own move purely to trigger the check, which then had to avoid
|
|
273
|
-
# interfering with the very position being tested).
|
|
274
|
-
#
|
|
275
|
-
# Raises the same refusals #dispatch does — a DomainRefusal
|
|
276
|
-
# subclass propagates normally, so a caller checking "would this be
|
|
277
|
-
# legal" writes the identical rescue clause a real dispatch already
|
|
278
|
-
# needs; this returns `true` only when nothing was refused.
|
|
279
|
-
#
|
|
280
|
-
# **Never a port verb** — `PortOperationInterpreter`'s own side effects
|
|
281
|
-
# (an external gateway call, say) have no meaningful in-memory-only
|
|
282
|
-
# form, so this refuses one outright rather than silently running
|
|
283
|
-
# it for real, which "dry" would otherwise quietly lie about.
|
|
183
|
+
# Runs the dispatch pipeline in memory only; refusals raise exactly as `dispatch` raises
|
|
184
|
+
# them. A port verb is refused: its side effects have no in-memory form.
|
|
284
185
|
#
|
|
285
186
|
# @param verb [String] the fully qualified aggregate or entity command verb
|
|
286
|
-
# @param args [Hash{Symbol => Object}] the
|
|
287
|
-
#
|
|
288
|
-
# @return [true] whenever nothing refused
|
|
289
|
-
# @raise [Runtime::WiringError] if the verb names a port operation
|
|
290
|
-
#
|
|
291
|
-
# @raise [Runtime::
|
|
292
|
-
# aggregate, command or entity that is not declared
|
|
293
|
-
# @raise [StandardError] any class in `Runtime::DOMAIN_REFUSALS` that the real dispatch
|
|
294
|
-
# would raise
|
|
187
|
+
# @param args [Hash{Symbol => Object}] the facts as flat keywords; `to` and `with` are
|
|
188
|
+
# ordinary facts here, never routing
|
|
189
|
+
# @return [true] whenever nothing refused
|
|
190
|
+
# @raise [Runtime::WiringError] if the verb names a port operation
|
|
191
|
+
# @raise [Runtime::UnknownVerb] if the verb is malformed or names something undeclared
|
|
192
|
+
# @raise [StandardError] any `Runtime::DOMAIN_REFUSALS` class the real dispatch would raise
|
|
295
193
|
def dry_run?(verb, **args)
|
|
296
194
|
domain, aggregate_name, command_name = parse(verb)
|
|
297
195
|
aggregate = resolve_aggregate(domain, aggregate_name, verb)
|
|
@@ -304,8 +202,7 @@ module Hecks
|
|
|
304
202
|
"only for aggregate and entity commands"
|
|
305
203
|
end
|
|
306
204
|
|
|
307
|
-
# `to:`/`with:` are not keywords
|
|
308
|
-
# either is an ordinary fact here (BUG#131), so both go in as nil.
|
|
205
|
+
# `to:`/`with:` are not keywords here; a key named either is an ordinary fact.
|
|
309
206
|
resolution = nil
|
|
310
207
|
invocation = Invocation.from_call(verb, to: nil, with: nil, flat: args, receiver: :entity) do
|
|
311
208
|
(resolution = EntityInterpreter::Resolution.of(aggregate, command_name)).command
|
|
@@ -320,36 +217,18 @@ module Hecks
|
|
|
320
217
|
true
|
|
321
218
|
end
|
|
322
219
|
|
|
323
|
-
# Runs one port operation named by its parts, then the reactions its events
|
|
324
|
-
#
|
|
325
|
-
# The door an adapter outside the bluebook calls through — never the
|
|
326
|
-
# domain itself. `port_name`/`operation_name` are separate arguments
|
|
327
|
-
# rather than one packed verb string on purpose: there is no established
|
|
328
|
-
# wire spelling for "domain, aggregate, port, operation" yet, and
|
|
329
|
-
# inventing one is a bigger decision than this call needs to make.
|
|
220
|
+
# Runs one port operation named by its parts, then the reactions its events owe.
|
|
330
221
|
#
|
|
331
|
-
#
|
|
332
|
-
#
|
|
333
|
-
# adapter may call this port" through is the next piece, not this one.
|
|
222
|
+
# The door for an adapter outside the bluebook; the parts are separate arguments because
|
|
223
|
+
# no wire spelling for a packed port verb exists.
|
|
334
224
|
#
|
|
335
|
-
# @param
|
|
336
|
-
# @param aggregate_name [String, Symbol] name of the aggregate that declares the port
|
|
337
|
-
# @param port_name [String] name of the port, as the aggregate declares it
|
|
338
|
-
# @param operation_name [String] name of the operation on that port
|
|
339
|
-
# @param to [String, Hash, nil] the receiving aggregate's identity; when nil it is read
|
|
340
|
-
# from the facts, by the operation's reference or identity attribute
|
|
225
|
+
# @param to [String, Hash, nil] the receiver; when nil it is read from the facts
|
|
341
226
|
# @param with [Hash, nil] the operation's facts, keyed by argument name
|
|
342
|
-
# @param flat [Hash] the
|
|
343
|
-
#
|
|
344
|
-
#
|
|
345
|
-
# @
|
|
346
|
-
#
|
|
347
|
-
# outbound one
|
|
348
|
-
# @raise [Runtime::UnknownVerb] if the domain, aggregate, port or operation is not declared
|
|
349
|
-
# @raise [Runtime::TypeMismatch] if no receiving identity can be found, or `to:`/`with:`
|
|
350
|
-
# is malformed
|
|
351
|
-
# @raise [Runtime::NotFound] if the receiving aggregate record does not exist
|
|
352
|
-
# @raise [Runtime::WiringError] if the aggregate's repository cannot be resolved
|
|
227
|
+
# @param flat [Hash] the `dispatch_flat` wire form, for an adapter holding a decoded webhook
|
|
228
|
+
# @return [Array<Runtime::Event>] the events the operation announced
|
|
229
|
+
# @raise [Runtime::UnknownVerb] if the domain, aggregate, port or operation is undeclared
|
|
230
|
+
# @raise [Runtime::TypeMismatch] if no receiving identity is found, or `to:`/`with:` is bad
|
|
231
|
+
# @raise [Runtime::NotFound] if the receiving record does not exist
|
|
353
232
|
def dispatch_port(domain, aggregate_name, port_name, operation_name, to: nil, with: nil, flat: {})
|
|
354
233
|
aggregate = resolve_aggregate(domain, aggregate_name, "#{domain}::#{aggregate_name}.#{port_name}.#{operation_name}")
|
|
355
234
|
port = aggregate.port(port_name) ||
|
|
@@ -369,22 +248,16 @@ module Hecks
|
|
|
369
248
|
|
|
370
249
|
# Answers a declared query: an aggregate query, an entity query, or a read model.
|
|
371
250
|
#
|
|
372
|
-
#
|
|
373
|
-
#
|
|
374
|
-
# `"Domain::Aggregate.Entity.Query"` an entity query.
|
|
251
|
+
# `"Domain.ReadModel"` (no `::`) is a read model; `"Domain::Aggregate.Query"` and
|
|
252
|
+
# `"Domain::Aggregate.Entity.Query"` are aggregate and entity queries.
|
|
375
253
|
#
|
|
376
254
|
# @param verb [String, Symbol] the query's verb, in one of the three shapes above
|
|
377
255
|
# @param args [Hash{Symbol => Object}] the query's declared arguments
|
|
378
|
-
# @return [Array<Hash>]
|
|
379
|
-
# its state with `:id` merged in last; for an entity query, one Hash per matching
|
|
380
|
-
# element with the parent's reference key merged in first; for a read model, a
|
|
256
|
+
# @return [Array<Hash>] one Hash per matching record or element; a read model returns a
|
|
381
257
|
# one-element Array holding a Hash of head name to projected rows
|
|
382
|
-
# @raise [Runtime::UnknownVerb] if the verb is
|
|
383
|
-
# aggregate, entity, query or read model that is not declared
|
|
258
|
+
# @raise [Runtime::UnknownVerb] if the verb is malformed or names something undeclared
|
|
384
259
|
# @raise [Runtime::NotFound] if a read model's root reference names no record
|
|
385
260
|
# @raise [Runtime::TypeMismatch] if an argument cannot be coerced to its declared type
|
|
386
|
-
# @raise [KeyError] if a rooted read model is asked without its reference argument
|
|
387
|
-
# @raise [Runtime::WiringError] if the aggregate's repository cannot be resolved
|
|
388
261
|
def query(verb, **args)
|
|
389
262
|
domain, query_name = verb.to_s.split(".", 2)
|
|
390
263
|
if query_name && !domain.include?("::")
|
|
@@ -404,20 +277,14 @@ module Hecks
|
|
|
404
277
|
|
|
405
278
|
# Answers an aggregate or entity query through the reference interpreter alone.
|
|
406
279
|
#
|
|
407
|
-
#
|
|
408
|
-
#
|
|
409
|
-
# `"Domain::Aggregate.Query"` forms answer here; the fuzzer's
|
|
410
|
-
# query oracle diffs this against `#query`'s answer.
|
|
280
|
+
# Never answered by the bound adapter's native hook; the fuzzer's query oracle diffs it
|
|
281
|
+
# against `#query`. Read models have no reference twin.
|
|
411
282
|
#
|
|
412
|
-
# @param verb [String]
|
|
413
|
-
# `"Domain::Aggregate.Entity.Query"`
|
|
283
|
+
# @param verb [String] `"Domain::Aggregate.Query"` or `"Domain::Aggregate.Entity.Query"`
|
|
414
284
|
# @param args [Hash{Symbol => Object}] the query's declared arguments
|
|
415
|
-
# @return [Array<Hash>] one Hash per matching record
|
|
416
|
-
#
|
|
417
|
-
# @raise [Runtime::UnknownVerb] if the verb is not fully qualified, or names a domain,
|
|
418
|
-
# aggregate, entity or query that is not declared
|
|
285
|
+
# @return [Array<Hash>] one Hash per matching record or element
|
|
286
|
+
# @raise [Runtime::UnknownVerb] if the verb is malformed or names something undeclared
|
|
419
287
|
# @raise [Runtime::TypeMismatch] if an argument cannot be coerced to its declared type
|
|
420
|
-
# @raise [Runtime::WiringError] if the aggregate's repository cannot be resolved
|
|
421
288
|
def reference_query(verb, **args)
|
|
422
289
|
domain, aggregate_name, query_name = parse(verb)
|
|
423
290
|
aggregate = resolve_aggregate(domain, aggregate_name, verb)
|
|
@@ -425,43 +292,18 @@ module Hecks
|
|
|
425
292
|
@queries.reference_call(domain, aggregate, query_name, args)
|
|
426
293
|
end
|
|
427
294
|
|
|
428
|
-
# Dispatches a reaction's command one level deeper in the cascade, as the system
|
|
429
|
-
# than as the triggering caller.
|
|
430
|
-
#
|
|
431
|
-
# A reaction is the system acting, not the caller who happened to be
|
|
432
|
-
# on the stack when the triggering command ran — the ambient caller
|
|
433
|
-
# is cleared for the reaction's own dispatch, so a triggering
|
|
434
|
-
# caller's role can neither satisfy nor block a reaction command it
|
|
435
|
-
# has nothing to do with (Runtime::Caller.without).
|
|
436
|
-
#
|
|
437
|
-
# `Thread.current[:hecks_reaction_depth]`, not a plain ivar — this
|
|
438
|
-
# `Dispatcher` instance is a single object shared by every thread
|
|
439
|
-
# dispatching through it (a Puma worker pool, say), so a plain ivar
|
|
440
|
-
# here is exactly the known Puma-concurrency bug class: two
|
|
441
|
-
# concurrent top-level dispatches on different threads would
|
|
442
|
-
# increment/decrement the same counter, letting one thread's nested
|
|
443
|
-
# reaction depth leak into another thread's unrelated dispatch. A
|
|
444
|
-
# `Mutex` is not the answer either — a reaction cascade re-enters
|
|
445
|
-
# `reenter` on the same thread (see `SagaInterpreter#advance_saga`'s
|
|
446
|
-
# own comment on why a non-reentrant `Mutex` can't guard this).
|
|
447
|
-
# `Thread.current`-backed, saved/restored around the call with a
|
|
448
|
-
# plain local + `ensure`, is the same idiom `Runtime::Caller`
|
|
449
|
-
# (`caller.rb`) already established for exactly this shape of
|
|
450
|
-
# per-thread ambient state.
|
|
295
|
+
# Dispatches a reaction's command one level deeper in the cascade, as the system.
|
|
451
296
|
#
|
|
452
|
-
# The
|
|
453
|
-
#
|
|
454
|
-
#
|
|
297
|
+
# The ambient caller is cleared (Runtime::Caller.without) so the triggering caller's role
|
|
298
|
+
# neither satisfies nor blocks the reaction. Depth lives in `Thread.current`, not an ivar
|
|
299
|
+
# or Mutex: the dispatcher is shared across threads and cascades re-enter on one thread.
|
|
300
|
+
# The depth limit is checked by the reacting interpreter, not here.
|
|
455
301
|
#
|
|
456
302
|
# @param verb [String] the fully qualified verb of the reaction's target command
|
|
457
|
-
# @param saga_correlation [Hash{String => Object}, nil]
|
|
458
|
-
#
|
|
459
|
-
# @
|
|
460
|
-
#
|
|
461
|
-
# @return [Runtime::Dispatcher::Result] the result of the nested dispatch
|
|
462
|
-
# @raise [Runtime::UnknownVerb] if the verb names nothing declared
|
|
463
|
-
# @raise [StandardError] any class in `Runtime::DOMAIN_REFUSALS` when the target
|
|
464
|
-
# refuses; the policy and saga interpreters rescue these as recorded outcomes
|
|
303
|
+
# @param saga_correlation [Hash{String => Object}, nil] set when a saga leg dispatches
|
|
304
|
+
# @param args [Hash{Symbol => Object}] flat facts, read as `dispatch_flat` reads them
|
|
305
|
+
# @return [Runtime::Dispatcher::Result] the nested dispatch's result
|
|
306
|
+
# @raise [StandardError] any `Runtime::DOMAIN_REFUSALS` class; interpreters rescue these
|
|
465
307
|
def reenter(verb, saga_correlation: nil, **args)
|
|
466
308
|
depth = Thread.current[:hecks_reaction_depth].to_i
|
|
467
309
|
Thread.current[:hecks_reaction_depth] = depth + 1
|
|
@@ -472,13 +314,12 @@ module Hecks
|
|
|
472
314
|
|
|
473
315
|
# Answers whether the calling thread's reaction cascade is as deep as it may go.
|
|
474
316
|
#
|
|
475
|
-
# @return [Boolean] true once
|
|
476
|
-
# `MAX_REACTION_DEPTH` or more; other threads' cascades are not counted
|
|
317
|
+
# @return [Boolean] true once nested `reenter` calls on this thread reach the limit
|
|
477
318
|
def reaction_depth_reached? = Thread.current[:hecks_reaction_depth].to_i >= MAX_REACTION_DEPTH
|
|
478
319
|
|
|
479
|
-
# Reads the cascade limit
|
|
320
|
+
# Reads the cascade limit an interpreter records when it declines to react.
|
|
480
321
|
#
|
|
481
|
-
# @return [Integer] `MAX_REACTION_DEPTH
|
|
322
|
+
# @return [Integer] `MAX_REACTION_DEPTH`
|
|
482
323
|
def max_reaction_depth = MAX_REACTION_DEPTH
|
|
483
324
|
|
|
484
325
|
private
|