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
|
@@ -1,31 +1,13 @@
|
|
|
1
1
|
module Hecks
|
|
2
2
|
module Bluebook
|
|
3
3
|
class Assembly
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
# `to_h` spells things as text so the export stands on its own, and every
|
|
7
|
-
# one of those spellings has to come back apart here. This is the same family
|
|
8
|
-
# of work `MetaValidator::Shapes` does for the reconstruction — the difference
|
|
9
|
-
# is that Shapes rebuilds hashes and this rebuilds objects, so it has to
|
|
10
|
-
# recover types rather than just strings.
|
|
11
|
-
#
|
|
12
|
-
# Encoding losses are the largest family of bug in this codebase, and every
|
|
13
|
-
# member has the same shape: reading an object where `to_h` holds a spelling.
|
|
14
|
-
# So each method below names the spelling it inverts.
|
|
4
|
+
# Reads the leaf shapes of an assembly's `to_h` export back into IR objects.
|
|
5
|
+
# Each method inverts one textual spelling, so types are recovered, not just strings.
|
|
15
6
|
module Marks
|
|
16
7
|
module_function
|
|
17
8
|
|
|
18
9
|
# `Attribute#to_h` spells a type with `to_s`, so a reference arrives as
|
|
19
|
-
# "Reference<Customer>" and has to become an edge again.
|
|
20
|
-
# a name and stays one.
|
|
21
|
-
#
|
|
22
|
-
# @param field [Hash{Symbol => Object}] one attribute's declared row, keyed
|
|
23
|
-
# `:type` (String, a plain type name or `"Reference<Target>"`), `:name`
|
|
24
|
-
# (String), `:list` and `:optional` (read as truthy), `:default` (Object,
|
|
25
|
-
# nil), `:pattern` (String, nil), `:admits` (String, nil) and
|
|
26
|
-
# `:relationship` (String, nil), each the raw declared value
|
|
27
|
-
# @return [Bluebook::Attribute] the attribute, with `type` resolved to a
|
|
28
|
-
# `Bluebook::Reference` when the row spelled one
|
|
10
|
+
# "Reference<Customer>" and has to become an edge again.
|
|
29
11
|
def attribute(field)
|
|
30
12
|
type = field[:type].to_s
|
|
31
13
|
target = type[/\AReference<(.+)>\z/, 1]
|
|
@@ -35,89 +17,39 @@ module Hecks
|
|
|
35
17
|
type: target ? Reference.new(target) : type,
|
|
36
18
|
list: field[:list] ? true : false,
|
|
37
19
|
default: field[:default],
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
# product — MetaValidator dispatches the declaration in and reads it
|
|
41
|
-
# back — so a fact this constructor does not carry is a fact the
|
|
42
|
-
# language cannot state about itself, however plainly the source
|
|
43
|
-
# wrote it.
|
|
20
|
+
# Every registry bluebook is a round-trip product, so a fact dropped
|
|
21
|
+
# here is a fact the language cannot state about itself.
|
|
44
22
|
optional: field[:optional] ? true : false,
|
|
45
23
|
pattern: field[:pattern],
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
# round trip, because the grammar registry keeps the assembled graph
|
|
49
|
-
# and downstream projections read the link off that. Dropped here, the
|
|
50
|
-
# language could not say `admits` about itself no matter how plainly
|
|
51
|
-
# the source wrote it, which is word for word what the note above
|
|
52
|
-
# already learned about `optional`.
|
|
24
|
+
# Not on `to_h`, but the grammar registry keeps the assembled graph and
|
|
25
|
+
# downstream projections read the link off it, so it must survive.
|
|
53
26
|
admits: field[:admits],
|
|
54
27
|
relationship: field[:relationship]
|
|
55
28
|
)
|
|
56
29
|
end
|
|
57
30
|
|
|
58
|
-
#
|
|
59
|
-
# different things in the language even though the IR keeps one class for
|
|
60
|
-
# both — `Aggregate.Attribute` and `Command.Argument` are separate verbs.
|
|
61
|
-
#
|
|
62
|
-
# @param field [Hash{Symbol => Object}] see `attribute`
|
|
63
|
-
# @return [Bluebook::Attribute] see `attribute`
|
|
31
|
+
# A head's field and a verb's argument are separate verbs sharing one IR class.
|
|
64
32
|
def shape_field(field) = attribute(field)
|
|
65
33
|
|
|
66
|
-
# One
|
|
67
|
-
# ordered list of them, and comes back out as the path it always was —
|
|
68
|
-
# a String, because `identity_paths` splits paths and never symbols.
|
|
69
|
-
#
|
|
70
|
-
# @param part [Hash{Symbol => Object}] one identity-path row, keyed `:value`
|
|
71
|
-
# (Object, read via `to_s`)
|
|
72
|
-
# @return [String] the path segment
|
|
34
|
+
# One identity part, as the String path `identity_paths` splits.
|
|
73
35
|
def identity_path(part) = part[:value].to_s
|
|
74
36
|
|
|
75
|
-
# A member's fields
|
|
76
|
-
#
|
|
77
|
-
#
|
|
78
|
-
# The values are unmarked, because `ValueObject#to_h` spells them with `to_s`
|
|
79
|
-
# and the language stores them as text: `member code: "JPY", minor_units: 0`
|
|
80
|
-
# came back with a minor_units of "0", and a closed set that admits the string
|
|
81
|
-
# would refuse the number the caller passes.
|
|
82
|
-
#
|
|
83
|
-
# @param pairs [Array<Array(String, Object)>] one member's own field pairs,
|
|
84
|
-
# each `[field_name, raw_value]` as declared
|
|
85
|
-
# @return [Hash{Symbol => Object}] the member's fields, keyed by field name,
|
|
86
|
-
# each value read back to its native type through `unmark_scalar`
|
|
37
|
+
# A member's fields, an open map, so the pairs arrive as a list.
|
|
38
|
+
# Values are unmarked because `ValueObject#to_h` spells them with `to_s`.
|
|
87
39
|
def member(pairs)
|
|
88
40
|
pairs.to_h { |key, value| [key.to_sym, unmark_scalar(value)] }
|
|
89
41
|
end
|
|
90
42
|
|
|
91
|
-
# A read model's gathered head
|
|
92
|
-
# declaration arrived, and `as` must be one too: it names the reader the
|
|
93
|
-
# projection answers to, and `ReadModel#to_h` spells it `to_s`.
|
|
94
|
-
#
|
|
95
|
-
# @param row [Hash{Symbol => Object}] one aggregate-head row, keyed
|
|
96
|
-
# `:aggregate` (String), `:as` (String, the reader name) and `:many`
|
|
97
|
-
# (Boolean)
|
|
98
|
-
# @return [Hash{Symbol => Object}] the head, with every key a Symbol and
|
|
99
|
-
# `:as` read back to a Symbol
|
|
43
|
+
# A read model's gathered head; `as` is a Symbol because `ReadModel#to_h` spells it `to_s`.
|
|
100
44
|
def head(row)
|
|
101
45
|
row.to_h { |key, value| [key.to_sym, key.to_sym == :as ? value.to_sym : value] }
|
|
102
46
|
end
|
|
103
47
|
|
|
104
|
-
#
|
|
105
|
-
# `{field: :symbol}`, so this matches it rather than leaving `field`
|
|
106
|
-
# as the String `Shapes#group_by_field` reads back.
|
|
107
|
-
#
|
|
108
|
-
# @param row [Hash{Symbol => String}] one group-by row, keyed `:field`
|
|
109
|
-
# @return [Hash{field: Symbol}] the row with `:field` read back to a Symbol
|
|
48
|
+
# Matches the builder's native `{field: :symbol}` shape.
|
|
110
49
|
def group_by_field(row) = { field: row[:field].to_sym }
|
|
111
50
|
|
|
112
|
-
#
|
|
113
|
-
#
|
|
114
|
-
# the shape of it. Unlike `read`, a bare word stays a String here, because
|
|
115
|
-
# a closed set admits words far more often than symbols.
|
|
116
|
-
#
|
|
117
|
-
# @param value [Object] the raw declared scalar, read via `to_s`
|
|
118
|
-
# @return [true, false, Integer, Float, String] `true`/`false` for those
|
|
119
|
-
# literal words, a number when the text matches a bare integer or decimal
|
|
120
|
-
# pattern, or the string itself otherwise
|
|
51
|
+
# Reads a member's scalar back from text. Unlike `read`, a bare word stays a
|
|
52
|
+
# String, because a closed set admits words far more often than symbols.
|
|
121
53
|
def unmark_scalar(value)
|
|
122
54
|
text = value.to_s
|
|
123
55
|
return true if text == "true"
|
|
@@ -128,74 +60,34 @@ module Hecks
|
|
|
128
60
|
text
|
|
129
61
|
end
|
|
130
62
|
|
|
131
|
-
# A saga's argument bindings
|
|
132
|
-
# marks a Symbol with a leading colon — lose it and an argument reads as a
|
|
133
|
-
# string of the same name.
|
|
134
|
-
#
|
|
135
|
-
# @param with [Array<Array(String, String)>, nil] the declared bindings,
|
|
136
|
-
# each `[argument_name, literal_spelling]` pair, or `nil` for none
|
|
137
|
-
# @return [Hash{Symbol => Object}] the bindings, keyed by argument name,
|
|
138
|
-
# each value read back through `Literal.read`
|
|
63
|
+
# A saga's argument bindings; Literal marks a Symbol with a leading colon.
|
|
139
64
|
def bindings(with) = Array(with).to_h { |key, value| [key.to_sym, read(value)] }
|
|
140
65
|
|
|
141
66
|
# Builds one aggregate or value object invariant from its declared row.
|
|
142
|
-
#
|
|
143
|
-
# @param rule [Hash{Symbol => String}] one invariant's declared row, keyed
|
|
144
|
-
# `:description` and `:canonical` (the canonical-form rendering of the
|
|
145
|
-
# rule's expression)
|
|
146
|
-
# @return [Bluebook::Invariant] the invariant, with `predicate`/`ast` left
|
|
147
|
-
# `nil` — `Expression::Evaluator` parses `canonical` on demand when
|
|
148
|
-
# neither is set
|
|
67
|
+
# `Expression::Evaluator` parses `canonical` on demand.
|
|
149
68
|
def invariant(rule)
|
|
150
69
|
Invariant.new(description: rule[:description], canonical: rule[:canonical])
|
|
151
70
|
end
|
|
152
71
|
|
|
153
72
|
# Builds one command precondition from its declared row.
|
|
154
|
-
#
|
|
155
|
-
# @param rule [Hash{Symbol => String}] one given's declared row, keyed
|
|
156
|
-
# `:description` and `:canonical` (the canonical-form rendering of the
|
|
157
|
-
# rule's expression)
|
|
158
|
-
# @return [Bluebook::Given] the given, with `predicate`/`ast` left `nil` —
|
|
159
|
-
# `Expression::Evaluator` parses `canonical` on demand when neither is set
|
|
160
73
|
def given(rule)
|
|
161
74
|
Given.new(description: rule[:description], canonical: rule[:canonical])
|
|
162
75
|
end
|
|
163
76
|
|
|
164
|
-
#
|
|
165
|
-
#
|
|
166
|
-
# free text, so — like `attribute`'s own `name`/`type` below —
|
|
167
|
-
# they come back as Symbols.
|
|
168
|
-
#
|
|
169
|
-
# @param row [Hash{Symbol => String}] one projected-field's declared row,
|
|
170
|
-
# keyed `:name`, `:reference` and `:remote_field` (each an identifier)
|
|
171
|
-
# @return [Bluebook::ProjectedField] the projected field, with each
|
|
172
|
-
# identifier read back to a Symbol
|
|
77
|
+
# All three fields are identifiers, unlike Invariant/Given's free text, so they
|
|
78
|
+
# come back as Symbols.
|
|
173
79
|
def projected_field(row)
|
|
174
80
|
ProjectedField.new(name: row[:name].to_sym, reference: row[:reference].to_sym,
|
|
175
81
|
remote_field: row[:remote_field].to_sym)
|
|
176
82
|
end
|
|
177
83
|
|
|
178
84
|
# `Mutation#to_h` branches on the operation, so this does too.
|
|
179
|
-
#
|
|
180
|
-
# An append binds several fields at once, each either an argument (a
|
|
181
|
-
# Symbol, wearing its colon) or a literal — the distinction that is the
|
|
182
|
-
# whole reason `append: { direction: "out" }` was once indistinguishable
|
|
183
|
-
# from an argument named `out`.
|
|
184
|
-
#
|
|
185
|
-
# @param change [Hash{Symbol => Object}] one mutation's declared row, keyed
|
|
186
|
-
# `:target` (String), `:op` (String, such as `"set"`, `"append"`,
|
|
187
|
-
# `"delegate"` or `"corrects"`), `:fields` (Array, for the append-shaped
|
|
188
|
-
# ops) and `:source` (Hash, for any other op)
|
|
189
|
-
# @return [Bluebook::Mutation] the mutation, with `source` a
|
|
190
|
-
# `Hash{Symbol => Object}` of field bindings for an append-shaped op, or
|
|
191
|
-
# `classified`'s own result for any other
|
|
85
|
+
# An append binds several fields, each an argument (a Symbol) or a literal.
|
|
192
86
|
def mutation(change)
|
|
193
87
|
target = change[:target].to_sym
|
|
194
88
|
op = change[:op].to_sym
|
|
195
89
|
|
|
196
|
-
# `:delegate
|
|
197
|
-
# #corrects_impl's own comments) ride the same multi-binding
|
|
198
|
-
# shape `:append` does.
|
|
90
|
+
# `:delegate` and `:corrects` ride the same multi-binding shape as `:append`.
|
|
199
91
|
return Mutation.new(target: target, op: op, source: appended(change[:fields])) if [:append, :delegate,
|
|
200
92
|
:corrects].include?(op)
|
|
201
93
|
|
|
@@ -203,26 +95,11 @@ module Hecks
|
|
|
203
95
|
end
|
|
204
96
|
|
|
205
97
|
# Reads an append mutation's field bindings back off their declared rows.
|
|
206
|
-
#
|
|
207
|
-
# @param fields [Array<Array(String, String)>, nil] the append's declared
|
|
208
|
-
# field bindings, each `[field_name, literal_spelling]` pair, or `nil`
|
|
209
|
-
# for none
|
|
210
|
-
# @return [Hash{Symbol => Object}] the bindings, keyed by field name, each
|
|
211
|
-
# value read back through `Literal.read`
|
|
212
98
|
def appended(fields)
|
|
213
99
|
Array(fields).to_h { |field, source| [field.to_sym, read(source)] }
|
|
214
100
|
end
|
|
215
101
|
|
|
216
|
-
# A set reads one thing
|
|
217
|
-
# name, or a literal by value.
|
|
218
|
-
#
|
|
219
|
-
# @param source [Hash{Symbol => Object}, nil] the mutation's declared
|
|
220
|
-
# source, keyed `:kind` (String, `"argument"`, `"state"` or a literal
|
|
221
|
-
# kind) plus `:name` (String, for `"argument"`/`"state"`) or `:value`
|
|
222
|
-
# (Object, for a literal), or `nil` for no source
|
|
223
|
-
# @return [Symbol, Hecks::StateRef, Object, nil] the command argument name,
|
|
224
|
-
# a state self-reference, the literal value, or `nil` when `source` is
|
|
225
|
-
# `nil`
|
|
102
|
+
# A set reads one thing: an argument by name, or a literal by value.
|
|
226
103
|
def classified(source)
|
|
227
104
|
return nil if source.nil?
|
|
228
105
|
|
|
@@ -233,44 +110,13 @@ module Hecks
|
|
|
233
110
|
end
|
|
234
111
|
end
|
|
235
112
|
|
|
236
|
-
#
|
|
237
|
-
#
|
|
238
|
-
#
|
|
239
|
-
# limit: all of them ride Literal's self-describing form, so all of them
|
|
240
|
-
# come back through this one reader, never a second one that might
|
|
241
|
-
# disagree about a quoted string or a number.
|
|
242
|
-
#
|
|
243
|
-
# An object literal is the one that bites hardest. A saga leg binds
|
|
244
|
-
# `narrative: { text: "transfer out" }` — a value object's fields written
|
|
245
|
-
# inline — and reading it as a plain string rather than through `Literal`
|
|
246
|
-
# would reach the runtime as `"{:text=>\"transfer out\"}"`, which coercion
|
|
247
|
-
# refuses: the debit leg is never delivered, and the whole settlement wire
|
|
248
|
-
# stops — banking emits TransferRequested five times and TransferDebited
|
|
249
|
-
# never. A whole-history replay gate is what catches this, because a saga
|
|
250
|
-
# that silently does nothing looks exactly like a saga with nothing to do.
|
|
251
|
-
#
|
|
252
|
-
# @param value [String, Object] wire spelling produced by `Literal.render`,
|
|
253
|
-
# or a bare word
|
|
254
|
-
# @return [nil, true, false, Integer, Float, Symbol, Hecks::StateRef,
|
|
255
|
-
# String, Hash, Array] the value read back — see `Literal.read`
|
|
113
|
+
# Reads every literal field on the wire through `Literal`, so no second reader
|
|
114
|
+
# can disagree about quoting. An object literal read as a plain string reaches
|
|
115
|
+
# the runtime as inspect text, which coercion refuses, and the saga leg stalls.
|
|
256
116
|
def read(value) = Literal.read(value)
|
|
257
117
|
|
|
258
|
-
# `target:`
|
|
259
|
-
#
|
|
260
|
-
# `OrderBy#to_h`/`LimitSpec#to_h` wrote (`resolve_target`'s own
|
|
261
|
-
# `Naming.demodulise` already ran once, at DSL-build time; this is
|
|
262
|
-
# the replay path every real boot actually goes through, reading
|
|
263
|
-
# that same wire shape back — see this class's own header). Absent
|
|
264
|
-
# from `clause`/`declared` entirely on older wire data that never
|
|
265
|
-
# declared `on:` — `clause[:target]`/`declared[:target]` reads
|
|
266
|
-
# `nil` for a missing key exactly like an explicit `nil` would,
|
|
267
|
-
# so this is additive, not a migration.
|
|
268
|
-
#
|
|
269
|
-
# @param clause [Hash{Symbol => Object}] one where-clause's declared row,
|
|
270
|
-
# keyed `:field` (String), `:op` (String, a comparator name), `:value`
|
|
271
|
-
# (String, Literal's spelling) and `:target` (String, `nil` when absent)
|
|
272
|
-
# @return [QuerySpecification::Common::WhereClause] the clause, with `op`
|
|
273
|
-
# read to a Symbol and `value` read back through `Literal.read`
|
|
118
|
+
# `target:` is read straight off the wire, unconverted. A missing key reads
|
|
119
|
+
# `nil` like an explicit `nil`, so older wire data needs no migration.
|
|
274
120
|
def where_clause(clause)
|
|
275
121
|
QuerySpecification::Common::WhereClause.new(
|
|
276
122
|
field: clause[:field], op: clause[:op].to_sym, value: read(clause[:value]), target: clause[:target]
|
|
@@ -278,12 +124,6 @@ module Hecks
|
|
|
278
124
|
end
|
|
279
125
|
|
|
280
126
|
# Builds a query's declared ordering, if it declares one.
|
|
281
|
-
#
|
|
282
|
-
# @param declared [Hash{Symbol => Object}, nil] the declared order-by row,
|
|
283
|
-
# keyed `:field` (String), `:direction` (String) and `:target` (String,
|
|
284
|
-
# `nil` when absent), or `nil` when the construct declares no ordering
|
|
285
|
-
# @return [QuerySpecification::Common::OrderBy, nil] the order-by, with
|
|
286
|
-
# `direction` read to a Symbol, or `nil` when `declared` is `nil`
|
|
287
127
|
def order_by(declared)
|
|
288
128
|
return nil unless declared
|
|
289
129
|
|
|
@@ -293,25 +133,14 @@ module Hecks
|
|
|
293
133
|
end
|
|
294
134
|
|
|
295
135
|
# Builds a query's declared limit, if it declares one.
|
|
296
|
-
#
|
|
297
|
-
# @param declared [Hash{Symbol => Object}, nil] the declared limit row,
|
|
298
|
-
# keyed `:value` (String, Literal's spelling) and `:target` (String,
|
|
299
|
-
# `nil` when absent), or `nil` when the construct declares no limit
|
|
300
|
-
# @return [QuerySpecification::Common::LimitSpec, nil] the limit, with
|
|
301
|
-
# `value` read back through `Literal.read`, or `nil` when `declared` is
|
|
302
|
-
# `nil`
|
|
303
136
|
def limit(declared)
|
|
304
137
|
return nil unless declared
|
|
305
138
|
|
|
306
139
|
QuerySpecification::Common::LimitSpec.new(value: read(declared[:value]), target: declared[:target])
|
|
307
140
|
end
|
|
308
141
|
|
|
309
|
-
# Every other specification option, from one table
|
|
310
|
-
#
|
|
311
|
-
# Each entry names the struct and which of its members carry a value that
|
|
312
|
-
# rode Literal's spelling rather than plain text. A
|
|
313
|
-
# ninth option is one row here and nothing else — the language already holds
|
|
314
|
-
# it, because it holds options as an open map rather than a field each.
|
|
142
|
+
# Every other specification option, from one table: the struct, and which of
|
|
143
|
+
# its members carry a value that rode Literal's spelling.
|
|
315
144
|
OPTIONS = {
|
|
316
145
|
offset: [QuerySpecification::Common::OffsetSpec, %i[value]],
|
|
317
146
|
cursor: [QuerySpecification::Common::CursorSpec, %i[value]],
|
|
@@ -320,24 +149,11 @@ module Hecks
|
|
|
320
149
|
inspection: [QuerySpecification::Common::InspectionSpec, []]
|
|
321
150
|
}.freeze
|
|
322
151
|
|
|
323
|
-
#
|
|
324
|
-
#
|
|
325
|
-
# with `to_s`, so the colon is not there to strip.
|
|
152
|
+
# The DSL declares these as symbols (`nulls :last`) and `to_h` spells them with
|
|
153
|
+
# `to_s`, so they are converted back.
|
|
326
154
|
SYMBOLIC = %i[mode policy tenant].freeze
|
|
327
155
|
|
|
328
156
|
# Builds one query specification option from its declared row and `OPTIONS`.
|
|
329
|
-
#
|
|
330
|
-
# @param name [Symbol] the option's name, a key of `OPTIONS` (`:offset`,
|
|
331
|
-
# `:cursor`, `:null_semantics`, `:authorization` or `:inspection`)
|
|
332
|
-
# @param declared [Hash{Symbol => Object}, nil] the option's declared row,
|
|
333
|
-
# or `nil` when the construct does not declare this option
|
|
334
|
-
# @return [QuerySpecification::Common::OffsetSpec,
|
|
335
|
-
# QuerySpecification::Common::CursorSpec,
|
|
336
|
-
# QuerySpecification::Common::NullSemantics,
|
|
337
|
-
# QuerySpecification::Common::AuthorizationSpec,
|
|
338
|
-
# QuerySpecification::Common::InspectionSpec, nil] the option built
|
|
339
|
-
# through the holder `OPTIONS` names for `name`, or `nil` when `declared`
|
|
340
|
-
# is `nil`
|
|
341
157
|
# @raise [KeyError] if `name` is not a key of `OPTIONS`
|
|
342
158
|
def option(name, declared)
|
|
343
159
|
return nil if declared.nil?
|
|
@@ -347,14 +163,6 @@ module Hecks
|
|
|
347
163
|
end
|
|
348
164
|
|
|
349
165
|
# Reads one option member's declared value back to its native type.
|
|
350
|
-
#
|
|
351
|
-
# @param key [Symbol] the option member's name being read
|
|
352
|
-
# @param value [Object, nil] the declared value for that member
|
|
353
|
-
# @param marked [Array<Symbol>] the members of this option that ride
|
|
354
|
-
# Literal's spelling, from `OPTIONS`
|
|
355
|
-
# @return [Object, nil] `value` read back through `Literal.read` when
|
|
356
|
-
# `key` is marked, a Symbol when `key` is one of `SYMBOLIC`, the raw
|
|
357
|
-
# `value` otherwise, or `nil` when `value` is `nil`
|
|
358
166
|
def option_value(key, value, marked)
|
|
359
167
|
return nil if value.nil?
|
|
360
168
|
return read(value) if marked.include?(key)
|
|
@@ -1,49 +1,18 @@
|
|
|
1
1
|
module Hecks
|
|
2
2
|
module Bluebook
|
|
3
3
|
class Assembly
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
# hand-written beside it.
|
|
7
|
-
#
|
|
8
|
-
# `Plan` already reads `grammar_registry` to build the judge's walk ; this
|
|
9
|
-
# reads the same chapter to build the other table this arc's own header
|
|
10
|
-
# names as duplication — "spelled as the IR spells them," field for field,
|
|
11
|
-
# for every category simple enough to say so.
|
|
12
|
-
#
|
|
13
|
-
# One case, proven, not the whole table. A field this can speak for is
|
|
14
|
-
# scalar and not a reference — every other field (a list, a reference, a
|
|
15
|
-
# fold like Lifecycle) is exactly what `contracts.rb`'s `reads:`/`derived:`
|
|
16
|
-
# exist to say, and stays hand-written until a later projection learns to
|
|
17
|
-
# derive readers and folds too. Restricting the claim to what can be
|
|
18
|
-
# proven correct — checked in spec/specializer_spec.rb against two
|
|
19
|
-
# independent categories — is the same discipline `derived:` itself
|
|
20
|
-
# enforces : a claim needs a kind, and this one's kind is "plain, checked."
|
|
4
|
+
# Projects `contracts.rb`'s `fields:` table from the language's own grammar,
|
|
5
|
+
# for fields simple enough to derive: scalar, non-reference, non-walked.
|
|
21
6
|
module Specializer
|
|
22
7
|
module_function
|
|
23
8
|
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
# it hangs off some aggregate's own `.entities` instead
|
|
27
|
-
# (searched recursively, the same reason `Value::Coercion#find_
|
|
28
|
-
# entity` does: a nested entity, like `Dispatch` inside
|
|
29
|
-
# `Handler`, is not a direct child of any aggregate either).
|
|
30
|
-
#
|
|
31
|
-
# @param chapter [Bluebook::Chapter] the chapter to search
|
|
32
|
-
# @param name [String, Symbol] the construct's declared name
|
|
33
|
-
# @return [Bluebook::Aggregate, Class, nil] the aggregate, or the entity class
|
|
34
|
-
# (a `Bluebook::Entity` subclass) nested anywhere under one, or `nil` if
|
|
35
|
-
# `chapter` declares no construct by that name
|
|
9
|
+
# Finds a construct by name — an aggregate, or an entity nested anywhere
|
|
10
|
+
# under one (recursively, since an entity like Dispatch nests two deep).
|
|
36
11
|
def construct_for(chapter, name)
|
|
37
12
|
chapter.aggregate(name) || chapter.aggregates.filter_map { |a| find_entity(a, name) }.first
|
|
38
13
|
end
|
|
39
14
|
|
|
40
15
|
# Searches a construct's own entities, recursively, for one by name.
|
|
41
|
-
#
|
|
42
|
-
# @param construct [Bluebook::Aggregate, Class] the aggregate, or entity class,
|
|
43
|
-
# to search under
|
|
44
|
-
# @param name [String, Symbol] the entity's declared name
|
|
45
|
-
# @return [Class, nil] the entity class (a `Bluebook::Entity` subclass), or `nil`
|
|
46
|
-
# if none of `construct`'s nested entities has that name
|
|
47
16
|
def find_entity(construct, name)
|
|
48
17
|
construct.entities.each do |candidate|
|
|
49
18
|
return candidate if candidate.hecks_name == name
|
|
@@ -54,23 +23,8 @@ module Hecks
|
|
|
54
23
|
nil
|
|
55
24
|
end
|
|
56
25
|
|
|
57
|
-
# `
|
|
58
|
-
#
|
|
59
|
-
# `order_by :position` on its `DeclaredIn` ask — but no `*`
|
|
60
|
-
# constructor takes it as an argument. `contracts.rb` already says so,
|
|
61
|
-
# in the language every other derived field speaks :
|
|
62
|
-
# `derived: { position: :walk }`. The language says a category has a
|
|
63
|
-
# position ; it does not say a category's own constructor is handed
|
|
64
|
-
# one, and that second fact is exactly what `fields:` needs to answer.
|
|
65
|
-
# So the skip reads the category's own walk claims (`Contract#walked`)
|
|
66
|
-
# rather than restating `position` here — Handler, which has no
|
|
67
|
-
# walk-minted position, skips nothing.
|
|
68
|
-
#
|
|
69
|
-
# @param category [String, Symbol] the construct category's name, such as
|
|
70
|
-
# `"Aggregate"` or `"Command"`
|
|
71
|
-
# @return [Hash{Symbol => Array(Symbol, Symbol)}] a `contracts.rb`-shaped
|
|
72
|
-
# `fields:` table, one `field => [field, :plain]` entry per scalar,
|
|
73
|
-
# non-reference, non-walked attribute the language declares for `category`
|
|
26
|
+
# Builds `category`'s own `fields:` entries from the language's scalar,
|
|
27
|
+
# non-reference attributes, skipping any the contract already derives.
|
|
74
28
|
def fields_for(category)
|
|
75
29
|
language = construct_for(MetaValidator.grammar_registry.bluebook("Bluebook"), category.to_s)
|
|
76
30
|
walked = Assembly.contract(category).walked
|
|
@@ -1,38 +1,7 @@
|
|
|
1
1
|
module Hecks
|
|
2
2
|
module Bluebook
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
# This is the half that lets the language orchestrate. `Reconstruction` reads a
|
|
6
|
-
# chapter back out of the meta-domain, in declaration order, as plain
|
|
7
|
-
# declarations — the same shape `to_h` spells. This turns those declarations
|
|
8
|
-
# into the graph the runtime runs: IR aggregates with their verbs, value
|
|
9
|
-
# objects, entities and asks, owned by the chapter that declares them.
|
|
10
|
-
#
|
|
11
|
-
# ## Why a hash, not a runtime
|
|
12
|
-
#
|
|
13
|
-
# It takes a hash, not a runtime, on purpose. That makes it a pure inverse of
|
|
14
|
-
# `to_h` and testable without the meta-domain in the picture at all:
|
|
15
|
-
#
|
|
16
|
-
# Assembly.call(built.to_h).to_h == built.to_h
|
|
17
|
-
#
|
|
18
|
-
# which is the check `spec/assembly_spec` makes for every chapter in the tree.
|
|
19
|
-
# Feed it the reconstruction instead and the same code assembles what the
|
|
20
|
-
# language holds — the only difference being where the declarations came from.
|
|
21
|
-
#
|
|
22
|
-
# ## One table, not a method per category
|
|
23
|
-
#
|
|
24
|
-
# Every field is read from one table. There is no method per category here:
|
|
25
|
-
# `Contracts` names what the language cannot say about a construct, `Build`
|
|
26
|
-
# reads it, and the coverage gate holds the table to the language. A method
|
|
27
|
-
# per category can decorate a verb the language declares without ever
|
|
28
|
-
# offering it; the table cannot, because `spec/assembly_spec` checks every
|
|
29
|
-
# field the language declares against it.
|
|
30
|
-
#
|
|
31
|
-
# ## What stays hand-written
|
|
32
|
-
#
|
|
33
|
-
# The containment — which construct holds which — stays hand-written; it is
|
|
34
|
-
# not a field table. The runtime surface is not built here at all — the
|
|
35
|
-
# door is a per-boot projection, facade/surface.rb.
|
|
3
|
+
# Builds the runtime graph (aggregates, read models, process managers) from
|
|
4
|
+
# a chapter's declared hash — the pure inverse of `Chapter#to_h`.
|
|
36
5
|
class Assembly
|
|
37
6
|
# Builds the graph the runtime runs from one chapter's declared hash.
|
|
38
7
|
#
|
|
@@ -67,10 +36,8 @@ module Hecks
|
|
|
67
36
|
|
|
68
37
|
private
|
|
69
38
|
|
|
70
|
-
#
|
|
71
|
-
# that declared it
|
|
72
|
-
# the chapter where the runtime reads it while the head keeps its own list. The
|
|
73
|
-
# language records which head, so the assembly can put it back.
|
|
39
|
+
# Hoists each reaction onto the chapter (for the runtime) and also back onto
|
|
40
|
+
# the aggregate head that declared it, per the language's own record of which.
|
|
74
41
|
def reactions(aggregates)
|
|
75
42
|
Array(@declaration[:policies]).map { |row| Build.call("Policy", row) }.each do |reaction|
|
|
76
43
|
next if reaction.aggregate.to_s.empty?
|
|
@@ -90,14 +57,8 @@ module Hecks
|
|
|
90
57
|
dispatches: Array(row[:dispatches]).map { |leg| dispatch(leg) })
|
|
91
58
|
end
|
|
92
59
|
|
|
93
|
-
# `compensates`
|
|
94
|
-
#
|
|
95
|
-
# `DispatchSpec` its own field actually is by recursing through
|
|
96
|
-
# this same method, one level in — the identical move `handler`
|
|
97
|
-
# itself takes into `dispatches`, one level up. `nil` when there
|
|
98
|
-
# is nothing to compensate; `Build.call` never sees a
|
|
99
|
-
# `compensates:` key it does not know how to read either way, the
|
|
100
|
-
# same reason `compensates` never joined `Contract#fields` at all.
|
|
60
|
+
# `compensates` recurses through this same method (as `handler` does for
|
|
61
|
+
# `dispatches`) since it's itself a nested `DispatchSpec`-shaped hash.
|
|
101
62
|
def dispatch(row)
|
|
102
63
|
compensates = row[:compensates] && dispatch(row[:compensates])
|
|
103
64
|
Build.call("Dispatch", row, compensates: compensates)
|
|
@@ -5,12 +5,8 @@ require_relative "../naming"
|
|
|
5
5
|
|
|
6
6
|
module Hecks
|
|
7
7
|
module Bluebook
|
|
8
|
-
# One declared field on a construct
|
|
9
|
-
#
|
|
10
|
-
# whether it's a list, its default/optional/pattern, and the closed set
|
|
11
|
-
# it `admits`. What `attribute :x, Type` (or `identified_by`,
|
|
12
|
-
# `reference_to`, etc.) actually mints, on an Aggregate, Entity, Command,
|
|
13
|
-
# ValueObject, Query or PortOperation alike.
|
|
8
|
+
# One declared field on a construct: name, type, list, default, optional, pattern
|
|
9
|
+
# and the closed set it `admits`.
|
|
14
10
|
class Attribute
|
|
15
11
|
include Hecks::IR
|
|
16
12
|
include Behaviour::Attribute
|
|
@@ -28,44 +24,17 @@ module Hecks
|
|
|
28
24
|
|
|
29
25
|
attr_reader :name, :type, :default, :pattern, :admits, :relationship
|
|
30
26
|
|
|
31
|
-
# A Reference is kept as itself
|
|
32
|
-
# crosses over as its construct does.
|
|
33
|
-
#
|
|
34
|
-
# `admits` names an already-declared closed set the value must belong
|
|
35
|
-
# to — `Vocabulary::QueryComparator` — spelled aggregate-qualified
|
|
36
|
-
# because the set is a value object inside an aggregate, and the
|
|
37
|
-
# aggregate is the only thing `reference_to` can reach.
|
|
38
|
-
#
|
|
39
|
-
# On the wire, because it is a rule and not only a typing hint.
|
|
40
|
-
#
|
|
41
|
-
# It began as neither. The link existed so a generator could type
|
|
42
|
-
# `WhereClause.op` as `WhereOp` — a typing convenience, not worth
|
|
43
|
-
# moving 710 attribute records across eight goldens for. Then `admits`
|
|
44
|
-
# grew teeth (coercion refuses a non-member) and the argument
|
|
45
|
-
# inverted: a rule the wire does not carry is one a reader of the IR
|
|
46
|
-
# cannot enforce, and a bluebook whose meaning depends on the reader
|
|
47
|
-
# means two things. Proved rather than assumed — the same domain
|
|
48
|
-
# refused "burnt" through one reading and emitted the event through
|
|
49
|
-
# another.
|
|
50
|
-
#
|
|
51
|
-
# The wire carries the name, not the members. A reader resolves it
|
|
52
|
-
# against the IR it holds, so the members are declared once and
|
|
53
|
-
# copied nowhere — which is the same reason `admits` exists at all.
|
|
27
|
+
# A Reference is kept as itself; every other type is a name.
|
|
54
28
|
#
|
|
55
29
|
# @param name [Symbol, String] the attribute's name
|
|
56
|
-
# @param type [Module, Bluebook::Reference, String, Symbol]
|
|
57
|
-
#
|
|
58
|
-
# text
|
|
30
|
+
# @param type [Module, Bluebook::Reference, String, Symbol] a bare constant, a Reference,
|
|
31
|
+
# or already-spelled text
|
|
59
32
|
# @param list [Boolean] whether this attribute holds a list of values rather than one
|
|
60
33
|
# @param default [Object, nil] the value a new record starts with when none is given
|
|
61
34
|
# @param optional [Boolean] whether a command may omit this attribute
|
|
62
|
-
# @param pattern [String, nil] a regex source the value must match
|
|
63
|
-
#
|
|
64
|
-
# @param
|
|
65
|
-
# name, such as `"Vocabulary::QueryComparator"`, that the value must belong to
|
|
66
|
-
# @param relationship [Symbol, nil] the DSL word that minted this attribute
|
|
67
|
-
# (`:reference_to`, `:has_many`, `:has_one` or `:belongs_to`), or `nil` for an
|
|
68
|
-
# ordinary attribute
|
|
35
|
+
# @param pattern [String, nil] a regex source the value must match (`PatternSubset`)
|
|
36
|
+
# @param admits [String, nil] an aggregate-qualified closed-set name for the value
|
|
37
|
+
# @param relationship [Symbol, nil] the DSL word that minted this attribute, or `nil`
|
|
69
38
|
def initialize(name:, type:, list: false, default: nil, optional: false, pattern: nil,
|
|
70
39
|
admits: nil, relationship: nil)
|
|
71
40
|
@name = name.to_sym
|
|
@@ -80,23 +49,9 @@ module Hecks
|
|
|
80
49
|
|
|
81
50
|
# A bare constant in a bluebook is a name, even when Ruby has heard of it.
|
|
82
51
|
#
|
|
83
|
-
# `
|
|
84
|
-
# resolver
|
|
85
|
-
#
|
|
86
|
-
# lookup fails, and `Facade::Surface` installs every aggregate name as a
|
|
87
|
-
# top-level constant (its own comment, and `ConstShim`'s, both say so).
|
|
88
|
-
#
|
|
89
|
-
# So in one process: boot a domain with an aggregate named `Target`, then
|
|
90
|
-
# load a chapter whose own value object is called `Target`, and Ruby
|
|
91
|
-
# resolves the constant before the hook is ever asked. The chapter is then
|
|
92
|
-
# built against somebody else's aggregate — silently, with no refusal —
|
|
93
|
-
# and the attribute stops meaning what the file plainly says.
|
|
94
|
-
#
|
|
95
|
-
# Demodulised, so both paths spell it the same: `:Target` and
|
|
96
|
-
# `QualityControl::Target` are both "Target". A plain class stays itself —
|
|
97
|
-
# `String` demodulises to "String" — so the ordinary case is untouched.
|
|
98
|
-
# This does not undo the constant leak; it makes the leak unable to change
|
|
99
|
-
# what a chapter means, which is the part that has to hold.
|
|
52
|
+
# `Facade::Surface` installs aggregate names as top-level constants, which would win
|
|
53
|
+
# over the `const_missing` resolver and silently rebind the attribute. Demodulising
|
|
54
|
+
# spells `:Target` and `QualityControl::Target` the same.
|
|
100
55
|
def spell(type)
|
|
101
56
|
return type if type.is_a?(Reference)
|
|
102
57
|
return Naming.demodulise(type) if type.is_a?(Module)
|
|
@@ -105,12 +60,8 @@ module Hecks
|
|
|
105
60
|
end
|
|
106
61
|
private :spell
|
|
107
62
|
|
|
108
|
-
#
|
|
109
|
-
# holds `Primitive`'s members to this list.
|
|
63
|
+
# Pinned by spec/vocabulary_conformance, which holds `Primitive`'s members to this list.
|
|
110
64
|
PRIMITIVES = Hecks::Vocabulary.fetch("Primitive")
|
|
111
|
-
|
|
112
|
-
# `type` is spelled, never handed over. A Reference renders as
|
|
113
|
-
# "Reference<Customer>" here because that is the export's pinned spelling.
|
|
114
65
|
end
|
|
115
66
|
end
|
|
116
67
|
end
|