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
|
@@ -5,37 +5,21 @@ require_relative "../refusal_wording"
|
|
|
5
5
|
module Hecks
|
|
6
6
|
module Runtime
|
|
7
7
|
class CommandInterpreter
|
|
8
|
-
# The payload gate: a command takes the arguments it declares
|
|
9
|
-
# them, and no others.
|
|
8
|
+
# The payload gate: a command takes the arguments it declares, all of them and no others.
|
|
10
9
|
module ArgumentGate
|
|
11
10
|
private
|
|
12
11
|
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
# misspelled argument would do nothing, in silence.
|
|
12
|
+
# Refuses any argument the command does not declare.
|
|
13
|
+
# Addressing keys (`id`, the aggregate's identity heads, the reference key)
|
|
14
|
+
# and saga correlation keys are allowed through.
|
|
17
15
|
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
# identified by, and the reference key of the root a command reaches
|
|
21
|
-
# through. Refusing those would refuse every dispatch there is.
|
|
22
|
-
#
|
|
23
|
-
# `extra_identity_heads:` — EntityInterpreter's own callers only. An
|
|
24
|
-
# entity dispatch addresses not just the root aggregate but every
|
|
25
|
-
# entity along the chain it walks to reach the piece the command
|
|
26
|
-
# actually belongs to (`Handler.Dispatch.Bind` is two hops), and each
|
|
27
|
-
# hop's own `identity_heads` is addressing the same way the root's
|
|
28
|
-
# are — `element_of` (entity_element.rb) reads them straight out of
|
|
29
|
-
# `args` to find the element, never as a fact the command itself
|
|
30
|
-
# declares. `[]` for a plain aggregate/port-operation dispatch, which
|
|
31
|
-
# has no chain to add.
|
|
16
|
+
# `extra_identity_heads:` carries the identity heads of each entity hop an entity
|
|
17
|
+
# dispatch walks; `[]` for a plain aggregate or port-operation dispatch.
|
|
32
18
|
def refuse_unknown_arguments(domain, aggregate, command, args, extra_identity_heads: [])
|
|
33
19
|
addressing = [:id, *aggregate.identity_heads, *extra_identity_heads, reference_key(command)] +
|
|
34
20
|
correlation_keys(domain)
|
|
35
21
|
known = (command.attributes.map(&:name) + addressing).compact.map(&:to_sym)
|
|
36
|
-
# Sorted
|
|
37
|
-
# refusal wording is contract — pinned byte-for-byte by the corpus, so
|
|
38
|
-
# it cannot depend on hash iteration order.
|
|
22
|
+
# Sorted: refusal wording is pinned byte-for-byte, so it cannot follow payload order.
|
|
39
23
|
unknown = (args.keys.map(&:to_sym) - known).sort
|
|
40
24
|
return if unknown.empty?
|
|
41
25
|
|
|
@@ -45,46 +29,18 @@ module Hecks
|
|
|
45
29
|
declared: declared_names(command))
|
|
46
30
|
end
|
|
47
31
|
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
#
|
|
52
|
-
# Refusing `Customer.Register` for a missing `name` needs to be
|
|
53
|
-
# deliberate, not an accident with a lie for a message. Without this
|
|
54
|
-
# check, `then_set :name, to: :name` finds nothing to resolve, passes
|
|
55
|
-
# the literal symbol on, and coercion reports `name is a PersonName —
|
|
56
|
-
# pass its fields as an object`, which describes a mistake the caller
|
|
57
|
-
# did not make. The real mistake — an argument simply missing — is
|
|
58
|
-
# never the one named unless this refuses it on purpose.
|
|
59
|
-
#
|
|
60
|
-
# No command attribute anywhere in the corpus carries a default — checked,
|
|
61
|
-
# all eight chapters, zero — so there is no optional argument for this to
|
|
62
|
-
# step on. Every declared attribute is a fact the command needs.
|
|
32
|
+
# Refuses a declared, non-optional argument that is missing. Without it a missing
|
|
33
|
+
# argument surfaces later as a misleading coercion error about a mistake the caller
|
|
34
|
+
# did not make.
|
|
63
35
|
#
|
|
64
|
-
# `aggregate:`
|
|
65
|
-
#
|
|
66
|
-
# (`CommandBuilder#reference_to`'s bare self-reference mints no
|
|
67
|
-
# attribute to be absent) — but `PortOperationBuilder#reference_to`
|
|
68
|
-
# always mints one (this file's own header on `PortOperation`: "no
|
|
69
|
-
# creates?/acts_on distinction to protect"), because an operation had
|
|
70
|
-
# no other way to say which record it addressed before `to:` existed.
|
|
71
|
-
# `to:` is that way now (`Dispatcher#port_invocation` promotes the
|
|
72
|
-
# identity attribute's own value out of the payload and into
|
|
73
|
-
# routing) — which leaves the attribute still declared, still
|
|
74
|
-
# non-optional, and never present in `args` at all: without this
|
|
75
|
-
# exemption, every operation with an identity attribute would refuse
|
|
76
|
-
# its own well-formed calls, dispatched exactly the way `to:`
|
|
77
|
-
# intends. Exempted here on the same terms an aggregate command's
|
|
78
|
-
# self-address always was — an address, not a fact the operation
|
|
79
|
-
# still needs handed back.
|
|
36
|
+
# `aggregate:` is set only for a port operation, whose identity attribute is
|
|
37
|
+
# promoted into routing by `to:` and so never appears in `args`; it is exempted.
|
|
80
38
|
def refuse_absent_arguments(command, args, aggregate: nil)
|
|
81
39
|
given = args.keys.map(&:to_sym)
|
|
82
40
|
exempt = aggregate && command.respond_to?(:identity_attribute) &&
|
|
83
41
|
command.identity_attribute(aggregate.hecks_name)&.name
|
|
84
42
|
required = command.attributes.reject(&:optional?).map { |attribute| attribute.name.to_sym } - [exempt]
|
|
85
|
-
# Sorted, for the same reason the unknown list
|
|
86
|
-
# contract, and a pinned wording cannot depend on the order a set
|
|
87
|
-
# difference happens to be computed in.
|
|
43
|
+
# Sorted, for the same reason as the unknown list.
|
|
88
44
|
absent = (required - given).sort
|
|
89
45
|
return if absent.empty?
|
|
90
46
|
|
|
@@ -94,29 +50,11 @@ module Hecks
|
|
|
94
50
|
declared: declared_names(command))
|
|
95
51
|
end
|
|
96
52
|
|
|
97
|
-
#
|
|
98
|
-
# .Freeze` is `reference_to Account` and no attributes at all, so
|
|
99
|
-
# `{declared}` rendered empty and the sentence trailed off mid-
|
|
100
|
-
# clause : "Freeze does not declare standing — it takes ". Read
|
|
101
|
-
# against a real refusal that shape is worse than unhelpful — it
|
|
102
|
-
# looks like the message itself is broken, right where a caller
|
|
103
|
-
# is already trying to work out what went wrong.
|
|
104
|
-
#
|
|
105
|
-
# Only the empty case changes. Every command that declares even
|
|
106
|
-
# one attribute renders exactly as it did before, because refusal
|
|
107
|
-
# wording is contract and pinned byte-for-byte by the corpus (see
|
|
108
|
-
# `refuse_unknown_arguments`' own note on sorting for why).
|
|
53
|
+
# An empty list must still read as a sentence; only the empty case is worded differently.
|
|
109
54
|
def declared_names(command) = command.attributes.map(&:name)
|
|
110
55
|
|
|
111
|
-
#
|
|
112
|
-
#
|
|
113
|
-
# each leg emits carries it and the next step can be correlated — so the key
|
|
114
|
-
# arrives on commands that never declare it, and legitimately.
|
|
115
|
-
#
|
|
116
|
-
# This is the weakest part of the gate. Correlation is the saga's business,
|
|
117
|
-
# and the better shape is for the saga to stamp its own key onto the event
|
|
118
|
-
# it caused rather than smuggle it through the command's payload. Until it
|
|
119
|
-
# does, refusing the key here would break every saga in the corpus.
|
|
56
|
+
# A saga threads its correlation key through every leg's payload, so the key arrives on
|
|
57
|
+
# commands that never declare it. Refusing it would break every saga.
|
|
120
58
|
def correlation_keys(domain)
|
|
121
59
|
Array(@registry.bluebook(domain)&.process_managers)
|
|
122
60
|
.filter_map { |saga| saga.correlates_by && saga.correlation_head }
|
|
@@ -4,9 +4,7 @@ require_relative "../entity_element"
|
|
|
4
4
|
module Hecks
|
|
5
5
|
module Runtime
|
|
6
6
|
class CommandInterpreter
|
|
7
|
-
#
|
|
8
|
-
# set, append (with value-object or entity elements), and the
|
|
9
|
-
# arithmetic pair.
|
|
7
|
+
# Applies a command's declared mutations (set, append, remove, arithmetic) to an instance.
|
|
10
8
|
module MutationApplier
|
|
11
9
|
private
|
|
12
10
|
|
|
@@ -19,23 +17,10 @@ module Hecks
|
|
|
19
17
|
end
|
|
20
18
|
end
|
|
21
19
|
|
|
22
|
-
#
|
|
23
|
-
# the grammar can emit gets its own branch, including the `else`
|
|
24
|
-
# backstop for the day a new op reaches this method undeclared (see
|
|
25
|
-
# its own comment). Splitting each branch into its own method would
|
|
26
|
-
# not reduce what a reader has to hold at once (each op's own
|
|
27
|
-
# comment already explains why it is shaped the way it is) and
|
|
28
|
-
# would obscure that the set is closed and exhaustive.
|
|
20
|
+
# Applies one mutation: sources read `pre` (pre-dispatch state), targets write `instance`.
|
|
29
21
|
# rubocop:disable Lint/DuplicateBranch -- :delegate and :corrects
|
|
30
|
-
# both no-op here, for
|
|
31
|
-
# branch's own comment below); merging would blur that distinction.
|
|
22
|
+
# both no-op here, for unrelated reasons; merging would blur that.
|
|
32
23
|
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
33
|
-
#
|
|
34
|
-
# `pre` — the pre-dispatch state (C4.2): every source below reads
|
|
35
|
-
# it, every target is written to `instance`. A command's effects
|
|
36
|
-
# are one update set; declaration order carries no meaning, and
|
|
37
|
-
# build refuses a field written twice (`CommandBuilder#
|
|
38
|
-
# refuse_duplicate_targets!`).
|
|
39
24
|
def apply(instance, aggregate, mutation, args, pre = instance)
|
|
40
25
|
case mutation.op
|
|
41
26
|
when :set
|
|
@@ -52,24 +37,14 @@ module Hecks
|
|
|
52
37
|
amount = @rules.resolve_source(mutation.source, args)
|
|
53
38
|
attribute = aggregate.attribute(mutation.target)
|
|
54
39
|
current = pre[mutation.target]
|
|
55
|
-
#
|
|
56
|
-
# task 9): see #rewrap_arithmetic_result's own comment below
|
|
57
|
-
# -- `amount` is wrapped only when `current` already is, not
|
|
58
|
-
# merely because the target attribute exists.
|
|
40
|
+
# Wrap `amount` only when `current` is already a Value (see #rewrap_arithmetic_result).
|
|
59
41
|
amount = Value.for_attribute(aggregate, attribute, amount) if attribute && current.is_a?(Value)
|
|
60
42
|
result = @rules.arithmetic(current, amount, mutation.target, @rules.sign_of(mutation.op))
|
|
61
43
|
instance[mutation.target] = rewrap_arithmetic_result(aggregate, attribute, current, result)
|
|
62
|
-
#
|
|
63
|
-
# plan task 4): remove -- the list-removal counterpart to
|
|
64
|
-
# append, matching an element by value (plan.bluebook's
|
|
65
|
-
# RemoveDependency/DeactivateSprint: "a concurrent Add can
|
|
66
|
-
# never be lost").
|
|
44
|
+
# Removes a list element by value, the counterpart to append.
|
|
67
45
|
when :remove
|
|
68
46
|
instance[mutation.target] = removed(pre, aggregate, mutation, args)
|
|
69
|
-
#
|
|
70
|
-
# plan task 4, i106): multiply/clamp, the scale/bound pair
|
|
71
|
-
# alongside increment/decrement's add/subtract pair -- see
|
|
72
|
-
# CommandRules::Arithmetic#multiply/#clamp's own comments.
|
|
47
|
+
# Scales the current value; the counterpart to clamp below.
|
|
73
48
|
when :multiply
|
|
74
49
|
amount = @rules.resolve_source(mutation.source, args)
|
|
75
50
|
attribute = aggregate.attribute(mutation.target)
|
|
@@ -77,65 +52,28 @@ module Hecks
|
|
|
77
52
|
amount = Value.for_attribute(aggregate, attribute, amount) if attribute && current.is_a?(Value)
|
|
78
53
|
result = @rules.multiply(current, amount, mutation.target)
|
|
79
54
|
instance[mutation.target] = rewrap_arithmetic_result(aggregate, attribute, current, result)
|
|
80
|
-
#
|
|
81
|
-
# plan task 4, i106): clamp -- bounds the current value into
|
|
82
|
-
# [min, max]. mutation.source is always a literal [min, max]
|
|
83
|
-
# pair, never an argument reference -- resolve_source would be
|
|
84
|
-
# a no-op for an Array (it only special-cases Symbol), so it's
|
|
85
|
-
# read straight.
|
|
55
|
+
# Bounds the current value into [min, max]; the source is a literal pair, read as is.
|
|
86
56
|
when :clamp
|
|
87
57
|
instance[mutation.target] = @rules.clamp(pre[mutation.target], mutation.source, mutation.target)
|
|
88
|
-
# `delegates_to
|
|
89
|
-
# the full reasoning for storing it as a mutation at all. A real
|
|
90
|
-
# no-op here, not a gap: it targets no field on this instance —
|
|
91
|
-
# `CommandInterpreter#step_delegate_to_entity`, a later step in
|
|
92
|
-
# the same dispatch, is what actually applies it, against the
|
|
93
|
-
# target entity element `EntityElement.apply_to_element` reaches,
|
|
94
|
-
# never through this method.
|
|
58
|
+
# `delegates_to`: a no-op here; CommandInterpreter#step_delegate_to_entity applies it.
|
|
95
59
|
when :delegate
|
|
96
60
|
nil
|
|
97
|
-
# `corrects
|
|
98
|
-
#
|
|
99
|
-
# no-op here too: it targets no field on this instance either —
|
|
100
|
-
# its own event name, and whether this record has actually
|
|
101
|
-
# emitted it, is checked once, up front, by
|
|
102
|
-
# CommandRules::Admissibility#enforce_correction_target, not
|
|
103
|
-
# here. Whatever field this correction actually changes is an
|
|
104
|
-
# ordinary declared (or, for `reverses: true`, derived — see
|
|
105
|
-
# AggregateBuilder#seal_correction_targets) mutation of its own,
|
|
106
|
-
# applied by one of the branches above like any other.
|
|
61
|
+
# `corrects`: a no-op here; its target event is checked up front by
|
|
62
|
+
# CommandRules::Admissibility#enforce_correction_target.
|
|
107
63
|
when :corrects
|
|
108
64
|
nil
|
|
109
65
|
else
|
|
110
|
-
#
|
|
111
|
-
# runtime path today, only a backstop against the day one
|
|
112
|
-
# more mutation kind reaches the grammar and this method,
|
|
113
|
-
# unlike every other one it could reach, does not: applying
|
|
114
|
-
# nothing and refusing nothing would be the one silent
|
|
115
|
-
# no-op in a language that otherwise refuses what it cannot
|
|
116
|
-
# check.
|
|
66
|
+
# Backstop: an unhandled op must refuse, not silently apply nothing.
|
|
117
67
|
raise Runtime::WiringError, "no mutation applier handles :#{mutation.op} — add one before declaring it"
|
|
118
68
|
end
|
|
119
69
|
end
|
|
120
70
|
# rubocop:enable Lint/DuplicateBranch
|
|
121
71
|
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
122
72
|
|
|
123
|
-
# A caller-supplied arg
|
|
124
|
-
#
|
|
125
|
-
# back to the aggregate's own current field when it isn't one — a
|
|
126
|
-
# caller appending at the end without computing or supplying a
|
|
127
|
-
# position (`position: :next_position`, a field the command never
|
|
128
|
-
# declares as an argument at all). `args.key?`, not a truthiness
|
|
129
|
-
# check on the value — an explicitly-nil argument still counts as
|
|
130
|
-
# "the caller named it," same distinction `assign_creation_attributes`
|
|
131
|
-
# already draws.
|
|
132
|
-
#
|
|
133
|
-
# Extracted to its own method (pure refactor, ternary -> early
|
|
134
|
-
# return, no behavior change) alongside `remove`'s own addition
|
|
135
|
-
# below, purely for readability at this point in the file.
|
|
73
|
+
# A caller-supplied arg wins; otherwise the field falls back to the instance's own
|
|
74
|
+
# value. `args.key?` so an explicit nil still counts as supplied.
|
|
136
75
|
def resolve_append_source(source, instance, args)
|
|
137
|
-
# `state(:field)`
|
|
138
|
-
# (`Literal::StateRef`'s own comment).
|
|
76
|
+
# `state(:field)` reads the record's own value, never an argument.
|
|
139
77
|
return instance[source.name] if source.is_a?(StateRef)
|
|
140
78
|
return source unless source.is_a?(Symbol)
|
|
141
79
|
return args[source] if args.key?(source)
|
|
@@ -149,12 +87,7 @@ module Hecks
|
|
|
149
87
|
value_object = aggregate.value_object(element_type)
|
|
150
88
|
value_object&.attributes&.each do |attribute|
|
|
151
89
|
held = fields[attribute.name]
|
|
152
|
-
# A single-field value unwraps to its scalar
|
|
153
|
-
# into the element's own (differently named) wrapper; a
|
|
154
|
-
# multi-field one (a `state(:en_passant_square)` Square
|
|
155
|
-
# copied off the record) has no scalar to stand in for it
|
|
156
|
-
# and is handed across whole — `Value.for_attribute` keeps a
|
|
157
|
-
# value of the element field's own type as it is.
|
|
90
|
+
# A single-field value unwraps to its scalar; a multi-field one passes through whole.
|
|
158
91
|
fields[attribute.name] = Value.scalar(held) if held.is_a?(Value) && held.to_h.size == 1
|
|
159
92
|
end
|
|
160
93
|
element = if value_object
|
|
@@ -165,27 +98,11 @@ module Hecks
|
|
|
165
98
|
fields)
|
|
166
99
|
end
|
|
167
100
|
|
|
168
|
-
# Frozen
|
|
169
|
-
# this, an appended list would come back mutable, letting a
|
|
170
|
-
# caller push straight into an aggregate's own state after the
|
|
171
|
-
# dispatch had finished.
|
|
101
|
+
# Frozen so a caller cannot push into the aggregate's state after dispatch.
|
|
172
102
|
Freezer.deep(Array(instance[mutation.target]) + [element])
|
|
173
103
|
end
|
|
174
104
|
|
|
175
|
-
#
|
|
176
|
-
# task 4): the removal counterpart to #appended -- matches by
|
|
177
|
-
# value equality, element-wise, no read-modify-write (plan.
|
|
178
|
-
# bluebook's own words: "so a concurrent Add can never be lost")
|
|
179
|
-
# -- unless the target list is itself entity-typed (BUG#32,
|
|
180
|
-
# QualityControl ledger), in which case `EntityElement.
|
|
181
|
-
# list_element_match?` matches by the entity's own identity
|
|
182
|
-
# field instead -- see that method's own comment for the full
|
|
183
|
-
# "why identity, not whole-value equality" reasoning. `mutation.
|
|
184
|
-
# source` is a single field reference (`:dependency`), unlike
|
|
185
|
-
# append's field-map -- resolved and Value-coerced the same way
|
|
186
|
-
# increment/decrement already coerce their own amount, so the
|
|
187
|
-
# comparison is against a like-shaped Value, not a raw scalar
|
|
188
|
-
# against a wrapped one.
|
|
105
|
+
# Removes the element matching by value, or by identity for entity-typed lists.
|
|
189
106
|
def removed(instance, aggregate, mutation, args)
|
|
190
107
|
value = @rules.resolve_source(mutation.source, args)
|
|
191
108
|
attribute = aggregate.attribute(mutation.target)
|
|
@@ -195,43 +112,8 @@ module Hecks
|
|
|
195
112
|
end
|
|
196
113
|
end
|
|
197
114
|
|
|
198
|
-
#
|
|
199
|
-
#
|
|
200
|
-
# branches wrapping `amount` into a `Value` unconditionally
|
|
201
|
-
# whenever the target attribute existed, never checking whether
|
|
202
|
-
# `current` (the field's own existing value, read straight off
|
|
203
|
-
# `instance[mutation.target]`) was also wrapped, would let the two
|
|
204
|
-
# sides of the same arithmetic call disagree on Value-ness. On a
|
|
205
|
-
# phantom-created field this is the common case, not an edge
|
|
206
|
-
# one: `Instance.defaults`/`#default_for` leaves a VO-typed
|
|
207
|
-
# attribute with no declared `default:` genuinely absent (nil),
|
|
208
|
-
# and `CommandRules::Arithmetic#arithmetic`/`#multiply`'s own
|
|
209
|
-
# `current ||= 0` then turns that nil into a raw, unwrapped
|
|
210
|
-
# Integer `0` -- so `current.is_a?(Value) && amount.is_a?(Value)`
|
|
211
|
-
# read false even though `amount` (correctly wrapped by the old
|
|
212
|
-
# unconditional line) genuinely held a valid, correctly-typed
|
|
213
|
-
# number, and the primitive path's `unless amount.is_a?(Numeric)`
|
|
214
|
-
# guard refused it as a type mismatch the caller never made --
|
|
215
|
-
# an artifact of this method's own asymmetric wrapping, not bad
|
|
216
|
-
# input.
|
|
217
|
-
#
|
|
218
|
-
# Fixed at the call site (above) by wrapping `amount` only when
|
|
219
|
-
# `current` is already a `Value` -- so an established VO-typed
|
|
220
|
-
# field (a multi-field Money balance, say, already hydrated from
|
|
221
|
-
# a prior save) keeps going through
|
|
222
|
-
# `Arithmetic#arithmetic_value_object` exactly as before (the
|
|
223
|
-
# "already-Value-wrapped field still mutates correctly" case
|
|
224
|
-
# this fix must not regress), while a phantom field's raw
|
|
225
|
-
# `current` and raw `amount` both take the plain-Numeric path
|
|
226
|
-
# together. This method closes the other half: the plain-Numeric
|
|
227
|
-
# path returns a bare Ruby number, and if the attribute is
|
|
228
|
-
# itself VO-typed (the norm), that raw result needs the same
|
|
229
|
-
# wrap `:set` already gives its own resolved value (`Value.for`)
|
|
230
|
-
# before it's stored, so a field's stored shape doesn't depend
|
|
231
|
-
# on which dispatch happened to mutate it first. A no-op
|
|
232
|
-
# whenever `current` was already a Value (the VO branch already
|
|
233
|
-
# returns one) or the mutation targets no declared attribute at
|
|
234
|
-
# all.
|
|
115
|
+
# Wraps a plain-Numeric arithmetic result back into the attribute's Value type.
|
|
116
|
+
# Skipped when `current` was already a Value, since the Value path returns one.
|
|
235
117
|
def rewrap_arithmetic_result(aggregate, attribute, current, result)
|
|
236
118
|
return result if current.is_a?(Value) || attribute.nil? || result.is_a?(Value)
|
|
237
119
|
|
|
@@ -254,37 +136,18 @@ module Hecks
|
|
|
254
136
|
EntityElement.check_entity_collision(aggregate, entity, current, fields)
|
|
255
137
|
end
|
|
256
138
|
fields[entity.lifecycle.field] ||= entity.lifecycle.default if entity.lifecycle
|
|
257
|
-
#
|
|
258
|
-
#
|
|
259
|
-
# above) didn't already touch gets its own default, the same
|
|
260
|
-
# way a fresh aggregate's own attributes already do
|
|
261
|
-
# (`Instance.defaults`) — see `EntityElement#
|
|
262
|
-
# fill_declared_defaults`'s own comment for the full reasoning;
|
|
263
|
-
# shared rather than reimplemented so this aggregate-level
|
|
264
|
-
# entity creation and `EntityElement#appended_to_element`'s
|
|
265
|
-
# entity-nested-in-entity one can never drift on what "the
|
|
266
|
-
# default" means.
|
|
139
|
+
# Fill declared defaults for attributes the append mapping did not touch, shared with
|
|
140
|
+
# EntityElement so both entity-creation paths agree on what "the default" means.
|
|
267
141
|
EntityElement.fill_declared_defaults(aggregate, entity, fields)
|
|
268
142
|
end
|
|
269
143
|
|
|
270
|
-
#
|
|
271
|
-
# `size + 1`, which repeats an identity the moment the list has
|
|
272
|
-
# ever shrunk. One strategy for the language, so the IR declares
|
|
273
|
-
# none; the Rust generators mint by the same rule.
|
|
144
|
+
# One past the highest identity held, not `size + 1`, which repeats one after a shrink.
|
|
274
145
|
def next_identity(current, entity)
|
|
275
146
|
held = Array(current).map { |element| Value.scalar(element[entity.identified_by]).to_i }
|
|
276
147
|
held.max.to_i + 1
|
|
277
148
|
end
|
|
278
149
|
|
|
279
|
-
# The entity-collision
|
|
280
|
-
# (entity_element.rb) — BUG#145 — shared by both `#entity_element` above
|
|
281
|
-
# (an aggregate's own entity list, e.g. `Workspace.boards`) and
|
|
282
|
-
# `EntityElement#appended_to_element`'s own nested-entity branch (an
|
|
283
|
-
# entity's own entity list one hop further in, e.g. `Board.cards`),
|
|
284
|
-
# which needs the exact same guard against a caller-supplied nested
|
|
285
|
-
# identity silently duplicating. See that method's own call site and
|
|
286
|
-
# comment; the check's own doc comment (heads/composite/auto-mint
|
|
287
|
-
# reasoning) lives with the code, in entity_element.rb.
|
|
150
|
+
# The entity-collision guard is shared with EntityElement#appended_to_element.
|
|
288
151
|
end
|
|
289
152
|
end
|
|
290
153
|
end
|