hecks 2.8.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 +4 -6
- 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 +17 -98
- 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 +5 -48
- 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 +31 -141
- 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 +14 -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 +25 -31
- 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 +16 -69
- 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 -194
- 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 -111
- 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 +53 -267
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +43 -305
- 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 +6 -21
- data/lib/hecks/bluebook/model_check.rb +100 -597
- 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 +4 -23
- data/lib/hecks/cli/document.rb +3 -21
- data/lib/hecks/cli/ir.rb +3 -5
- data/lib/hecks/cli/mcp.rb +2 -3
- data/lib/hecks/cli/mcp_door.rb +19 -114
- data/lib/hecks/cli/model_check.rb +18 -85
- data/lib/hecks/cli/project_cli.rb +7 -40
- data/lib/hecks/cli/project_diagrams.rb +0 -7
- data/lib/hecks/cli/run.rb +12 -58
- data/lib/hecks/cli/smoke_test.rb +2 -16
- data/lib/hecks/cli/stores.rb +1 -2
- data/lib/hecks/cli.rb +18 -24
- 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 +82 -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 +9 -90
- 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 +61 -64
- 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 +6 -25
- 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 +18 -124
- 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 +150 -678
- 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 +2 -15
- 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 +42 -134
- 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 +3 -6
- data/lib/hecks/release/runner/commands.rb +2 -4
- data/lib/hecks/release/runner/gem_publisher.rb +2 -3
- data/lib/hecks/release/runner/npm_publisher.rb +6 -20
- data/lib/hecks/release/runner/preflight.rb +4 -19
- data/lib/hecks/release/runner/tagger.rb +2 -9
- data/lib/hecks/release/runner.rb +3 -32
- 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 +124 -306
- 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 +64 -219
- 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 +117 -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 +99 -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 +141 -568
- 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.rb +26 -81
- 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 +3 -2
|
@@ -6,127 +6,59 @@ require_relative "../value"
|
|
|
6
6
|
module Hecks
|
|
7
7
|
module Runtime
|
|
8
8
|
class CommandRules
|
|
9
|
-
# The arithmetic half of mutation:
|
|
10
|
-
# increment/decrement land on an Integer or a one-numeric-field value
|
|
11
|
-
# object.
|
|
9
|
+
# The arithmetic half of mutation: source resolution, and how
|
|
10
|
+
# increment/decrement land on an Integer or a one-numeric-field value object.
|
|
12
11
|
module Arithmetic
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
# clamp, remove, delegate, corrects) declares an empty sign — it does
|
|
18
|
-
# no add-or-subtract arithmetic — which reads here as nil.
|
|
12
|
+
# Mirrors Vocabulary::MutationOp (language/bluebook/vocabulary.bluebook) so
|
|
13
|
+
# increment/decrement's sign cannot drift from the language's own definition.
|
|
14
|
+
# Ops with no arithmetic (set, append, multiply, clamp, remove, delegate,
|
|
15
|
+
# corrects) declare an empty sign, which reads here as nil.
|
|
19
16
|
MutationOp = Struct.new(:name, :sign, keyword_init: true)
|
|
20
17
|
|
|
21
18
|
MUTATION_OPS = Hecks::Vocabulary.rows("MutationOp").map do |row|
|
|
22
19
|
MutationOp.new(name: row["name"], sign: row["sign"].empty? ? nil : Integer(row["sign"]))
|
|
23
20
|
end.freeze
|
|
24
21
|
|
|
25
|
-
#
|
|
26
|
-
# itself
|
|
22
|
+
# Resolves a mutation's source: an argument's value for a Symbol, the
|
|
23
|
+
# literal itself otherwise.
|
|
27
24
|
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
# and `to: "sold"`, never a Symbol meant as a value.
|
|
25
|
+
# Looked up unconditionally, with no `args.key?` guard, so an absent
|
|
26
|
+
# optional argument resolves to nil instead of falling back to the
|
|
27
|
+
# symbol itself as a value.
|
|
32
28
|
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
# itself as the value. `Customer.Register` without its `name` would set name to
|
|
36
|
-
# the literal `:name`, coercion would meet a Symbol where a PersonName belongs,
|
|
37
|
-
# and the refusal would read "name is a PersonName — pass its fields as an
|
|
38
|
-
# object, not :name" — a message describing a mistake the caller had not
|
|
39
|
-
# made. The real mistake, an absent argument, would never be the one refused,
|
|
40
|
-
# which is what fuzz surfaced.
|
|
41
|
-
#
|
|
42
|
-
# An absent argument resolving to nil is correct, not pending work. The
|
|
43
|
-
# language can say which arguments are optional (`attribute ...,
|
|
44
|
-
# optional: true` — `CommandBuilder#attribute_impl`,
|
|
45
|
-
# `attribute_collector.rb`): `sets` sources correctly from
|
|
46
|
-
# an optional attribute, resolving absent to nil exactly as this
|
|
47
|
-
# method does, and refusing it here would be wrong, not merely
|
|
48
|
-
# undone work — `TillRoom::Till.TakeIn`'s own `note` (spec/
|
|
49
|
-
# fixtures/till.bluebook) and Banking's `CardPayment.Authorize`'s
|
|
50
|
-
# `tags` (payment_cards.bluebook) are real, live commands whose
|
|
51
|
-
# `sets` mutation is deliberately sourced from an optional
|
|
52
|
-
# attribute the caller may omit — `spec/runtime/command_rules_spec
|
|
53
|
-
# .rb`'s own "says an absent optional argument is nil, not the
|
|
54
|
-
# name of the argument" pins exactly this as correct, not pending.
|
|
55
|
-
# The meta-domain's own self-hosted commands (Command.Declare's
|
|
56
|
-
# `role`/`goal`/`provenance`/`from`/`position`, and ~35 more sites
|
|
57
|
-
# across the language) all lean on the identical pattern — nil is
|
|
58
|
-
# the right answer for a `sets` sourced from a declared-optional
|
|
59
|
-
# attribute the caller left out, every time.
|
|
60
|
-
#
|
|
61
|
-
# The one narrow gap that leaves — a `sets` source Symbol naming
|
|
62
|
-
# nothing the command declares at all (a typo, not an optional
|
|
63
|
-
# argument), which would resolve to nil here, indistinguishable
|
|
64
|
-
# from a legitimate optional absence — is closed at build time
|
|
65
|
-
# instead of here: `CommandBuilder#refuse_unknown_argument_sources!`
|
|
66
|
-
# refuses it the moment the `.bluebook` file loads, mirroring
|
|
67
|
-
# `AggregateBuilder#seal_query_argument`'s identical check for a
|
|
68
|
-
# query's own where-clause argument. This function stays a pure,
|
|
69
|
-
# unconditional lookup because by the time any mutation reaches
|
|
70
|
-
# it, the source has already been proven to name either a real,
|
|
71
|
-
# possibly-optional argument, or a StateRef/literal; there is
|
|
72
|
-
# nothing left here to refuse.
|
|
73
|
-
#
|
|
74
|
-
# @param source [Symbol, Object] a mutation's source: a Symbol names a command argument,
|
|
75
|
-
# anything else (String, Numeric, Array, Hash, `StateRef`) is returned as is
|
|
29
|
+
# @param source [Symbol, Object] a Symbol names a command argument, anything else
|
|
30
|
+
# is returned as is
|
|
76
31
|
# @param args [Hash{Symbol => Object}] the normalized command arguments
|
|
77
|
-
# @return [Object, nil] the
|
|
78
|
-
# argument out; otherwise `source` itself
|
|
32
|
+
# @return [Object, nil] the argument's value, nil if omitted, or `source` itself
|
|
79
33
|
def resolve_source(source, args)
|
|
80
34
|
return args[source] if source.is_a?(Symbol)
|
|
81
35
|
|
|
82
36
|
source
|
|
83
37
|
end
|
|
84
38
|
|
|
85
|
-
# Adds or subtracts `amount
|
|
86
|
-
#
|
|
39
|
+
# Adds or subtracts `amount`, on a bare number or the one numeric field two value
|
|
40
|
+
# objects share.
|
|
87
41
|
#
|
|
88
|
-
# @param current [Numeric, Runtime::Value, nil]
|
|
89
|
-
#
|
|
90
|
-
# @param
|
|
91
|
-
#
|
|
92
|
-
#
|
|
93
|
-
# @
|
|
94
|
-
# @
|
|
95
|
-
# @
|
|
96
|
-
#
|
|
97
|
-
# @raise [Runtime::TypeMismatch] if `amount` or `current` is not numeric, or two value
|
|
98
|
-
# objects do not share exactly one numeric field
|
|
99
|
-
# @raise [Runtime::InvariantViolation] if a value-object result breaks one of its own
|
|
100
|
-
# invariants
|
|
101
|
-
# @raise [Bluebook::Expression::EvaluationError] if the result does not fit a signed
|
|
102
|
-
# 64-bit Integer, or is a non-finite Float
|
|
42
|
+
# @param current [Numeric, Runtime::Value, nil] pre-dispatch value; nil (unset) is 0
|
|
43
|
+
# @param amount [Numeric, Runtime::Value] amount to move by
|
|
44
|
+
# @param target [Symbol, String] attribute name, for refusal wording only
|
|
45
|
+
# @param sign [Integer] 1 to increment, -1 to decrement
|
|
46
|
+
# @return [Numeric, Runtime::Value] `Runtime::Value` if both sides are, else a bare number
|
|
47
|
+
# @raise [Runtime::TypeMismatch] if either side isn't numeric, or shares no numeric field
|
|
48
|
+
# @raise [Runtime::InvariantViolation] if a value-object result breaks an invariant
|
|
49
|
+
# @raise [Bluebook::Expression::EvaluationError] if the result overflows Integer, or isn't
|
|
50
|
+
# finite
|
|
103
51
|
def arithmetic(current, amount, target, sign)
|
|
104
52
|
op = sign.positive? ? "increment" : "decrement"
|
|
105
53
|
current ||= 0
|
|
106
54
|
|
|
107
55
|
return arithmetic_value_object(current, amount, target, sign, op) if current.is_a?(Value) && amount.is_a?(Value)
|
|
108
56
|
|
|
109
|
-
#
|
|
110
|
-
# `
|
|
111
|
-
#
|
|
112
|
-
# field against yet (that is what `arithmetic_value_object`,
|
|
113
|
-
# above, is for once both sides carry real fields). Before this,
|
|
114
|
-
# falling straight to `unless amount.is_a?(Numeric)` below
|
|
115
|
-
# refused with "increment needs an Integer, got 500" — true of
|
|
116
|
-
# nothing: 500 is exactly the Integer it asked for, just still
|
|
117
|
-
# wearing the Money wrapper the command's own declared attribute
|
|
118
|
-
# type put it in. Unwrapped here, the same shape #clamp already
|
|
119
|
-
# falls through to for an absent VO-typed attribute
|
|
120
|
-
# (`current ||= 0`, then a raw scalar) — the mutation applier
|
|
121
|
-
# re-wraps the raw result into the declared VO type on write,
|
|
122
|
-
# the same way it already does for clamp's own result.
|
|
57
|
+
# A VO-typed attribute with no declared default is genuinely absent
|
|
58
|
+
# here (`current` is 0, not a Value), so `amount` still needs
|
|
59
|
+
# unwrapping to compare against a bare number.
|
|
123
60
|
amount = unwrap_single_numeric_field(amount) if amount.is_a?(Value)
|
|
124
61
|
|
|
125
|
-
# Widened from Integer to Numeric (migration plan task 4, i106):
|
|
126
|
-
# an external project's organ math increments a Float (`increment: 0.02`) --
|
|
127
|
-
# the raw, non-value-object path only ever mattered for Integer
|
|
128
|
-
# counters before this corpus existed. Integer stays the common
|
|
129
|
-
# case; Float is now accepted the same way.
|
|
130
62
|
unless amount.is_a?(Numeric)
|
|
131
63
|
raise TypeMismatch, RefusalWording.render_site("TypeMismatch", "arithmetic_amount",
|
|
132
64
|
op: op, target: target, offered: Rendering.describe(amount))
|
|
@@ -139,22 +71,19 @@ module Hecks
|
|
|
139
71
|
bounded(current + (sign * amount), op, current, sign * amount, sign.positive? ? "+" : "-")
|
|
140
72
|
end
|
|
141
73
|
|
|
142
|
-
#
|
|
143
|
-
#
|
|
144
|
-
#
|
|
145
|
-
# refusal, C8.3), worded as the Rust kernel's own generated
|
|
146
|
-
# `checked_add`/`checked_sub`/`checked_mul` word it.
|
|
74
|
+
# An effect's arithmetic is held to the same value model an expression's is:
|
|
75
|
+
# Integer signed 64-bit, Float finite. Out of range is an evaluation fault,
|
|
76
|
+
# not a refusal (ADR checked_add/checked_sub/checked_mul wording).
|
|
147
77
|
INT64_RANGE = (-(2**63))..((2**63) - 1)
|
|
148
78
|
|
|
149
|
-
# Passes an arithmetic result through only if it fits the value model: a signed
|
|
150
|
-
# Integer or a finite Float.
|
|
79
|
+
# Passes an arithmetic result through only if it fits the value model: a signed
|
|
80
|
+
# 64-bit Integer or a finite Float.
|
|
151
81
|
#
|
|
152
82
|
# @param result [Numeric] the computed value to check
|
|
153
|
-
# @param oper [String] the op's name
|
|
154
|
-
# the first word of the fault message
|
|
83
|
+
# @param oper [String] the op's name, the first word of the fault message
|
|
155
84
|
# @param lhs [Numeric] the left operand, quoted in the fault message
|
|
156
85
|
# @param rhs [Numeric] the right operand; its absolute value is quoted
|
|
157
|
-
# @param symbol [String] the operator to print between the operands
|
|
86
|
+
# @param symbol [String] the operator to print between the operands
|
|
158
87
|
# @return [Numeric] `result`, unchanged
|
|
159
88
|
# @raise [Bluebook::Expression::EvaluationError] if an Integer result is outside
|
|
160
89
|
# `INT64_RANGE`, or a Float result is NaN or infinite
|
|
@@ -171,31 +100,23 @@ module Hecks
|
|
|
171
100
|
"#{oper} overflowed: #{lhs} #{symbol} #{rhs.abs} is not a finite number"
|
|
172
101
|
end
|
|
173
102
|
|
|
174
|
-
# Adds or subtracts on the one numeric field two value objects share
|
|
175
|
-
# value object of `current`'s type.
|
|
103
|
+
# Adds or subtracts on the one numeric field two value objects share.
|
|
176
104
|
#
|
|
177
105
|
# @param current [Runtime::Value] the attribute's pre-dispatch value
|
|
178
|
-
# @param amount [Runtime::Value] how much to move by
|
|
179
|
-
# @param target [Symbol, String] name
|
|
106
|
+
# @param amount [Runtime::Value] how much to move by
|
|
107
|
+
# @param target [Symbol, String] attribute name, for refusal wording only
|
|
180
108
|
# @param sign [Integer] 1 to add, -1 to subtract
|
|
181
|
-
# @param oper [String] `"increment"
|
|
182
|
-
# @return [Runtime::Value]
|
|
183
|
-
#
|
|
184
|
-
# @raise [Runtime::
|
|
185
|
-
#
|
|
186
|
-
#
|
|
187
|
-
# object's own invariants
|
|
188
|
-
# @raise [Bluebook::Expression::EvaluationError] if the result does not fit a signed
|
|
189
|
-
# 64-bit Integer, or is a non-finite Float
|
|
109
|
+
# @param oper [String] `"increment"`/`"decrement"`, for refusal/fault wording
|
|
110
|
+
# @return [Runtime::Value] `current`, with the shared field replaced
|
|
111
|
+
# @raise [Runtime::TypeMismatch] if the two share no numeric field, or the rebuilt refuses
|
|
112
|
+
# @raise [Runtime::InvariantViolation] if the new field value breaks an invariant
|
|
113
|
+
# @raise [Bluebook::Expression::EvaluationError] if the result overflows Integer, or isn't
|
|
114
|
+
# finite
|
|
190
115
|
def arithmetic_value_object(current, amount, target, sign, oper)
|
|
191
116
|
current_fields = current.to_h
|
|
192
117
|
amount_fields = amount.to_h
|
|
193
|
-
#
|
|
194
|
-
#
|
|
195
|
-
# Float attribute (an external project's Synapse#strength, auto-wrapped per
|
|
196
|
-
# Part 3a's "bare primitives forbidden" finding) lands here as
|
|
197
|
-
# a one-Float-field Value exactly the way a one-Integer-field
|
|
198
|
-
# Value already did.
|
|
118
|
+
# A synthesized value-object wrapper around a bare numeric attribute
|
|
119
|
+
# always carries exactly one numeric field.
|
|
199
120
|
shared_numeric = current_fields.keys.select do |field|
|
|
200
121
|
current_fields[field].is_a?(Numeric) && amount_fields[field].is_a?(Numeric)
|
|
201
122
|
end
|
|
@@ -209,54 +130,32 @@ module Hecks
|
|
|
209
130
|
current[field], amount[field], sign.positive? ? "+" : "-"))
|
|
210
131
|
end
|
|
211
132
|
|
|
212
|
-
# Looks up whether a mutation op adds or subtracts, from the generated
|
|
133
|
+
# Looks up whether a mutation op adds or subtracts, from the generated
|
|
134
|
+
# `MUTATION_OPS` table.
|
|
213
135
|
#
|
|
214
|
-
# Not a bare `.find(...)&.sign || -1
|
|
215
|
-
# decrement's sign for
|
|
216
|
-
#
|
|
217
|
-
# (set/append/multiply/clamp/remove — see `MUTATION_OPS` above).
|
|
218
|
-
# Callers today only ever reach this for :increment/:decrement
|
|
219
|
-
# (both MutationApplier#apply and EntityInterpreter#
|
|
220
|
-
# apply_to_element gate every other op through their own `case`
|
|
221
|
-
# first, each with its own loud WiringError backstop), so this
|
|
222
|
-
# raise is not a real runtime path yet — it is the same
|
|
223
|
-
# backstop one level down, in case a future caller reaches
|
|
224
|
-
# #sign_of directly for an op that was never meant to have one.
|
|
136
|
+
# Not a bare `.find(...)&.sign || -1`: that would silently answer
|
|
137
|
+
# decrement's sign both for an unknown op and for a real op declared
|
|
138
|
+
# with no sign at all (set/append/multiply/clamp/remove/delegate/corrects).
|
|
225
139
|
#
|
|
226
140
|
# @param oper [Symbol, String] the mutation op's name, such as `:increment`
|
|
227
141
|
# @return [Integer] 1 for increment, -1 for decrement
|
|
228
142
|
# @raise [Runtime::WiringError] if the op is unknown, or is declared with no sign
|
|
229
|
-
# (set, append, multiply, clamp, remove, delegate, corrects)
|
|
230
143
|
def sign_of(oper)
|
|
231
144
|
MUTATION_OPS.find { |candidate| candidate.name == oper.to_s }&.sign ||
|
|
232
145
|
raise(WiringError, "no sign declared for mutation op #{oper.inspect} — add one before calling #sign_of")
|
|
233
146
|
end
|
|
234
147
|
|
|
235
|
-
# Scales an attribute's current value by `amount`, on a bare number or
|
|
148
|
+
# Scales an attribute's current value by `amount`, on a bare number or the one numeric
|
|
236
149
|
# field two value objects share.
|
|
237
150
|
#
|
|
238
|
-
#
|
|
239
|
-
#
|
|
240
|
-
#
|
|
241
|
-
#
|
|
242
|
-
#
|
|
243
|
-
#
|
|
244
|
-
#
|
|
245
|
-
#
|
|
246
|
-
# @param current [Numeric, Runtime::Value, nil] the attribute's pre-dispatch value; nil
|
|
247
|
-
# (never set) counts as 0
|
|
248
|
-
# @param amount [Numeric, Runtime::Value] the factor; a value object is combined field
|
|
249
|
-
# by field with a value-object `current`, and otherwise unwrapped to its single
|
|
250
|
-
# numeric field
|
|
251
|
-
# @param target [Symbol, String] name of the attribute, used only to word a refusal
|
|
252
|
-
# @return [Numeric, Runtime::Value] the product: a `Runtime::Value` when both sides are
|
|
253
|
-
# value objects, otherwise a bare number the caller re-wraps
|
|
254
|
-
# @raise [Runtime::TypeMismatch] if `amount` or `current` is not numeric, or two value
|
|
255
|
-
# objects do not share exactly one numeric field
|
|
256
|
-
# @raise [Runtime::InvariantViolation] if a value-object result breaks one of its own
|
|
257
|
-
# invariants
|
|
258
|
-
# @raise [Bluebook::Expression::EvaluationError] if the product does not fit a signed
|
|
259
|
-
# 64-bit Integer, or is a non-finite Float
|
|
151
|
+
# @param current [Numeric, Runtime::Value, nil] pre-dispatch value; nil (unset) is 0
|
|
152
|
+
# @param amount [Numeric, Runtime::Value] the factor
|
|
153
|
+
# @param target [Symbol, String] attribute name, for refusal wording only
|
|
154
|
+
# @return [Numeric, Runtime::Value] the product, a `Runtime::Value` when both sides are
|
|
155
|
+
# @raise [Runtime::TypeMismatch] if either side isn't numeric, or shares no numeric field
|
|
156
|
+
# @raise [Runtime::InvariantViolation] if a value-object result breaks an invariant
|
|
157
|
+
# @raise [Bluebook::Expression::EvaluationError] if the product overflows Integer, or isn't
|
|
158
|
+
# finite
|
|
260
159
|
def multiply(current, amount, target)
|
|
261
160
|
current ||= 0
|
|
262
161
|
|
|
@@ -266,8 +165,7 @@ module Hecks
|
|
|
266
165
|
end
|
|
267
166
|
end
|
|
268
167
|
|
|
269
|
-
# Same absent
|
|
270
|
-
# — see that method's own comment.
|
|
168
|
+
# Same absent-current, VO-wrapped-amount gap as #arithmetic, above.
|
|
271
169
|
amount = unwrap_single_numeric_field(amount) if amount.is_a?(Value)
|
|
272
170
|
|
|
273
171
|
unless amount.is_a?(Numeric) && current.is_a?(Numeric)
|
|
@@ -282,35 +180,15 @@ module Hecks
|
|
|
282
180
|
# Bounds an attribute's current value into `[min, max]`, on a bare number or on
|
|
283
181
|
# the one numeric field the wrapping value object carries.
|
|
284
182
|
#
|
|
285
|
-
#
|
|
286
|
-
# task 4, i106): bound the current value into `[min, max]` -- no
|
|
287
|
-
# "amount" to combine, so it does not go through
|
|
288
|
-
# #arithmetic/#multiply's shared-numeric-field matching at all;
|
|
289
|
-
# it clamps whichever single numeric field the wrapping value
|
|
290
|
-
# object carries (a synthesised wrapper always carries exactly
|
|
291
|
-
# one, per Part 3a's auto-synthesis).
|
|
292
|
-
#
|
|
293
|
-
# @param current [Numeric, Runtime::Value, nil] the attribute's pre-dispatch value; nil
|
|
294
|
-
# (never set) counts as 0
|
|
183
|
+
# @param current [Numeric, Runtime::Value, nil] pre-dispatch value; nil (unset) is 0
|
|
295
184
|
# @param bounds [Array<Numeric>] the two-element `[min, max]` range to clamp into
|
|
296
|
-
# @param target [Symbol, String] name
|
|
185
|
+
# @param target [Symbol, String] attribute name, used only to word a refusal
|
|
297
186
|
# @return [Numeric, Runtime::Value] the clamped value: a `Runtime::Value` when
|
|
298
187
|
# `current` is one, otherwise a bare number the caller re-wraps
|
|
299
188
|
# @raise [Runtime::TypeMismatch] if `current` is a value object with no single
|
|
300
189
|
# numeric field, or is neither numeric nor a value object
|
|
301
190
|
def clamp(current, bounds, target)
|
|
302
191
|
min, max = bounds
|
|
303
|
-
# The same `current ||= 0` #arithmetic/#multiply both give a
|
|
304
|
-
# phantom (never-set) numeric field, one line up from each —
|
|
305
|
-
# this was the one arithmetic op that didn't, so a VO-typed
|
|
306
|
-
# attribute with no declared `default:` (genuinely absent,
|
|
307
|
-
# `Instance.defaults`/`#default_for`) hit TypeMismatch on the
|
|
308
|
-
# first clamp. (#arithmetic/#multiply's own absent-current gap
|
|
309
|
-
# is a real, separate bug: they do not silently treat an absent
|
|
310
|
-
# field as zero; they raise too, blaming a perfectly valid
|
|
311
|
-
# `amount` for not being an Integer when it is one, just still
|
|
312
|
-
# Money-wrapped. Fixed alongside this one — see
|
|
313
|
-
# #unwrap_single_numeric_field.)
|
|
314
192
|
current ||= 0
|
|
315
193
|
if current.is_a?(Value)
|
|
316
194
|
fields = current.to_h
|
|
@@ -330,17 +208,9 @@ module Hecks
|
|
|
330
208
|
|
|
331
209
|
private
|
|
332
210
|
|
|
333
|
-
# `
|
|
334
|
-
#
|
|
335
|
-
#
|
|
336
|
-
# to call once `current` is known not to be a Value itself (the
|
|
337
|
-
# `current.is_a?(Value) && amount.is_a?(Value)` branch, above in
|
|
338
|
-
# both callers, already owns the case where both sides carry real
|
|
339
|
-
# fields to combine). Refuses rather than guesses when more than
|
|
340
|
-
# one field is numeric — genuinely ambiguous which one an absent
|
|
341
|
-
# `current` should be treated as zero for, the same reasoning
|
|
342
|
-
# `combine_value_object`'s own `shared_numeric.size == 1` check
|
|
343
|
-
# already holds to when both sides are present.
|
|
211
|
+
# Only meaningful once `current` is known not to itself be a Value (the
|
|
212
|
+
# both-sides-are-Values branch owns that case in each caller). Refuses
|
|
213
|
+
# rather than guesses when more than one field is numeric.
|
|
344
214
|
def unwrap_single_numeric_field(value)
|
|
345
215
|
fields = value.to_h
|
|
346
216
|
numeric_fields = fields.keys.select { |field| fields[field].is_a?(Numeric) }
|
|
@@ -6,44 +6,21 @@ require_relative "../../ports/authorization"
|
|
|
6
6
|
module Hecks
|
|
7
7
|
module Runtime
|
|
8
8
|
class CommandRules
|
|
9
|
-
#
|
|
10
|
-
# the one check that runs before any domain-state work, alongside the
|
|
11
|
-
# argument gate rather than after it.
|
|
9
|
+
# Refuses a command whose declared `role` the ambient caller does not hold.
|
|
12
10
|
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
# caller who never named who they are (every caller before this) is
|
|
16
|
-
# checked exactly the way it always has been, string equality
|
|
17
|
-
# against the command's own `role`. Only a caller that also binds an
|
|
18
|
-
# `actor_id` (`Hecks.as_caller(role:, actor_id:)`) reaches the
|
|
19
|
-
# real check — a live lookup through `Ports::Authorization`, once the
|
|
20
|
-
# command's domain has an authorization provider: its own chapter,
|
|
21
|
-
# or a framework member it attaches, declaring `provides
|
|
22
|
-
# "authorization"` (Governance, via `uses_framework "Governance"`).
|
|
23
|
-
# Boot refuses a domain that declares a `role` and has no provider —
|
|
24
|
-
# `Registry::Verification#refuse_ungoverned_roles!`. An identified caller is never
|
|
25
|
-
# let back through the string fallback: a real identity that holds
|
|
26
|
-
# no matching grant is refused, not waved through because it also
|
|
27
|
-
# happens to type the right word.
|
|
11
|
+
# A caller with an `actor_id` is checked against live grants when the domain has an
|
|
12
|
+
# authorization provider (ADR 0025); one without is compared by role string only.
|
|
28
13
|
module Authorization
|
|
29
|
-
# Refuses the command when the ambient caller (`Caller.current`)
|
|
30
|
-
# the command declares.
|
|
14
|
+
# Refuses the command when the ambient caller (`Caller.current`) lacks its declared role.
|
|
31
15
|
#
|
|
32
|
-
# Opt-in
|
|
33
|
-
# today. No role declared: unchecked too — `role` is genuinely
|
|
34
|
-
# optional in this language (roughly a third of banking's own
|
|
35
|
-
# commands declare none), so a command that never named a role has
|
|
36
|
-
# nothing to check a caller against.
|
|
16
|
+
# Opt-in on both sides: no caller bound, or no role declared, means no check.
|
|
37
17
|
#
|
|
38
|
-
# @param command [Bluebook::Command] the command about to run
|
|
39
|
-
#
|
|
40
|
-
# @
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
# @raise [Runtime::
|
|
44
|
-
# where a provider is attached, or otherwise if the caller's role string differs
|
|
45
|
-
# @raise [Runtime::WiringError] if an identified caller is checked and zero or more than
|
|
46
|
-
# one adapter implements the authorization port
|
|
18
|
+
# @param command [Bluebook::Command] the command about to run
|
|
19
|
+
# @param domain [String] name of the command's domain, whose provider answers the check
|
|
20
|
+
# @return [nil] when unchecked or authorized
|
|
21
|
+
# @raise [Runtime::Unauthorized] if the caller holds no grant of the role (identified
|
|
22
|
+
# caller) or its role string differs (unidentified caller)
|
|
23
|
+
# @raise [Runtime::WiringError] if zero or several adapters implement the port
|
|
47
24
|
def refuse_role_mismatch(command, domain)
|
|
48
25
|
caller = Caller.current
|
|
49
26
|
return unless caller
|
|
@@ -66,17 +43,8 @@ module Hecks
|
|
|
66
43
|
|
|
67
44
|
private
|
|
68
45
|
|
|
69
|
-
#
|
|
70
|
-
#
|
|
71
|
-
# The provider's own commands are looked up too, not waved through
|
|
72
|
-
# the string fallback: `Governance::RoleAssignment.Assign` declares
|
|
73
|
-
# `role "Governance administrator"`, and an identified caller
|
|
74
|
-
# dispatching it is checked against a live assignment of that role
|
|
75
|
-
# like any other gated command (ADR 0025 §9). The Rust kernel's
|
|
76
|
-
# `check_role` (`rust/src/kernel/repository.rs`) does the same. The
|
|
77
|
-
# consequence is deliberate: the first administrator grant has to
|
|
78
|
-
# come from a caller that binds no `actor_id` (the unchecked,
|
|
79
|
-
# string-compared path) — a bootstrap step, not a hole.
|
|
46
|
+
# The provider's own commands are checked too, so the first administrator grant must
|
|
47
|
+
# come from a caller with no `actor_id` (the string-compared path).
|
|
80
48
|
def governance_attached?(domain)
|
|
81
49
|
!registry.authorization_provider_for(domain).nil?
|
|
82
50
|
end
|
|
@@ -3,33 +3,20 @@ require_relative "../event"
|
|
|
3
3
|
module Hecks
|
|
4
4
|
module Runtime
|
|
5
5
|
class CommandRules
|
|
6
|
-
#
|
|
7
|
-
# and — where the store can hold one — a recorded event beside the
|
|
8
|
-
# data it describes.
|
|
6
|
+
# Turns a command's `emits` into events in the registry's log and, where possible, the store.
|
|
9
7
|
module Emission
|
|
10
|
-
# Builds one frozen event per name the command `emits
|
|
11
|
-
# event log, and records it in the store when the repository keeps events.
|
|
8
|
+
# Builds one frozen event per name the command `emits` and records each.
|
|
12
9
|
#
|
|
13
|
-
# `correlation`
|
|
14
|
-
# event afterwards. It is part of the transaction — known from
|
|
15
|
-
# `dispatch`'s own argument before anything is emitted — and an
|
|
16
|
-
# event that is still being written to is not yet a record of
|
|
17
|
-
# what happened. Setting it at construction is what lets the
|
|
18
|
-
# event be frozen the moment it exists.
|
|
10
|
+
# `correlation` is set at construction so the event can be frozen the moment it exists.
|
|
19
11
|
#
|
|
20
12
|
# @param command [Bluebook::Command] the command whose `emits` names the events
|
|
21
|
-
# @param domain [String]
|
|
22
|
-
# `aggregate` (`"Domain::Aggregate"`)
|
|
13
|
+
# @param domain [String] the emitting domain's name
|
|
23
14
|
# @param aggregate [Bluebook::Aggregate] the aggregate the record belongs to
|
|
24
15
|
# @param instance [Runtime::Instance] the settled record; its `id` stamps every event
|
|
25
|
-
# @param args [Hash{Symbol => Object}] the normalized
|
|
26
|
-
#
|
|
27
|
-
# @param
|
|
28
|
-
#
|
|
29
|
-
# @param correlation [Hash, nil] saga correlation head => value for a saga-caused
|
|
30
|
-
# dispatch; nil otherwise
|
|
31
|
-
# @return [Array<Runtime::Event>] the emitted events in `emits` order, each frozen;
|
|
32
|
-
# `[]` when the command emits nothing
|
|
16
|
+
# @param args [Hash{Symbol => Object}] the normalized arguments, used as each payload
|
|
17
|
+
# @param repository [Ports::Persistence::AppendOnly] asked to `record_event` if it can
|
|
18
|
+
# @param correlation [Hash, nil] saga correlation for a saga-caused dispatch
|
|
19
|
+
# @return [Array<Runtime::Event>] the emitted events in `emits` order
|
|
33
20
|
def emit(command, domain, aggregate, instance, args, repository, correlation = nil)
|
|
34
21
|
command.emits.map do |event_name|
|
|
35
22
|
event = Event.new(
|