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,38 +5,11 @@ require_relative "../../rendering"
|
|
|
5
5
|
module Hecks
|
|
6
6
|
module Runtime
|
|
7
7
|
class Value
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
# sibling, extended into `Value` alongside it exactly the way
|
|
11
|
-
# `Admission` already is) once `Coercion` itself grew past
|
|
12
|
-
# `Metrics/ModuleLength`'s budget from two, unrelated fixes landing in
|
|
13
|
-
# the same method the same week (BUG#32's own `hydrate_entity_identity`
|
|
14
|
-
# and BUG#33's own `check_entity_list_identities` — see each method's
|
|
15
|
-
# own header, and this repo's `.rubocop_todo.yml` for the merge that
|
|
16
|
-
# made the split necessary). Cross-calls into `Coercion`'s own
|
|
17
|
-
# `for_attribute`/`build`/`fields_for`/`value_object_for`/
|
|
18
|
-
# `trusting_stored_state?` work unqualified here, exactly as they do
|
|
19
|
-
# within `Coercion` itself, because both modules land on the same
|
|
20
|
-
# `Value` singleton class once extended — `self` never has to know
|
|
21
|
-
# which file a sibling method actually lives in.
|
|
8
|
+
# Hydrates a `list_of` attribute's own elements, entity-typed and
|
|
9
|
+
# value-object-typed alike; extended into `Value` alongside `Coercion`.
|
|
22
10
|
module EntityListCoercion
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
# root aggregate — `for_attribute`'s own `aggregate` argument is
|
|
26
|
-
# never reassigned as hydration recurses into a nested element,
|
|
27
|
-
# because coercion has to resolve value objects, and only the
|
|
28
|
-
# root answers `.value_object` at all (Entity's own header
|
|
29
|
-
# comment: an entity must not answer to it, or `Value.
|
|
30
|
-
# for_attribute` could no longer tell a piece from a head). So
|
|
31
|
-
# a nested entity — Dispatch, inside Handler — is not a direct
|
|
32
|
-
# child of the root the way Handler itself is, and a plain
|
|
33
|
-
# `aggregate.entities.find` stops one level short of it.
|
|
34
|
-
#
|
|
35
|
-
# @param construct [Bluebook::Aggregate, Bluebook::Entity] the construct to
|
|
36
|
-
# search, and every entity nested under it
|
|
37
|
-
# @param name [String] the entity's declared `hecks_name` to find
|
|
38
|
-
# @return [Bluebook::Entity, nil] the matching entity anywhere in the tree, or
|
|
39
|
-
# nil if none matches
|
|
11
|
+
# Searches the whole entity tree, not just the root's direct
|
|
12
|
+
# children; `aggregate` here is always the root aggregate. (ADR 0026)
|
|
40
13
|
def find_entity(construct, name)
|
|
41
14
|
construct.entities.each do |candidate|
|
|
42
15
|
return candidate if candidate.hecks_name == name
|
|
@@ -47,54 +20,12 @@ module Hecks
|
|
|
47
20
|
nil
|
|
48
21
|
end
|
|
49
22
|
|
|
50
|
-
# Hydrates a `list_of` attribute's offered value
|
|
51
|
-
# whole-list
|
|
52
|
-
# `attribute.type` and `value`'s own shape.
|
|
53
|
-
#
|
|
54
|
-
# Frozen through: a list read back out of the store is an answer,
|
|
55
|
-
# not a handle on what is stored.
|
|
23
|
+
# Hydrates a `list_of` attribute's offered value: each element of a
|
|
24
|
+
# whole-list Array, or a single remove-target value.
|
|
56
25
|
#
|
|
57
|
-
#
|
|
58
|
-
#
|
|
59
|
-
#
|
|
60
|
-
# mutation sourced from a whole-array argument (as opposed to
|
|
61
|
-
# element-by-element `append:`) goes straight through
|
|
62
|
-
# `for_attribute`'s `:list` branch, so `Banking::CardPayment.
|
|
63
|
-
# Authorize`'s own `sets :tags` (`list_of(Tag)`) would store plain
|
|
64
|
-
# Ruby Hashes as its `tags` elements forever — never a real
|
|
65
|
-
# `Value`, never through `Tag`'s own `pattern:`/`invariant`
|
|
66
|
-
# checks. `remove:`'s `==` comparison (a real `Value` against a
|
|
67
|
-
# raw `Hash`) would then always fail, since `Hash#==` refuses
|
|
68
|
-
# anything that isn't itself a compatible Hash — the bug ADR 0047
|
|
69
|
-
# traces in full. Delegating to `hydrate_value_object_list` below
|
|
70
|
-
# closes that gap the same way the entity branch already works:
|
|
71
|
-
# build a real, validated `Value` per element, reusing
|
|
72
|
-
# `for_attribute`'s own composite-construction path rather than
|
|
73
|
-
# inventing a second one.
|
|
74
|
-
# BUG#32 (QualityControl ledger) — without this, `remove:`'s own
|
|
75
|
-
# single-target value would fall straight into
|
|
76
|
-
# `Array(value).map { ... }` below unguarded, unlike this method's
|
|
77
|
-
# own delegated `hydrate_value_object_list` sibling, whose
|
|
78
|
-
# `value.is_a?(Array)` check exists for exactly this shape (see
|
|
79
|
-
# that method's own comment). For an entity-typed list, `remove:`'s
|
|
80
|
-
# scalar target (`Ledger.Void`'s `sequence: EntrySequence`) is
|
|
81
|
-
# never a Hash, so `Array(2)` would merely wrap it as `[2]` rather
|
|
82
|
-
# than shredding it — but the wrapping itself would still be wrong:
|
|
83
|
-
# `MutationApplier#removed`'s `element == value` would then compare
|
|
84
|
-
# a stored `Entry` Hash against a one-element Array, which can
|
|
85
|
-
# never be `==` a Hash, so nothing would ever be removed and
|
|
86
|
-
# nothing would ever refuse either. Routed to `hydrate_entity_identity`
|
|
87
|
-
# instead, below.
|
|
88
|
-
#
|
|
89
|
-
# @param aggregate [Bluebook::Aggregate] the root aggregate `attribute` is
|
|
90
|
-
# declared on
|
|
91
|
-
# @param attribute [Bluebook::Attribute] the `list_of` attribute being hydrated
|
|
92
|
-
# @param value [Array<Hash, Object>, Object] the offered value: a whole-list
|
|
93
|
-
# Array (a `sets`/hydrate load) or a single remove-target value
|
|
94
|
-
# @return [Object] a frozen Array of hydrated elements when `value` is a
|
|
95
|
-
# whole-list Array and `attribute.type` names an entity; otherwise whatever
|
|
96
|
-
# `hydrate_entity_identity` (a non-Array value naming an entity) or
|
|
97
|
-
# `hydrate_value_object_list` (`attribute.type` naming no entity) returns
|
|
26
|
+
# Delegates non-entity types to `hydrate_value_object_list` so
|
|
27
|
+
# elements get the same `pattern:`/invariant checks other
|
|
28
|
+
# composites get. (ADR 0047)
|
|
98
29
|
def hydrate_entity_list(aggregate, attribute, value)
|
|
99
30
|
entity = find_entity(aggregate, attribute.type.to_s)
|
|
100
31
|
return hydrate_value_object_list(aggregate, attribute, value) unless entity
|
|
@@ -110,61 +41,16 @@ module Hecks
|
|
|
110
41
|
acc[key] = field ? for_attribute(aggregate, field, field_value) : field_value
|
|
111
42
|
end
|
|
112
43
|
end
|
|
113
|
-
#
|
|
114
|
-
#
|
|
115
|
-
# single-target shape this same method also hydrates (a `remove:`
|
|
116
|
-
# target, wrapped one level up by `Array()`) never reaches this
|
|
117
|
-
# check, and never should — see `check_entity_list_identities`'s
|
|
118
|
-
# own comment.
|
|
44
|
+
# Only a genuine whole-list offering names every element's own
|
|
45
|
+
# identity at once; a single `remove:` target never reaches this.
|
|
119
46
|
check_entity_list_identities(aggregate, entity, hydrated) if value.is_a?(Array)
|
|
120
47
|
Freezer.deep(hydrated)
|
|
121
48
|
end
|
|
122
49
|
|
|
123
|
-
#
|
|
124
|
-
#
|
|
125
|
-
#
|
|
126
|
-
#
|
|
127
|
-
# command argument/mutation, qa/stress_domains/corrections). The
|
|
128
|
-
# array branch above rebuilds each offered element's own declared
|
|
129
|
-
# fields but never checked the offered list itself for either way
|
|
130
|
-
# it can misname its own entities:
|
|
131
|
-
#
|
|
132
|
-
# - two elements sharing one identity — the same silent-duplicate
|
|
133
|
-
# hazard BUG#13's own comment describes: `EntityInterpreter#
|
|
134
|
-
# element_of`'s own `find_index` always matches the first
|
|
135
|
-
# match, so the second becomes permanently unaddressable by any
|
|
136
|
-
# later command.
|
|
137
|
-
# - an element missing its identity altogether — there is no
|
|
138
|
-
# auto-mint for a whole-list replace the way `MutationApplier#
|
|
139
|
-
# entity_element` mints one for a single append (which element
|
|
140
|
-
# would it mint for? every element here is the caller's own
|
|
141
|
-
# whole state, offered at once), so an absent identity is
|
|
142
|
-
# refused rather than guessed.
|
|
143
|
-
#
|
|
144
|
-
# Non-composite identities only, exactly BUG#13's own scope
|
|
145
|
-
# (`entity.identified_by` answers a single Symbol only when
|
|
146
|
-
# `identity_heads.size == 1`, `Behaviour::Traits#derive_identity`) —
|
|
147
|
-
# a composite identity's own duplicate/missing question is the
|
|
148
|
-
# same pre-existing, narrower gap BUG#13 documented and left open,
|
|
149
|
-
# not widened here.
|
|
150
|
-
#
|
|
151
|
-
# Refuses a whole-list offering that misnames its own entities' identities —
|
|
152
|
-
# a duplicate identity across two elements, or an element missing one.
|
|
153
|
-
#
|
|
154
|
-
# Skipped under `trusting_stored_state?`, the same guard `validate!`
|
|
155
|
-
# already gives every value object (C6.3): a record already
|
|
156
|
-
# written is trusted as it was, so tightening this check can never
|
|
157
|
-
# make an old, already-persisted record unreadable.
|
|
158
|
-
#
|
|
159
|
-
# @param aggregate [Bluebook::Aggregate] the aggregate `entity` belongs to,
|
|
160
|
-
# named in a refusal
|
|
161
|
-
# @param entity [Bluebook::Entity] the entity type `elements` are shaped as
|
|
162
|
-
# @param elements [Array<Hash, Object>] the hydrated whole-list offering; a
|
|
163
|
-
# non-Hash element is skipped, not checked
|
|
164
|
-
# @return [void]
|
|
165
|
-
# @raise [Runtime::TypeMismatch] if `entity` declares a single-field identity
|
|
166
|
-
# and an element offers no value for it
|
|
167
|
-
# @raise [Runtime::AlreadyExists] if two elements offer the same identity value
|
|
50
|
+
# Refuses a whole-list offering that misnames its own entities: a
|
|
51
|
+
# duplicate identity across two elements, or an element missing
|
|
52
|
+
# one. Single-field identities only; skipped once
|
|
53
|
+
# `trusting_stored_state?`.
|
|
168
54
|
def check_entity_list_identities(aggregate, entity, elements)
|
|
169
55
|
identity = entity.identified_by
|
|
170
56
|
return unless identity
|
|
@@ -194,43 +80,10 @@ module Hecks
|
|
|
194
80
|
end
|
|
195
81
|
end
|
|
196
82
|
|
|
197
|
-
#
|
|
198
|
-
#
|
|
199
|
-
#
|
|
200
|
-
#
|
|
201
|
-
# must never answer `.value_object` at all (`Entity`'s own header
|
|
202
|
-
# comment), so there is no whole-value shape here to rebuild in
|
|
203
|
-
# the first place, only the one field a caller would otherwise
|
|
204
|
-
# have to name to address that element any other way
|
|
205
|
-
# (`EntityElement#element_of`'s own `wants`). So this coerces the
|
|
206
|
-
# offered scalar against the entity's own identity field's
|
|
207
|
-
# declared type — not the entity's full shape — and hands back a
|
|
208
|
-
# real, correctly-typed `Value` ready to compare against each
|
|
209
|
-
# stored element's own identity field
|
|
210
|
-
# (`EntityElement.list_element_match?`, the shared rule both
|
|
211
|
-
# `MutationApplier#removed` and `EntityElement#
|
|
212
|
-
# removed_from_element` match against).
|
|
213
|
-
#
|
|
214
|
-
# A composite identity (more than one head) has no single field a
|
|
215
|
-
# bare `remove:` target could mean, so this passes the value
|
|
216
|
-
# through uncoerced rather than guessing which head — the same
|
|
217
|
-
# "nothing in this corpus needs it yet" boundary
|
|
218
|
-
# `MutationApplier#check_entity_collision`'s own header already
|
|
219
|
-
# draws for entity identity elsewhere in this runtime.
|
|
220
|
-
# Coerces a `remove:` target against an entity's own single-field
|
|
221
|
-
# identity type, rather than the entity's full shape.
|
|
222
|
-
#
|
|
223
|
-
# `list_element_match?` treats an uncoerced value the same way
|
|
224
|
-
# it always treated the pre-fix wrapped Array: never a match, a
|
|
225
|
-
# documented no-op rather than a crash.
|
|
226
|
-
#
|
|
227
|
-
# @param aggregate [Bluebook::Aggregate] the aggregate `entity` belongs to
|
|
228
|
-
# @param entity [Bluebook::Entity] the entity type `value` addresses
|
|
229
|
-
# @param value [Object] the offered remove-target value
|
|
230
|
-
# @return [Runtime::Value, Object] `value` already coerced (returned unchanged);
|
|
231
|
-
# the value coerced against the identity field's declared type when `entity`
|
|
232
|
-
# has a single identity head and a matching attribute; `value` unchanged
|
|
233
|
-
# otherwise (no identity head, a composite identity, or no matching attribute)
|
|
83
|
+
# Coerces a `remove:` target against an entity's single-field
|
|
84
|
+
# identity type, rather than the entity's full shape. Passed
|
|
85
|
+
# through unchanged for a composite identity (more than one head)
|
|
86
|
+
# rather than guessing which head it means.
|
|
234
87
|
def hydrate_entity_identity(aggregate, entity, value)
|
|
235
88
|
return value if value.is_a?(self)
|
|
236
89
|
|
|
@@ -243,47 +96,12 @@ module Hecks
|
|
|
243
96
|
for_attribute(aggregate, field, value)
|
|
244
97
|
end
|
|
245
98
|
|
|
246
|
-
# Hydrates a `list_of` attribute's offered value when
|
|
247
|
-
# names a value object rather than an entity.
|
|
99
|
+
# Hydrates a `list_of` attribute's offered value when
|
|
100
|
+
# `attribute.type` names a value object rather than an entity.
|
|
248
101
|
#
|
|
249
|
-
#
|
|
250
|
-
#
|
|
251
|
-
#
|
|
252
|
-
# a scalar composite attribute already uses (`for_attribute`'s own
|
|
253
|
-
# `coerced = ... build(value_object, fields_for(...), aggregate)`
|
|
254
|
-
# line) — same defaults, same `pattern:`/`admits:`/invariant
|
|
255
|
-
# checks, same `trusting_stored_state?` bypass on a trusted load.
|
|
256
|
-
# `attribute.type` naming neither an entity nor a value object
|
|
257
|
-
# (a `list_of(String)`, say) has no shape to rebuild into, so the
|
|
258
|
-
# element passes through unchanged, exactly as the entity branch's
|
|
259
|
-
# own non-Hash elements do.
|
|
260
|
-
#
|
|
261
|
-
# Not `Array(value).map` (unlike the entity branch above) — `value`
|
|
262
|
-
# here is not always genuinely list-shaped. `MutationApplier#
|
|
263
|
-
# removed`'s own `Value.for_attribute(aggregate, attribute, value)`
|
|
264
|
-
# call (`attribute` = the list attribute, `mutation.target`; `value`
|
|
265
|
-
# = the single remove-target argument, already a real `Value` by
|
|
266
|
-
# the time it gets here) reuses this exact branch — for `remove:`,
|
|
267
|
-
# not for a whole-list `sets`. `Array(a_real_Value)` alone would be
|
|
268
|
-
# harmless (`Value` defines neither `to_a` nor `to_ary`, so Kernel
|
|
269
|
-
# wraps it `[value]`), but `Array(a_Hash)` is not harmless: Ruby's
|
|
270
|
-
# `Array()` opens a bare Hash into its own `[[k, v], ...]` pairs,
|
|
271
|
-
# not `[hash]` — silently shredding a single-element Hash-shaped
|
|
272
|
-
# target into garbage instead of hydrating it. Branching on
|
|
273
|
-
# `value.is_a?(Array)` up front (true only for a genuine whole-list
|
|
274
|
-
# `sets`/hydrate load) keeps the single-target shape a single
|
|
275
|
-
# target, hydrated the same way, never listified.
|
|
276
|
-
#
|
|
277
|
-
# @param aggregate [Bluebook::Aggregate] the aggregate `attribute` is declared
|
|
278
|
-
# on, or a construct that does not respond to `value_object` (an entity), in
|
|
279
|
-
# which case `value` passes through unchanged
|
|
280
|
-
# @param attribute [Bluebook::Attribute] the `list_of` attribute being hydrated
|
|
281
|
-
# @param value [Array<Hash, Object>, Object] the offered value: a whole-list
|
|
282
|
-
# Array, or a single remove-target value
|
|
283
|
-
# @return [Object] `value` unchanged when `aggregate` does not respond to
|
|
284
|
-
# `value_object`, or `attribute.type` names no value object; otherwise a
|
|
285
|
-
# frozen Array of built `Value`s for a whole-list Array, or a single built
|
|
286
|
-
# `Value` (via `hydrate_value_object_element`) otherwise
|
|
102
|
+
# Branches on `value.is_a?(Array)` rather than `Array(value)`: a
|
|
103
|
+
# bare Hash-shaped single target would otherwise be shredded into
|
|
104
|
+
# its own `[[k, v], ...]` pairs instead of hydrated whole.
|
|
287
105
|
def hydrate_value_object_list(aggregate, attribute, value)
|
|
288
106
|
return value unless aggregate.respond_to?(:value_object)
|
|
289
107
|
|
|
@@ -296,19 +114,8 @@ module Hecks
|
|
|
296
114
|
Freezer.deep(hydrated)
|
|
297
115
|
end
|
|
298
116
|
|
|
299
|
-
# Rebuilds one `list_of` element into a real, validated `Value`,
|
|
300
|
-
# already is one of `value_object`'s own type.
|
|
301
|
-
#
|
|
302
|
-
# @param aggregate [Bluebook::Aggregate] the aggregate `value_object` is
|
|
303
|
-
# resolved against
|
|
304
|
-
# @param attribute [Bluebook::Attribute] the `list_of` attribute `element`
|
|
305
|
-
# belongs to
|
|
306
|
-
# @param value_object [Class] the `Bluebook::ValueObject` subclass `element`
|
|
307
|
-
# is built as
|
|
308
|
-
# @param element [Object] the raw element to build: a Hash of fields, a scalar
|
|
309
|
-
# `fields_for` can still open, or an already-built `Value`
|
|
310
|
-
# @return [Runtime::Value] `element` unchanged if it is already a `Value` of
|
|
311
|
-
# `value_object`'s own type; otherwise a freshly built one
|
|
117
|
+
# Rebuilds one `list_of` element into a real, validated `Value`,
|
|
118
|
+
# unless it already is one of `value_object`'s own type.
|
|
312
119
|
def hydrate_value_object_element(aggregate, attribute, value_object, element)
|
|
313
120
|
return element if element.is_a?(self) && element.type_name == value_object.hecks_name
|
|
314
121
|
|
data/lib/hecks/runtime/value.rb
CHANGED
|
@@ -7,14 +7,8 @@ require_relative "value/admission"
|
|
|
7
7
|
|
|
8
8
|
module Hecks
|
|
9
9
|
module Runtime
|
|
10
|
-
# A typed value object
|
|
11
|
-
#
|
|
12
|
-
# numeric types, patterns and closed sets — is the class-side engine in
|
|
13
|
-
# value/coercion.rb, value/entity_list_coercion.rb (a `list_of`
|
|
14
|
-
# attribute's own elements — split out once growing Coercion tripped
|
|
15
|
-
# Metrics/ModuleLength, see that file's own header), and
|
|
16
|
-
# value/admission.rb, extended here so the door stays where it always
|
|
17
|
-
# was: `Value.for`, `Value.build`.
|
|
10
|
+
# A typed value object: frozen fields, read by name.
|
|
11
|
+
# Construction lives in value/coercion.rb, entity_list_coercion.rb and admission.rb.
|
|
18
12
|
class Value
|
|
19
13
|
extend Coercion
|
|
20
14
|
extend EntityListCoercion
|
|
@@ -22,20 +16,7 @@ module Hecks
|
|
|
22
16
|
|
|
23
17
|
attr_reader :value_object
|
|
24
18
|
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
# `@fields.freeze` alone stops a key being added or removed and
|
|
28
|
-
# nothing else: the String, Array or Hash a field holds stays
|
|
29
|
-
# mutable, so `vo[:value] << "!"` edits a value object in place —
|
|
30
|
-
# demonstrated on a real dispatch before this was written, not
|
|
31
|
-
# supposed. Same shape as the three freezing bugs already fixed
|
|
32
|
-
# (list attributes, the event log, query rows), where the container
|
|
33
|
-
# was frozen and the contents were not.
|
|
34
|
-
#
|
|
35
|
-
# A value object is the one thing in the domain that has no
|
|
36
|
-
# identity to change over — `with` already answers a new one rather
|
|
37
|
-
# than mutating — so freezing it through is what it always claimed
|
|
38
|
-
# to be.
|
|
19
|
+
# Deep-freezes the fields so a held String, Array or Hash cannot be mutated in place.
|
|
39
20
|
#
|
|
40
21
|
# @param value_object [Bluebook::ValueObject] the declared type this instance is one of
|
|
41
22
|
# @param fields [Hash] the type's fields, keyed by name (String or Symbol); deep-frozen
|
|
@@ -103,18 +84,8 @@ module Hecks
|
|
|
103
84
|
end
|
|
104
85
|
end
|
|
105
86
|
|
|
106
|
-
# `materialize`, but a single-attribute value object
|
|
107
|
-
#
|
|
108
|
-
# field instead of building `{field: ...}` — a Board's own `label`
|
|
109
|
-
# unwraps to `"Kanban"`, not `{value: "Kanban"}`. Not a replacement
|
|
110
|
-
# for `materialize` itself: every existing report/query/command
|
|
111
|
-
# caller keeps the wrapped shape it already depends on (Banking's
|
|
112
|
-
# own `CustomerPortfolio` reads `payment[:amount][:cents]`, and
|
|
113
|
-
# changing that out from under it would be a real breaking change,
|
|
114
|
-
# not a bug fix). This is read_model_interpreter.rb's own opt-in,
|
|
115
|
-
# used only for a `group_by`-declared head's own rows — grouping
|
|
116
|
-
# needs a real scalar to key by regardless, so a report already
|
|
117
|
-
# asking for that gets the unwrap for free.
|
|
87
|
+
# `materialize`, but a single-attribute value object unwraps to its bare field.
|
|
88
|
+
# Opt-in for `group_by` rows; `materialize` keeps the wrapped shape callers depend on.
|
|
118
89
|
#
|
|
119
90
|
# @param value [Object] the value to materialize; anything that is not a `Runtime::Value`,
|
|
120
91
|
# Array or Hash passes through unchanged
|
|
@@ -127,12 +98,7 @@ module Hecks
|
|
|
127
98
|
sole = value.value_object.sole_attribute
|
|
128
99
|
return materialize_unwrapped(value[sole.name]) if sole
|
|
129
100
|
|
|
130
|
-
# Not `value.to_h
|
|
131
|
-
# plain `materialize`, so a VO nested inside a multi-attribute VO
|
|
132
|
-
# would already be a plain Hash by the time this method ever saw
|
|
133
|
-
# it, and never reach the `when self` branch above. Read each
|
|
134
|
-
# field straight off `value` instead, so recursion actually
|
|
135
|
-
# happens through this method the whole way down.
|
|
101
|
+
# Not `value.to_h`: it materializes nested values to Hashes, ending the recursion.
|
|
136
102
|
value.value_object.attributes.to_h { |attr| [attr.name, materialize_unwrapped(value[attr.name])] }
|
|
137
103
|
when Array then value.map { |item| materialize_unwrapped(item) }
|
|
138
104
|
when Hash then value.transform_values { |item| materialize_unwrapped(item) }
|
|
@@ -140,22 +106,8 @@ module Hecks
|
|
|
140
106
|
end
|
|
141
107
|
end
|
|
142
108
|
|
|
143
|
-
# Reduces an append-only sub-log to its current state
|
|
144
|
-
#
|
|
145
|
-
# already performs replaying an aggregate's own command history
|
|
146
|
-
# into its current attributes, applied here to a single `list_of`
|
|
147
|
-
# field acting as its own miniature append-only log (a placement
|
|
148
|
-
# history, a tombstone-style soft-delete list, a versioned
|
|
149
|
-
# setting). `rows` is what a `list_of` attribute hands back — an
|
|
150
|
-
# Array of `Value`, in append order — and `key` names the field
|
|
151
|
-
# that identifies "the same logical thing" across entries.
|
|
152
|
-
#
|
|
153
|
-
# **Grouping only, never interpretation**. What counts as "removed,"
|
|
154
|
-
# how to order what survives — that meaning belongs to whichever
|
|
155
|
-
# domain declared the field, never here: a generic reduction that
|
|
156
|
-
# started guessing domain semantics would need to keep guessing
|
|
157
|
-
# forever, once per shape of "gone" any caller ever invents. The
|
|
158
|
-
# caller filters and sorts the result; this only groups it.
|
|
109
|
+
# Reduces an append-only `list_of` sub-log to its current state: the latest row per `key`.
|
|
110
|
+
# Grouping only; what counts as removed, and the ordering, belong to the caller.
|
|
159
111
|
#
|
|
160
112
|
# @param rows [Array<Runtime::Value>] a `list_of` attribute's own elements, in append order
|
|
161
113
|
# @param key [Symbol] the method to call on each row to find "the same logical thing"
|
|
@@ -169,21 +121,8 @@ module Hecks
|
|
|
169
121
|
def method_missing(name, *args)
|
|
170
122
|
return @fields[name] if @fields.key?(name)
|
|
171
123
|
|
|
172
|
-
#
|
|
173
|
-
#
|
|
174
|
-
# attribute is actually named — a single-attribute value object
|
|
175
|
-
# is a name for a scalar, not a genuine group
|
|
176
|
-
# ([[feedback_name_the_scalar_field]], `Behaviour::ValueObject#
|
|
177
|
-
# sole_attribute`), so `money.value` reads `Money`'s own `amount`
|
|
178
|
-
# exactly as `label.value` reads a shorthand-declared `value`.
|
|
179
|
-
# After the real-field lookup above, on purpose: a field
|
|
180
|
-
# literally named `value` is already answered there (and is the
|
|
181
|
-
# sole attribute whenever the count is one), so this branch only
|
|
182
|
-
# ever aliases, never shadows. A multi-attribute value object
|
|
183
|
-
# keeps its NoMethodError — `sole_attribute` answers nil for it,
|
|
184
|
-
# and falling through to `super` is exactly the refusal it
|
|
185
|
-
# always gave: with two or more fields there is no single value
|
|
186
|
-
# `.value` could honestly mean.
|
|
124
|
+
# `.value` aliases the sole field of a single-attribute value object; after the real-field
|
|
125
|
+
# lookup so a field literally named `value` is never shadowed.
|
|
187
126
|
if name == :value
|
|
188
127
|
sole = @value_object.sole_attribute
|
|
189
128
|
return @fields[sole.name] if sole
|
|
@@ -201,19 +140,8 @@ module Hecks
|
|
|
201
140
|
|
|
202
141
|
private
|
|
203
142
|
|
|
204
|
-
#
|
|
205
|
-
#
|
|
206
|
-
# `[]`/`key?`/`with`: `:value` names a single-attribute value
|
|
207
|
-
# object's sole field whatever that field is actually called. A
|
|
208
|
-
# real key always wins first (a field literally named `value` is
|
|
209
|
-
# its own answer, and is the sole attribute anyway whenever the
|
|
210
|
-
# count is one), so this only ever resolves a `:value` that would
|
|
211
|
-
# otherwise miss — it can never redirect a genuine field read.
|
|
212
|
-
# `with(:value, x)` in particular needs this: merging a literal
|
|
213
|
-
# `:value` key beside a sole field named `amount` would build a
|
|
214
|
-
# two-key hash for a one-field shape and be refused (or worse,
|
|
215
|
-
# stored) downstream — aliasing at the merge is what keeps the
|
|
216
|
-
# write half of the rule as true as the read half.
|
|
143
|
+
# Resolves `:value` to the sole field's name so `[]`, `key?`, `with` match `method_missing`.
|
|
144
|
+
# A real key always wins.
|
|
217
145
|
def resolve_field(field)
|
|
218
146
|
sym = field.to_sym
|
|
219
147
|
return sym if @fields.key?(sym)
|
data/lib/hecks/runtime.rb
CHANGED
|
@@ -1,33 +1,7 @@
|
|
|
1
1
|
# Hecks::Runtime
|
|
2
2
|
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
# required each file by hand, and the runtime's own state — the registry a
|
|
6
|
-
# declaration is being collected into — sat on the top-level Hecks module
|
|
7
|
-
# beside the DSL words.
|
|
8
|
-
#
|
|
9
|
-
# What lives here is what runs a domain :
|
|
10
|
-
#
|
|
11
|
-
# Runtime.boot(path) load a directory and return its Dispatcher
|
|
12
|
-
# Runtime.with_registry(r) bind the ambient registry for the duration of a load
|
|
13
|
-
# Runtime.current_registry the registry a declaration is landing in, or nil
|
|
14
|
-
#
|
|
15
|
-
# What does not live here is what declares one — `Hecks.bluebook`,
|
|
16
|
-
# `.hecksagon`, `.port`, `.adapter`, `.world` are loading words and stay on the
|
|
17
|
-
# top-level module, which now reads as a facade over this.
|
|
18
|
-
#
|
|
19
|
-
# runtime = Hecks::Runtime.boot("examples/pizzas/bluebook")
|
|
20
|
-
# runtime.dispatch("Pizzas::Pizza.CreatePizza", name: "Margherita")
|
|
21
|
-
#
|
|
22
|
-
# Note, and it is the reason this file exists : `current_registry` is still
|
|
23
|
-
# process-global. Each boot builds a fresh Registry, and `Loader.bind_runtime`
|
|
24
|
-
# installs a fresh facade door whose modules close over that boot's dispatcher
|
|
25
|
-
# — no class-level runtime binding remains, so two boots in one process no
|
|
26
|
-
# longer share dispatch state, only the top-level name (the last-bound door
|
|
27
|
-
# wins the constant, which is what per-boot install means). Owning the state
|
|
28
|
-
# here was the first move ; the dispatcher reachable per-runtime rather than
|
|
29
|
-
# through a constant was the second, and it is done — the door is the only
|
|
30
|
-
# constant left, and it is a projection, not the runtime.
|
|
3
|
+
# Boots a domain directory and holds the ambient registry and caller state a boot runs under.
|
|
4
|
+
# `current_registry` is process-global; each boot's dispatcher is per-boot.
|
|
31
5
|
|
|
32
6
|
require_relative "runtime/event"
|
|
33
7
|
require_relative "runtime/value"
|
|
@@ -55,41 +29,33 @@ require_relative "runtime/tenant_check"
|
|
|
55
29
|
require_relative "runtime/loader"
|
|
56
30
|
|
|
57
31
|
module Hecks
|
|
58
|
-
#
|
|
59
|
-
# here (rather than documented in place) only because the
|
|
60
|
-
# `require_relative` calls above must run before Ruby reopens the
|
|
61
|
-
# module they populate.
|
|
32
|
+
# The runtime layer: boots a domain directory and holds the ambient registry a boot runs under.
|
|
62
33
|
module Runtime
|
|
63
34
|
class << self
|
|
64
|
-
# The registry declarations are currently landing in, or nil outside a
|
|
65
|
-
# boot. Read by the DSL collectors on the top-level module and by the
|
|
66
|
-
# extraction port.
|
|
35
|
+
# The registry declarations are currently landing in, or nil outside a boot.
|
|
67
36
|
attr_reader :current_registry
|
|
68
37
|
|
|
69
|
-
#
|
|
70
|
-
#
|
|
38
|
+
# Loads a bluebook directory and returns the Dispatcher bound to it. See Loader.boot.
|
|
39
|
+
#
|
|
40
|
+
# Hecks::Runtime.boot("examples/pizzas/bluebook")
|
|
41
|
+
# .dispatch("Pizzas::Pizza.CreatePizza", name: "Margherita")
|
|
71
42
|
#
|
|
72
43
|
# @param path [String] path to a domain directory, or a file inside one
|
|
73
|
-
# @param shared [String, nil] a shared-root override
|
|
74
|
-
# @param install_facade [Boolean] whether to install the
|
|
75
|
-
#
|
|
76
|
-
# @param environment [String, nil] the environment name passed through to
|
|
77
|
-
# `Adapters::Folder#load_domain`
|
|
44
|
+
# @param shared [String, nil] a shared-root override
|
|
45
|
+
# @param install_facade [Boolean] whether to install the Ruby facade constants
|
|
46
|
+
# @param environment [String, nil] the environment name for `Adapters::Folder#load_domain`
|
|
78
47
|
# @return [Runtime::Dispatcher, Runtime::RemoteDispatcher] the dispatcher bound
|
|
79
48
|
# to the booted domain
|
|
80
49
|
def boot(path, shared: nil, install_facade: true, environment: nil)
|
|
81
50
|
Loader.boot(path, shared: shared, install_facade: install_facade, environment: environment)
|
|
82
51
|
end
|
|
83
52
|
|
|
84
|
-
#
|
|
53
|
+
# Loads only the given files of a domain; otherwise like `boot`. See Loader.boot_files.
|
|
85
54
|
#
|
|
86
55
|
# @param paths [String, Array<String>] one or more file paths within the domain
|
|
87
|
-
#
|
|
88
|
-
# @param
|
|
89
|
-
# @param
|
|
90
|
-
# Ruby facade constants for this boot
|
|
91
|
-
# @param environment [String, nil] the environment name passed through to the
|
|
92
|
-
# selected-file loader
|
|
56
|
+
# @param shared [String, nil] a shared-root override
|
|
57
|
+
# @param install_facade [Boolean] whether to install the Ruby facade constants
|
|
58
|
+
# @param environment [String, nil] the environment name for the selected-file loader
|
|
93
59
|
# @return [Runtime::Dispatcher, Runtime::RemoteDispatcher] the dispatcher bound
|
|
94
60
|
# to the booted domain
|
|
95
61
|
def boot_files(paths, shared: nil, install_facade: true, environment: nil)
|
|
@@ -110,23 +76,9 @@ module Hecks
|
|
|
110
76
|
@current_registry = previous
|
|
111
77
|
end
|
|
112
78
|
|
|
113
|
-
#
|
|
114
|
-
#
|
|
115
|
-
# against.
|
|
116
|
-
#
|
|
117
|
-
# `as_of:` is optional, same opt-in shape as `actor_id:` — a caller
|
|
118
|
-
# that wants a Governance `RoleAssignment`'s `starts_at` enforced
|
|
119
|
-
# passes `as_of: Ports::Clock.now(registry)` here, at the door,
|
|
120
|
-
# exactly where `cli_runner.rb` already merges `Clock.now` into a
|
|
121
|
-
# command's own args. Nothing on the dispatch path calls the clock
|
|
122
|
-
# itself — see `Ports::Clock`'s own header for why — so an unbound
|
|
123
|
-
# `as_of` leaves `starts_at` unchecked, exactly as before.
|
|
79
|
+
# Binds the ambient caller (see Runtime::Caller) for the duration of the block.
|
|
80
|
+
# A command's declared `role` is checked against it.
|
|
124
81
|
#
|
|
125
|
-
# `scope:` is optional too — a caller that states which scope it is
|
|
126
|
-
# acting in gets that scope checked against the matching
|
|
127
|
-
# `RoleAssignment`'s own `scope`, not just its `role_name`. See
|
|
128
|
-
# `Runtime::Caller::Current`'s own header for why this lives here
|
|
129
|
-
# rather than as a command-level DSL construct.
|
|
130
82
|
# @param role [String, Symbol] the role to check the caller against
|
|
131
83
|
# @param actor_id [String, nil] who is calling, checked against a real Governance
|
|
132
84
|
# `RoleAssignment` when given; string-equality only against `role` when nil
|