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
|
@@ -2,50 +2,22 @@ module Hecks
|
|
|
2
2
|
module Bluebook
|
|
3
3
|
module DSL
|
|
4
4
|
class AggregateBuilder
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
# lifecycle) is otherwise in place, checking that what a command,
|
|
8
|
-
# query, or default names actually exists elsewhere on the
|
|
9
|
-
# aggregate. Split out of aggregate_builder.rb (which keeps the
|
|
10
|
-
# DSL surface itself — attribute/command/query/policy declaration
|
|
11
|
-
# — and the smaller drain_pending!/identity bookkeeping) because
|
|
12
|
-
# this cluster is one cohesive concern: cross-field validation
|
|
13
|
-
# that can only run after every declaration is real, the same
|
|
14
|
-
# relationship BluebookBuilder's own `self.validate_*` cluster has
|
|
15
|
-
# to its chapter (see that file's own header for the parallel).
|
|
16
|
-
# `include`d back into AggregateBuilder, same pattern as
|
|
17
|
-
# `Runtime::Registry`'s own `include Verification` /
|
|
18
|
-
# `include SagaPersistence` — same class, its private instance
|
|
19
|
-
# methods, just filed by responsibility across files.
|
|
5
|
+
# Build-time checks that what a command, query, or default names exists on the aggregate.
|
|
6
|
+
# Included into AggregateBuilder; `#build` runs them once every declaration is in place.
|
|
20
7
|
module Sealing
|
|
21
8
|
private
|
|
22
9
|
|
|
23
|
-
#
|
|
24
|
-
# find the chapter and resolve its target.
|
|
10
|
+
# Tells every reference which aggregate declares it, so it can resolve its target.
|
|
25
11
|
#
|
|
26
|
-
# Stamped
|
|
27
|
-
#
|
|
28
|
-
# deliberately across every list that can carry one — a reference the walk
|
|
29
|
-
# missed would resolve to nil, and `resolve_references` skips a nil target,
|
|
30
|
-
# so the guarantee would go quiet instead of going red. That is the exact
|
|
31
|
-
# shape of the bug that let an Account belong to an unregistered customer
|
|
32
|
-
# fourteen times over.
|
|
12
|
+
# Stamped at build because a command builder does not hold the aggregate. Walks every
|
|
13
|
+
# list that can carry a reference: a missed one resolves to nil and is silently skipped.
|
|
33
14
|
def stamp_references(aggregate)
|
|
34
15
|
reference_bearing_attributes.each { |attribute| attribute.type.declared_in = aggregate }
|
|
35
16
|
end
|
|
36
17
|
|
|
37
|
-
# An owned piece's
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
# -> Board::Card -> Product -> Board) is the same "no boundary
|
|
41
|
-
# anyone can reason about alone" `validate_no_bidirectional_
|
|
42
|
-
# references!` already refuses for a direct aggregate-to-
|
|
43
|
-
# aggregate ring; it was invisible before this because only
|
|
44
|
-
# `AggregateBuilder#reference_to` ever fed `@reference_targets`,
|
|
45
|
-
# never `EntityBuilder#reference_to`. Command/query reference
|
|
46
|
-
# arguments are deliberately excluded — they are data flowing
|
|
47
|
-
# through a dispatch, not persisted state the graph a cycle
|
|
48
|
-
# means anything over.
|
|
18
|
+
# An owned piece's `reference_to` is an edge the aggregate points across too, so a ring
|
|
19
|
+
# through a contained piece is refused like a direct aggregate-to-aggregate ring.
|
|
20
|
+
# Command/query reference arguments are excluded: they are dispatch data, not state.
|
|
49
21
|
def entity_reference_targets
|
|
50
22
|
@entities.flat_map { |entity| entity.attributes.select(&:reference?).map { |a| a.type.target_name.to_s } }
|
|
51
23
|
end
|
|
@@ -61,51 +33,12 @@ module Hecks
|
|
|
61
33
|
lists.flatten.select(&:reference?)
|
|
62
34
|
end
|
|
63
35
|
|
|
64
|
-
# A mutation must name a field the aggregate actually has.
|
|
65
|
-
#
|
|
66
|
-
# Not moved to the language, and deliberately so. The language says only
|
|
67
|
-
# `given("a mutation names a target") { !target.value.to_s.empty? }` —
|
|
68
|
-
# non-emptiness — because saying more means reaching a list that lives on
|
|
69
|
-
# a different root : a command's changes hang off Command, the fields they
|
|
70
|
-
# name hang off Aggregate, and a given is a closed predicate over its own
|
|
71
|
-
# state. Aggregate.Seal is the right shape and cannot see commands ; the
|
|
72
|
-
# reference trick that rescued "attributes use value-object types" needs a
|
|
73
|
-
# root to point at, and an aggregate's fields are a value-object list, not
|
|
74
|
-
# roots. This is the second rule that cannot port for that reason — the
|
|
75
|
-
# first is read-model uniqueness — and both wait on the same thing : a
|
|
76
|
-
# quantifier, or fields promoted to roots.
|
|
77
|
-
#
|
|
78
|
-
# So it lives here, at build, where every declaration is present. Found by
|
|
79
|
-
# writing `then_set :disputed_by` on CardPayment before the field existed :
|
|
80
|
-
# it wrote into nothing, refused nothing, and every check stayed green.
|
|
81
36
|
# A default fills the shape it is declared on, or it fills nothing.
|
|
82
37
|
#
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
# pass its fields as an object" — because the value object wants its
|
|
86
|
-
# fields and got a bare string. The bluebook is wrong at the line where
|
|
87
|
-
# it is written and says so nowhere near it.
|
|
88
|
-
#
|
|
89
|
-
# It cost a corpus member 33 refusals out of 40 steps, with every gate
|
|
90
|
-
# green throughout: the refusals were perfectly consistent, which is
|
|
91
|
-
# consistency about nothing. `till.bluebook` has always had the right shape
|
|
92
|
-
# — `default: { cents: 0 }`.
|
|
93
|
-
#
|
|
94
|
-
# A primitive takes a scalar and a value object takes its fields, so the
|
|
95
|
-
# test is simply which one the type names. Nothing here guesses at the
|
|
96
|
-
# keys: a default that is a Hash is left to `Value.for_attribute`, which
|
|
97
|
-
# is where a wrong field belongs.
|
|
38
|
+
# A bare default on a value-object attribute builds cleanly and then refuses every
|
|
39
|
+
# create at dispatch. A Hash default is left to `Value.for_attribute`.
|
|
98
40
|
def seal_defaults
|
|
99
|
-
#
|
|
100
|
-
# this method's own comment names: an inline `one_of(...)`
|
|
101
|
-
# synthesises its value object through `closed_sets`
|
|
102
|
-
# (AttributeCollector#synthesise_closed_set), never installed
|
|
103
|
-
# into `@value_objects` until `#build` merges them (see
|
|
104
|
-
# `#build`'s own `@value_objects + closed_sets`, and
|
|
105
|
-
# `declared_value_object`'s identical merge). Checking
|
|
106
|
-
# `@value_objects` alone made this exact attribute — a bare
|
|
107
|
-
# default on an inline closed set — invisible to the one
|
|
108
|
-
# check meant to catch it.
|
|
41
|
+
# closed_sets too: an inline `one_of(...)` lives there until `#build` merges it.
|
|
109
42
|
shapes = (@value_objects + closed_sets).map { |shape| shape.hecks_name.to_s }
|
|
110
43
|
|
|
111
44
|
attributes.each do |attribute|
|
|
@@ -119,11 +52,7 @@ module Hecks
|
|
|
119
52
|
end
|
|
120
53
|
end
|
|
121
54
|
|
|
122
|
-
# A command's `from:` guard needs a lifecycle field to check
|
|
123
|
-
# against — declared at build time (S10, ADR 0025), the same
|
|
124
|
-
# point every other "does this actually resolve" check in this
|
|
125
|
-
# file runs, rather than left to crash `enforce_lifecycle_
|
|
126
|
-
# guard` the first time such a command is ever dispatched.
|
|
55
|
+
# A command's `from:` guard needs a lifecycle field to check against.
|
|
127
56
|
def seal_lifecycle_guards
|
|
128
57
|
return if @lifecycle
|
|
129
58
|
|
|
@@ -137,15 +66,9 @@ module Hecks
|
|
|
137
66
|
end
|
|
138
67
|
end
|
|
139
68
|
|
|
140
|
-
# `projects`
|
|
141
|
-
#
|
|
142
|
-
#
|
|
143
|
-
# `name` must not collide with an attribute already declared
|
|
144
|
-
# (a projected field is its own kind of field, never a second
|
|
145
|
-
# spelling of one that already exists). The target aggregate's
|
|
146
|
-
# own field is checked separately, once every aggregate in the
|
|
147
|
-
# chapter is real — see BluebookBuilder#validate_projected_
|
|
148
|
-
# fields!'s own comment for why that half cannot happen here.
|
|
69
|
+
# The local half of `projects` resolution: `reference` must name a reference attribute
|
|
70
|
+
# here and `name` must not collide with a declared attribute. The target aggregate's
|
|
71
|
+
# field is checked later by BluebookBuilder, once the whole chapter exists.
|
|
149
72
|
def seal_projected_fields
|
|
150
73
|
declared = attributes.map { |attribute| attribute.name.to_sym }
|
|
151
74
|
|
|
@@ -166,31 +89,22 @@ module Hecks
|
|
|
166
89
|
end
|
|
167
90
|
end
|
|
168
91
|
|
|
92
|
+
# A mutation must name a field the aggregate actually has.
|
|
93
|
+
#
|
|
94
|
+
# Lives here, not in the language: a command's changes and the aggregate's fields hang
|
|
95
|
+
# off different roots, and a given is a closed predicate over its own state.
|
|
169
96
|
def seal_mutation_targets
|
|
170
97
|
known = attributes.map { |attribute| attribute.name.to_sym }
|
|
171
98
|
known << @lifecycle.field.to_sym if @lifecycle
|
|
172
99
|
|
|
173
100
|
@commands.each do |command|
|
|
174
101
|
command.mutations.each do |mutation|
|
|
175
|
-
#
|
|
176
|
-
#
|
|
177
|
-
# names an "Entity.Command" pair instead, checked when the
|
|
178
|
-
# command builds (`delegates_to`'s own `rpartition` guard)
|
|
179
|
-
# and again at dispatch time (`CommandInterpreter
|
|
180
|
-
# #step_delegate_to_entity`, which refuses a real one that
|
|
181
|
-
# names no such entity or command). Sealing this check
|
|
182
|
-
# against it would refuse every delegating command outright.
|
|
183
|
-
# `:corrects` — CommandBuilder#corrects_impl's own comment —
|
|
184
|
-
# targets an event name, not a field either; checked instead
|
|
185
|
-
# by `seal_correction_targets`, below.
|
|
102
|
+
# :delegate targets an "Entity.Command" pair and :corrects an event name, not a
|
|
103
|
+
# field; the latter is checked by `seal_correction_targets`.
|
|
186
104
|
next if [:delegate, :corrects].include?(mutation.op)
|
|
187
105
|
|
|
188
|
-
# C5.3
|
|
189
|
-
#
|
|
190
|
-
# would be overwritten by any transition and bypass the
|
|
191
|
-
# state machine otherwise. Refused at build — except for
|
|
192
|
-
# frozen era text (`MetaValidator.shadow_parsing?`), which
|
|
193
|
-
# is history and must keep parsing as the language tightens.
|
|
106
|
+
# The lifecycle field moves only by transition (C5.3). Frozen era text is exempt
|
|
107
|
+
# (`MetaValidator.shadow_parsing?`) so it keeps parsing.
|
|
194
108
|
if @lifecycle && mutation.target.to_sym == @lifecycle.field.to_sym && !MetaValidator.shadow_parsing?
|
|
195
109
|
raise Malformed,
|
|
196
110
|
"#{@name}.#{command.hecks_name} sets #{mutation.target}, #{@name}'s lifecycle field — " \
|
|
@@ -206,50 +120,11 @@ module Hecks
|
|
|
206
120
|
end
|
|
207
121
|
end
|
|
208
122
|
|
|
209
|
-
# `corrects`
|
|
210
|
-
#
|
|
211
|
-
#
|
|
212
|
-
# itself — a command cannot see its own siblings' `emits` while
|
|
213
|
-
# it is still being built). Two things are checked:
|
|
214
|
-
#
|
|
215
|
-
# 1. The named event must be something a sibling command here
|
|
216
|
-
# actually `emits` — naming an event nothing in this aggregate
|
|
217
|
-
# ever announces is a build-time authoring error. (Whether
|
|
218
|
-
# this record has actually emitted it yet is the dispatch-time
|
|
219
|
-
# half — CommandRules::Admissibility#enforce_correction_target.)
|
|
123
|
+
# Checks `corrects` once every sibling command is known: the named event must be emitted
|
|
124
|
+
# by a command on this aggregate, and `reverses: true` needs every source mutation to be
|
|
125
|
+
# an increment/decrement, the only ops invertible without runtime data.
|
|
220
126
|
#
|
|
221
|
-
#
|
|
222
|
-
# original command's own mutations, rather than the author
|
|
223
|
-
# writing them — but only when every one of those mutations is
|
|
224
|
-
# structurally invertible with no runtime data: increment/
|
|
225
|
-
# decrement, same argument, opposite verb (`sign_for`'s own
|
|
226
|
-
# +1/-1 pair — CommandRules::Arithmetic applies `current +
|
|
227
|
-
# sign * amount`, so the same source with the opposite sign
|
|
228
|
-
# undoes it exactly). Nothing else qualifies today: `set` has
|
|
229
|
-
# no such rule at all — inverting it needs the specific prior
|
|
230
|
-
# value at the moment the original fired, which is per-
|
|
231
|
-
# instance runtime data no build-time derivation can have;
|
|
232
|
-
# `multiply`/`clamp` are lossy by design (a clamped value's
|
|
233
|
-
# own pre-clamp magnitude is not recoverable from the mutation
|
|
234
|
-
# at all); `append`/`remove` look symmetric but are not
|
|
235
|
-
# reliably so — `append`'s source is a per-field binding hash
|
|
236
|
-
# (`append: { name: :name, amount: :amount }`), `remove`'s is
|
|
237
|
-
# a single resolved value to match by equality
|
|
238
|
-
# (MutationApplier#removed), and collapsing one shape into the
|
|
239
|
-
# other correctly needs the target list's own value-object
|
|
240
|
-
# field names, not just the mutation's own recorded shape — a
|
|
241
|
-
# real gap, left for a follow-on round rather than guessed at
|
|
242
|
-
# here. Refuses rather than silently deriving something wrong
|
|
243
|
-
# — see docs/decisions/ for the ADR that draws this exact
|
|
244
|
-
# line.
|
|
245
|
-
# One closed cluster of `corrects`/`reverses: true` rules, run
|
|
246
|
-
# in sequence against one command at a time (emission exists,
|
|
247
|
-
# reverses/own-sets conflict, invertibility, then the actual
|
|
248
|
-
# derivation) — each `raise` gates the next check for that
|
|
249
|
-
# command, and `inverse_op`/`emitted_by` are shared read-only
|
|
250
|
-
# lookups built once up front. Splitting the per-command body
|
|
251
|
-
# out would still need all of `command`/`event`/`sources`/
|
|
252
|
-
# `inverse_op` passed in, for no clearer a result.
|
|
127
|
+
# One cluster of sequential rules against one command, each `raise` gating the next.
|
|
253
128
|
# rubocop:disable-next Metrics/AbcSize
|
|
254
129
|
# rubocop:disable-next Metrics/CyclomaticComplexity
|
|
255
130
|
# rubocop:disable-next Metrics/PerceivedComplexity
|
|
@@ -299,22 +174,11 @@ module Hecks
|
|
|
299
174
|
end
|
|
300
175
|
end
|
|
301
176
|
|
|
302
|
-
# A query must ask about a field the aggregate
|
|
303
|
-
#
|
|
304
|
-
#
|
|
305
|
-
#
|
|
306
|
-
#
|
|
307
|
-
# member (QuerySpecification::FieldPath is the one walk every engine
|
|
308
|
-
# now shares) — landing on a value object hands SQL a JSON object
|
|
309
|
-
# where the reference interpreter unwraps a hash. An ordered
|
|
310
|
-
# comparator (lt/gt/gte/lte) must land on a numeric leaf — over text
|
|
311
|
-
# the reference interpreter quietly matches no rows while SQL
|
|
312
|
-
# compares lexicographically. And a :symbol value must name one of
|
|
313
|
-
# the query's own declared arguments, or it resolves to nil at
|
|
314
|
-
# dispatch and matches nothing.
|
|
315
|
-
# `private` above has no effect on a constant (Ruby constants are
|
|
316
|
-
# always resolvable through their lexical scope); kept here anyway,
|
|
317
|
-
# beside the method that actually reads it, for the narrative.
|
|
177
|
+
# A query must ask about a field the aggregate has. A dotted path must land on a scalar
|
|
178
|
+
# member, an ordered comparator (lt/gt/gte/lte) on a numeric leaf, and a :symbol value
|
|
179
|
+
# must name one of the query's own arguments; else engines disagree or match nothing.
|
|
180
|
+
#
|
|
181
|
+
# `private` does not apply to constants; this sits beside the method that reads it.
|
|
318
182
|
# rubocop:disable-next Lint/UselessConstantScoping
|
|
319
183
|
ORDERED_COMPARATORS = %i[lt lte gt gte].freeze
|
|
320
184
|
|
|
@@ -339,18 +203,11 @@ module Hecks
|
|
|
339
203
|
@entities.map { |entity| ["#{@name}::#{entity.hecks_name}", entity.attributes, entity.lifecycle, entity.queries] }
|
|
340
204
|
end
|
|
341
205
|
|
|
342
|
-
# `/` crosses into another record
|
|
343
|
-
#
|
|
344
|
-
#
|
|
345
|
-
#
|
|
346
|
-
#
|
|
347
|
-
# one would also have tried to resolve as a local dotted walk.
|
|
348
|
-
# A closed decision tree over where one field can resolve —
|
|
349
|
-
# hop, local scalar, lifecycle field, value object (refused),
|
|
350
|
-
# or nothing (refused) — see the doc comment above (and the
|
|
351
|
-
# method-level comments on the hop/ordering split) for why each
|
|
352
|
-
# branch exists. Every branch already reads as its own named
|
|
353
|
-
# rule; extracting pieces would just relocate them.
|
|
206
|
+
# `/` crosses into another record and `.` walks fields inside this one, so a hop is
|
|
207
|
+
# routed to `seal_query_hop` before any `.`-splitting.
|
|
208
|
+
#
|
|
209
|
+
# A closed decision tree over where a field can resolve: hop, local scalar, lifecycle
|
|
210
|
+
# field, value object (refused), or nothing (refused).
|
|
354
211
|
# rubocop:disable-next Metrics/CyclomaticComplexity
|
|
355
212
|
# rubocop:disable-next Metrics/PerceivedComplexity
|
|
356
213
|
def seal_query_field(owner, query, fields, lifecycle, field, ordering: false)
|
|
@@ -378,25 +235,11 @@ module Hecks
|
|
|
378
235
|
"matches nothing and refuses nothing"
|
|
379
236
|
end
|
|
380
237
|
|
|
381
|
-
# ORDER BY refuses a hop outright
|
|
382
|
-
# hop (deferred below), this doesn't need the target's shape to
|
|
383
|
-
# answer: an ask is ordered by what its own answering rows
|
|
384
|
-
# hold, and a hop answers with a candidate set, not a sort key
|
|
385
|
-
# (see Runtime::ReferenceHop).
|
|
238
|
+
# ORDER BY refuses a hop outright: a hop answers with a candidate set, not a sort key.
|
|
386
239
|
#
|
|
387
|
-
# A where hop is only recognised here
|
|
388
|
-
#
|
|
389
|
-
#
|
|
390
|
-
# declaration. What it points at is not: stamp_references has
|
|
391
|
-
# already run by this point, but the chapter (Bluebook, and the
|
|
392
|
-
# owning aggregate's own place in it) does not exist yet, so
|
|
393
|
-
# Reference#resolve would answer nil for every target in the
|
|
394
|
-
# file, including ones declared above this one. The tail, and
|
|
395
|
-
# whether the target even exists, are BluebookBuilder's
|
|
396
|
-
# business — see validate_query_hops!, which runs once the
|
|
397
|
-
# chapter is real, for exactly the reason
|
|
398
|
-
# validate_no_bidirectional_references! already gives for
|
|
399
|
-
# living at that same later point.
|
|
240
|
+
# A where hop is only recognised here. Its head must be one of this aggregate's own
|
|
241
|
+
# references, but the target cannot resolve before the chapter exists, so
|
|
242
|
+
# BluebookBuilder#validate_query_hops! checks the tail and the target later.
|
|
400
243
|
def seal_query_hop(owner, query, fields, field, ordering:)
|
|
401
244
|
unless QuerySpecification::HopPath.hop_head?(field, fields)
|
|
402
245
|
raise Malformed,
|
|
@@ -416,14 +259,8 @@ module Hecks
|
|
|
416
259
|
def seal_ordered_comparator(owner, query, fields, clause)
|
|
417
260
|
return unless ORDERED_COMPARATORS.include?(clause.op.to_s.to_sym)
|
|
418
261
|
|
|
419
|
-
# A where
|
|
420
|
-
#
|
|
421
|
-
# unlike ORDER BY (refused outright in seal_query_field, see
|
|
422
|
-
# its own comment), a where-clause hop answers a real
|
|
423
|
-
# candidate set either way, ordered or not. Deferred for the
|
|
424
|
-
# same reason any other hop is: whether the tail is even
|
|
425
|
-
# numeric is BluebookBuilder#validate_query_hops!'s question
|
|
426
|
-
# to ask of the target's shape, not this aggregate's own.
|
|
262
|
+
# A where hop with an ordered comparator is legitimate; whether its tail is numeric
|
|
263
|
+
# is BluebookBuilder#validate_query_hops!'s question, so it is deferred.
|
|
427
264
|
return if clause.field.to_s.include?("/") && QuerySpecification::HopPath.hop_head?(clause.field, fields)
|
|
428
265
|
|
|
429
266
|
name, *nested = clause.field.to_s.split(".")
|
|
@@ -448,12 +285,9 @@ module Hecks
|
|
|
448
285
|
"resolves to nil and matches nothing"
|
|
449
286
|
end
|
|
450
287
|
|
|
451
|
-
# A symbolic right-hand side is a query input
|
|
452
|
-
#
|
|
453
|
-
#
|
|
454
|
-
# Reference hops are resolved only after the whole chapter has been
|
|
455
|
-
# owner-stamped; BluebookBuilder performs the identical inference for
|
|
456
|
-
# those deferred paths.
|
|
288
|
+
# A symbolic right-hand side is a query input; when the compared path lands on this
|
|
289
|
+
# owner's shape its type is known, so no `attribute` line is needed. Reference hops
|
|
290
|
+
# are inferred later by BluebookBuilder, once the chapter is owner-stamped.
|
|
457
291
|
def infer_local_query_argument(query, fields, lifecycle, clause)
|
|
458
292
|
name = clause.value
|
|
459
293
|
return unless name.is_a?(Symbol)
|
|
@@ -473,24 +307,11 @@ module Hecks
|
|
|
473
307
|
query.attributes << leaf if leaf
|
|
474
308
|
end
|
|
475
309
|
|
|
476
|
-
# A bare field naming a value object
|
|
477
|
-
#
|
|
478
|
-
# already refuses a path that lands on a value object rather than
|
|
479
|
-
# a scalar; a bare name was returning unconditionally, so
|
|
480
|
-
# `where(frequency: ...)` against a StatementFrequency
|
|
481
|
-
# (cadence, retention_months, paper_fee_cents) compiled — and the
|
|
482
|
-
# engines then disagreed about which member it meant, one taking
|
|
483
|
-
# the first numeric and another declining to unwrap at all.
|
|
484
|
-
#
|
|
485
|
-
# Unambiguous is: exactly one member, whatever its type, or
|
|
486
|
-
# exactly one numeric member among several (Money's `cents`
|
|
487
|
-
# beside its `currency` — the reading every engine already
|
|
488
|
-
# shared, and what the corpus relies on). Anything else names
|
|
489
|
-
# its member with a dotted path, which already works.
|
|
310
|
+
# A bare field naming a value object must say which member it means when several could
|
|
311
|
+
# answer; otherwise engines disagree (first numeric member vs. no unwrap at all).
|
|
490
312
|
#
|
|
491
|
-
#
|
|
492
|
-
# membership, not a scalar comparison
|
|
493
|
-
# reading across the engines.
|
|
313
|
+
# Unambiguous is exactly one member, or exactly one numeric member among several.
|
|
314
|
+
# A list is exempt: `contains` reads element membership, not a scalar comparison.
|
|
494
315
|
def refuse_ambiguous_comparison!(owner, query, field, attribute)
|
|
495
316
|
return if attribute.list?
|
|
496
317
|
|