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,13 +2,8 @@ require_relative "word_gate"
|
|
|
2
2
|
module Hecks
|
|
3
3
|
module Bluebook
|
|
4
4
|
module DSL
|
|
5
|
-
# Parses a `.hecksagon` file's
|
|
6
|
-
#
|
|
7
|
-
# (`persisted_by`, `projected_by`, ...), which framework/vendored
|
|
8
|
-
# bluebooks it attaches, which external events it subscribes to, and
|
|
9
|
-
# its bare chapter-root port. Kept separate from the bluebook itself
|
|
10
|
-
# (the domain's own declared model) because wiring is an operational
|
|
11
|
-
# decision, not a fact the domain states about itself.
|
|
5
|
+
# Parses a `.hecksagon` file's DSL block into a Hecksagon: a domain's adapter bindings,
|
|
6
|
+
# framework/vendored attachments and subscriptions — wiring, not part of the bluebook.
|
|
12
7
|
class HecksagonBuilder
|
|
13
8
|
GRAMMAR_CONTEXT = "Hecksagon".freeze
|
|
14
9
|
|
|
@@ -20,7 +15,6 @@ module Hecks
|
|
|
20
15
|
|
|
21
16
|
attr_reader :binds, :subscriptions, :framework_members, :vendored_bluebooks
|
|
22
17
|
|
|
23
|
-
# @param domain [String] name of the domain whose wiring this hecksagon declares
|
|
24
18
|
def initialize(domain)
|
|
25
19
|
@domain = domain
|
|
26
20
|
@binds = []
|
|
@@ -31,173 +25,59 @@ module Hecks
|
|
|
31
25
|
@translates = []
|
|
32
26
|
end
|
|
33
27
|
|
|
34
|
-
# Marks this chapter as a bounded context
|
|
35
|
-
#
|
|
36
|
-
# Framework and vendored packages get the mark automatically from
|
|
37
|
-
# those words; they never write `bounded` in their own bluebooks.
|
|
38
|
-
# A bounded chapter wraps in its own module (no Object shortcut)
|
|
39
|
-
# and must declare at least one `translates` ACL or boot refuses.
|
|
40
|
-
#
|
|
41
|
-
# @return [Boolean] true
|
|
28
|
+
# Marks this chapter as a bounded context; framework/vendored attachments set it too.
|
|
29
|
+
# Must declare at least one `translates` ACL or boot refuses.
|
|
42
30
|
def bounded
|
|
43
31
|
@bounded = true
|
|
44
32
|
end
|
|
45
33
|
|
|
46
|
-
# Subscribes
|
|
47
|
-
#
|
|
48
|
-
# @param event [String, Symbol] the external event's name
|
|
49
|
-
# @return [Array<String>] every subscription declared so far, this one last
|
|
34
|
+
# Subscribes to an event from outside this domain's own bluebook.
|
|
50
35
|
def subscribe(event) = @subscriptions << event.to_s
|
|
51
36
|
|
|
52
|
-
# Attaches a framework member
|
|
53
|
-
#
|
|
54
|
-
# A framework/ member this domain wants attached —
|
|
55
|
-
# Governance, Identity, whatever else lands beside them.
|
|
56
|
-
# Attaching one is a wiring decision, the same kind `persisted_by`/
|
|
57
|
-
# `projected_by` already are, so it lives here rather than as a
|
|
58
|
-
# fact stated in the domain's own bluebook. Recorded onto this
|
|
59
|
-
# hecksagon, the same way `subscribe` records onto its own
|
|
60
|
-
# `subscriptions` — and loads the member's bluebook then its own
|
|
61
|
-
# hecksagon into whatever registry this one is loading into, see
|
|
62
|
-
# `Framework.load!`.
|
|
63
|
-
#
|
|
64
|
-
# @param name [String, Symbol] the member's name, such as `"Governance"`
|
|
65
|
-
# @return [Boolean, nil] true when this call loaded the member's bluebook, nil when the
|
|
66
|
-
# current registry already held it
|
|
67
|
-
# @raise [Runtime::WiringError] if no framework member has that name
|
|
37
|
+
# Attaches a framework member (e.g. Governance) and loads it into the current registry.
|
|
68
38
|
def uses_framework(name)
|
|
69
39
|
@framework_members << name.to_s
|
|
70
40
|
Hecks::Framework.load!(name)
|
|
71
|
-
#
|
|
72
|
-
#
|
|
73
|
-
# the anti-corruption layer. Not written in the framework
|
|
74
|
-
# bluebook itself.
|
|
41
|
+
# Marks the framework member as bounded; the consumer's own hecksagon is the
|
|
42
|
+
# anti-corruption layer.
|
|
75
43
|
Hecks.current_registry&.mark_bounded(name.to_s)
|
|
76
44
|
end
|
|
77
45
|
|
|
78
46
|
# Attaches a vendored embryonaut bluebook to this domain and loads its files into the
|
|
79
|
-
#
|
|
80
|
-
#
|
|
81
|
-
# A vendored, external bluebook this domain wants attached — same
|
|
82
|
-
# wiring-decision shape `uses_framework` already is, one level
|
|
83
|
-
# further out: not a member shipped inside hecks's own lib/,
|
|
84
|
-
# but a separate package (embryonaut_bluebooks) vendored into this
|
|
85
|
-
# project's own checkout. See EmbryonautBluebook's own header for
|
|
86
|
-
# the full reasoning on why its root can't be a fixed constant the
|
|
87
|
-
# way Framework::ROOT is, and for the recovery provenance.
|
|
88
|
-
#
|
|
89
|
-
# Recorded onto @vendored_bluebooks, same shape `uses_framework`
|
|
90
|
-
# already gives @framework_members — a separate list on purpose:
|
|
91
|
-
# `framework_members` is load-bearing for `refuse_ungoverned_roles!`
|
|
92
|
-
# (`Registry::Verification`) and for Governance's own attachment
|
|
93
|
-
# check; conflating the two would make a vendored bluebook attachment
|
|
94
|
-
# satisfy a Governance check it has nothing to do with.
|
|
95
|
-
#
|
|
96
|
-
# @param name [String, Symbol] the vendored package's directory name under
|
|
97
|
-
# `vendor/embryonaut_bluebooks/`
|
|
98
|
-
# @return [Array<String>, nil] paths of the `.bluebook` files this call loaded, or nil
|
|
99
|
-
# when the current registry already held the bluebook
|
|
100
|
-
# @raise [Runtime::WiringError] if the current registry has no root to vendor from, or
|
|
101
|
-
# no vendored bluebook of that name exists under it
|
|
47
|
+
# registry. Recorded separately from @framework_members, which is load-bearing for
|
|
48
|
+
# governance checks.
|
|
102
49
|
def uses_embryonaut_bluebook(name)
|
|
103
50
|
@vendored_bluebooks << name.to_s
|
|
104
51
|
Hecks::EmbryonautBluebook.load!(name)
|
|
105
|
-
#
|
|
106
|
-
#
|
|
107
|
-
# (`"membership"` → `Membership`).
|
|
52
|
+
# Marks the chapter bounded, same as `uses_framework`; the directory name Pascal-cases
|
|
53
|
+
# to the chapter name (`"membership"` → `Membership`).
|
|
108
54
|
Hecks.current_registry&.mark_bounded(Hecks::Naming.pascal(name.to_s))
|
|
109
55
|
end
|
|
110
56
|
|
|
111
|
-
# Declares a port at the hecksagon's root
|
|
112
|
-
#
|
|
113
|
-
# The primary port, bare at the root — belongs to the chapter as a
|
|
114
|
-
# whole, not one aggregate. `BindingProxy#port` is the aggregate-
|
|
115
|
-
# scoped sibling (`Payments::Payment.port("Gateway") do ... end`);
|
|
116
|
-
# this is what's left when a port isn't about any one record. The
|
|
117
|
-
# bluebook must already be built and registered, since a hecksagon
|
|
118
|
-
# loads after its bluebook, and this attaches to that real, final
|
|
119
|
-
# object directly rather than building a second copy MetaValidator
|
|
120
|
-
# would have to know how to reconstruct.
|
|
121
|
-
#
|
|
122
|
-
# Answers the `port` word through the table's `calls:` column —
|
|
123
|
-
# item #13's full metaprogrammed dispatch (slice 5). Not
|
|
124
|
-
# bootstrap-reachable (checked directly — no core/attached chapter
|
|
125
|
-
# declares a Hecksagon of its own). Reached through `WordGate`'s
|
|
126
|
-
# `word_gate_dispatch`, called explicitly below since
|
|
127
|
-
# `HecksagonBuilder`'s own class-level `method_missing` (the
|
|
128
|
-
# open-verb catch-all beneath this) always wins over the module's —
|
|
129
|
-
# see `word_gate.rb`'s own header for the full mechanism.
|
|
130
|
-
#
|
|
131
|
-
# @param name [String] the port's name
|
|
132
|
-
# @yield the port body, evaluated against a `DomainPortBuilder`: either `verb`/`signal`
|
|
133
|
-
# or `operation`/`tells`/`asks` blocks
|
|
134
|
-
# @return [Bluebook::Port, Bluebook::DomainPort] the built port: a verb-shaped `Port`
|
|
135
|
-
# registered on the current registry, or a `DomainPort` attached to the bluebook
|
|
136
|
-
# @raise [Bluebook::DSL::Malformed] if the current registry holds no bluebook for this
|
|
137
|
-
# domain, or the body declares both a verb and operations, neither, or an operation
|
|
138
|
-
# the port grammar refuses
|
|
57
|
+
# Declares a port at the hecksagon's root — the chapter as a whole, not one aggregate.
|
|
139
58
|
def port_impl(name, &block)
|
|
140
59
|
bluebook_ir = Hecks.current_registry.bluebook(@domain) or
|
|
141
60
|
raise Malformed, "#{@domain} declares no such bluebook — a port needs one to belong to"
|
|
142
61
|
|
|
143
|
-
#
|
|
144
|
-
#
|
|
145
|
-
# dynamic extent, currently this file's own BindingProxy-minting
|
|
146
|
-
# one, which would turn a bare constant inside an operation's
|
|
147
|
-
# `reference_to`/`attribute` into another BindingProxy instead of
|
|
148
|
-
# a name.
|
|
62
|
+
# Swaps the active ConstShim resolver to plain passthrough — without it a bare constant
|
|
63
|
+
# inside `reference_to`/`attribute` would resolve to a BindingProxy instead of a name.
|
|
149
64
|
built = ConstShim.with(->(const) { const }) { DomainPortBuilder.build(name, &block) }
|
|
150
65
|
|
|
151
|
-
#
|
|
152
|
-
#
|
|
153
|
-
# way `Hecks.port`'s top-level method already does, not attached
|
|
154
|
-
# to this bluebook's own IR the way an operations-shaped
|
|
155
|
-
# `DomainPort` is.
|
|
66
|
+
# A verb-shaped port is a plain `Port`, registered like `Hecks.port`'s top-level method,
|
|
67
|
+
# not attached to this bluebook's IR the way an operations-shaped `DomainPort` is.
|
|
156
68
|
return Hecks.current_registry.add_port(built) if built.is_a?(Port)
|
|
157
69
|
|
|
158
70
|
bluebook_ir.add_port(built)
|
|
159
71
|
end
|
|
160
72
|
|
|
161
|
-
# A
|
|
162
|
-
#
|
|
163
|
-
# builds the exact same `Policy` a `policy` block inside this
|
|
164
|
-
# domain's own `.bluebook` would (same `on_impl`/`trigger_impl`,
|
|
165
|
-
# same `PolicyInterpreter` runtime — reusing `PolicyBuilder`
|
|
166
|
-
# directly, zero new runtime semantics). What's new is only where
|
|
167
|
-
# it can be written: a cross-domain reaction is a wiring/context-
|
|
168
|
-
# mapping decision (this chapter conforming to a foreign chapter's
|
|
169
|
-
# published event), the same kind of decision `port`/
|
|
170
|
-
# `uses_framework` already are — not a fact this domain's own
|
|
171
|
-
# model states about itself, which `policy` (inside the bluebook)
|
|
172
|
-
# remains the right word for.
|
|
173
|
-
#
|
|
174
|
-
# Must be a block, not `translates Event, into: Command` — a flat
|
|
175
|
-
# call's arguments are evaluated eagerly, under this builder's own
|
|
176
|
-
# `ConstShim` resolver (`BindingProxy.namespace`, set up by
|
|
177
|
-
# `self.build` below), which mints a `BindingProxy` instance per
|
|
178
|
-
# segment and cannot answer a further `::` (it is not a Module) —
|
|
179
|
-
# a multi-segment reference like `Deploy::Tenant::TenantProvisioned`
|
|
180
|
-
# would raise before this method ever ran. `port_impl`'s own
|
|
181
|
-
# `ConstShim.with(->(const) { const })` swap only works because
|
|
182
|
-
# its own callers never pass a multi-segment bare constant as an
|
|
183
|
-
# eagerly-evaluated argument — everything of that shape lives
|
|
184
|
-
# inside its block, evaluated later, under the swapped resolver.
|
|
185
|
-
# A block defers evaluation the same way; a flat call cannot.
|
|
186
|
-
#
|
|
187
|
-
# @param name [String, Symbol] the reaction's name
|
|
188
|
-
# @yield the `on`/`trigger` block, evaluated later under the scoped resolver
|
|
189
|
-
# @return [Array<Bluebook::Policy>] the chapter's policies, with the new one appended
|
|
190
|
-
# @raise [Malformed] if no bluebook is registered for this domain to attach the reaction to
|
|
73
|
+
# A cross-domain reaction, built as the same `Policy` an in-bluebook `policy` block would.
|
|
74
|
+
# Must be a block — the eager const resolver here can't handle multi-segment references.
|
|
191
75
|
def translates(name, &block)
|
|
192
76
|
bluebook_ir = Hecks.current_registry.bluebook(@domain) or
|
|
193
77
|
raise Malformed, "#{@domain} declares no such bluebook — translates needs one to attach its reaction to"
|
|
194
78
|
|
|
195
|
-
# Same resolver
|
|
196
|
-
#
|
|
197
|
-
# `ScopedConstant`, not the bare passthrough `port_impl` swaps
|
|
198
|
-
# to, because `on`/`trigger` here take genuinely multi-segment
|
|
199
|
-
# references (`Deploy::Tenant::TenantProvisioned`), not a
|
|
200
|
-
# single-segment type name.
|
|
79
|
+
# Same resolver `policy` blocks use for `on`/`trigger` — a ScopedConstant, not the bare
|
|
80
|
+
# passthrough `port_impl` swaps to, since these take multi-segment references.
|
|
201
81
|
resolver = ->(const) { ConstShim::ScopedConstant.for(const) }
|
|
202
82
|
built = ConstShim.with(resolver) { PolicyBuilder.build(name, &block) }
|
|
203
83
|
|
|
@@ -206,58 +86,18 @@ module Hecks
|
|
|
206
86
|
end
|
|
207
87
|
|
|
208
88
|
# Assembles the collected binds, subscriptions and attachments into a `Hecksagon`.
|
|
209
|
-
#
|
|
210
|
-
# No ungoverned-role check here — see
|
|
211
|
-
# Registry::Verification#refuse_ungoverned_roles!. It lives outside
|
|
212
|
-
# per-block `build`, alongside `environment:`
|
|
213
|
-
# (Runtime::Loader.boot's comment has the provenance): a domain
|
|
214
|
-
# split across multiple hecksagon blocks (base + an
|
|
215
|
-
# `environments/<name>.hecksagon` overlay) would have every
|
|
216
|
-
# block but the one declaring `uses_framework "Governance"`
|
|
217
|
-
# refused here, even though `Registry#add_hecksagon` merges them
|
|
218
|
-
# into one Hecksagon before anything ever dispatches against it.
|
|
219
|
-
# Checking the merged result once, at verify! time — after every
|
|
220
|
-
# file for this domain has loaded — is both more permissive (no
|
|
221
|
-
# need to repeat `uses_framework` in every file) and strictly
|
|
222
|
-
# more correct (a check against an incomplete, not-yet-merged
|
|
223
|
-
# hecksagon can never see the real final shape).
|
|
224
|
-
#
|
|
225
|
-
# @return [Bluebook::Hecksagon] this block's wiring, which `Registry#add_hecksagon` merges
|
|
226
|
-
# with any other block declared for the same domain
|
|
89
|
+
# No ungoverned-role check here — it runs once on the merged result at verify! time.
|
|
227
90
|
def build
|
|
228
91
|
Hecksagon.new(domain: @domain, binds: @binds, subscriptions: @subscriptions,
|
|
229
92
|
framework_members: @framework_members, vendored_bluebooks: @vendored_bluebooks,
|
|
230
93
|
bounded: @bounded, translates: @translates)
|
|
231
94
|
end
|
|
232
95
|
|
|
233
|
-
# Records any verb the grammar
|
|
234
|
-
#
|
|
235
|
-
# **Domain-level default binds** — `persisted_by "Heki"` bare, at the top
|
|
236
|
-
# of a hecksagon block, applies to every aggregate in this domain
|
|
237
|
-
# that doesn't declare its own override. Mirrors `BindingProxy`'s own
|
|
238
|
-
# `method_missing` one level down (`aggregate:` filled in there,
|
|
239
|
-
# `nil` here) — generic over verb name, not hardcoded to
|
|
240
|
-
# `persisted_by`/`projected_by` specifically, so any future verb
|
|
241
|
-
# gets a domain-level default for free too. See `Hecksagon#bind_for`
|
|
242
|
-
# for the fallback lookup this feeds.
|
|
243
|
-
#
|
|
244
|
-
# @param verb [Symbol] the word called, such as `:persisted_by`
|
|
245
|
-
# @param args [Array<Object>] positional arguments; the first names the adapter
|
|
246
|
-
# @param kwargs [Hash{Symbol => Object}] keyword arguments; `:role` is kept on the bind
|
|
247
|
-
# @yield an optional block, called once after the bind is recorded
|
|
248
|
-
# @return [Object] this builder after recording a bind, or the grammar word's own result
|
|
249
|
-
# when `verb` is one the `Hecksagon` grammar admits
|
|
250
|
-
# @raise [NoMethodError] if `verb` is no grammar word and names no adapter
|
|
251
|
-
# @raise [Bluebook::DSL::Malformed] if the grammar admits `verb` only in another context,
|
|
252
|
-
# or admits it here and its implementation refuses the declaration
|
|
96
|
+
# Records any verb the grammar doesn't own as a domain-wide default bind, e.g. bare
|
|
97
|
+
# `persisted_by "Heki"` at the top of a block, applied unless an aggregate overrides it.
|
|
253
98
|
def method_missing(verb, *args, **kwargs, &block)
|
|
254
|
-
#
|
|
255
|
-
#
|
|
256
|
-
# `WordGate#word_gate_dispatch`'s own header for why this class
|
|
257
|
-
# needs to call it explicitly rather than including it the
|
|
258
|
-
# ordinary way. Only once that says "not admitted" does the
|
|
259
|
-
# genuinely open-ended `persisted_by "Heki"`-style bind
|
|
260
|
-
# vocabulary below get a turn.
|
|
99
|
+
# Grammar words (like `port`) get first refusal via explicit dispatch; only when that's
|
|
100
|
+
# not admitted does the open-ended `persisted_by`-style bind vocabulary below apply.
|
|
261
101
|
result = word_gate_dispatch(verb, args, kwargs, block)
|
|
262
102
|
return result unless result.equal?(WordGate::NOT_ADMITTED)
|
|
263
103
|
|
|
@@ -272,14 +112,6 @@ module Hecks
|
|
|
272
112
|
|
|
273
113
|
# Evaluates a `Hecks.hecksagon` block with bare `Domain::Aggregate` constants resolving to
|
|
274
114
|
# bind-collecting proxies, and returns the wiring it declared.
|
|
275
|
-
#
|
|
276
|
-
# @param domain [String] name of the domain being wired
|
|
277
|
-
# @yield the hecksagon body, evaluated with the builder as `self`; may be omitted
|
|
278
|
-
# @return [Bluebook::Hecksagon] the declared wiring
|
|
279
|
-
# @raise [Bluebook::DSL::Malformed] if a `port` names no registered bluebook or aggregate,
|
|
280
|
-
# or declares a shape the port grammar refuses
|
|
281
|
-
# @raise [Runtime::WiringError] if `uses_framework` or `uses_embryonaut_bluebook` names
|
|
282
|
-
# something that cannot be found
|
|
283
115
|
def self.build(domain, &block)
|
|
284
116
|
builder = new(domain)
|
|
285
117
|
resolver = ->(name) { BindingProxy.namespace(name, builder.binds) }
|
|
@@ -1,68 +1,19 @@
|
|
|
1
1
|
module Hecks
|
|
2
2
|
module Bluebook
|
|
3
3
|
module DSL
|
|
4
|
-
# `identified_by
|
|
5
|
-
#
|
|
6
|
-
# resolve_pending_identity! go"): a piece's own identity cannot
|
|
7
|
-
# spell differently from its aggregate's, and until this slice it
|
|
8
|
-
# was hand-duplicated onto both rather than shared.
|
|
9
|
-
#
|
|
10
|
-
# A separate module from AttributeCollector on purpose — every
|
|
11
|
-
# `attribute()`-taking builder (Command, Query, PortOperation,
|
|
12
|
-
# ValueObject, ...) `include`s that one too, and none of them
|
|
13
|
-
# declares an identity of its own ; folding `identified_by` in
|
|
14
|
-
# there made it answer for six builders that never earned the
|
|
15
|
-
# word (`syntax_conformance_spec.rb` catches exactly this — a
|
|
16
|
-
# builder answering a method the grammar never grants it).
|
|
17
|
-
#
|
|
18
|
-
# Requires its includer to also `include AttributeCollector`
|
|
19
|
-
# (for `attributes`/`resolve_identity_field!`/`resolve_identity_
|
|
20
|
-
# type!`, still declared there since every includer of that
|
|
21
|
-
# module needs them) and to supply `identity_pool` (private) —
|
|
22
|
-
# the value-object list a bare field's own type resolves
|
|
23
|
-
# against: AggregateBuilder's own `@value_objects + closed_sets`,
|
|
24
|
-
# or EntityBuilder's owner's, since a piece mints none of its own.
|
|
4
|
+
# `identified_by`, shared by AggregateBuilder and EntityBuilder (ADR 0025).
|
|
5
|
+
# The includer must include AttributeCollector and define a private `identity_pool`.
|
|
25
6
|
module IdentityDeclaration
|
|
26
|
-
# Records which
|
|
27
|
-
# resolution until build time.
|
|
28
|
-
#
|
|
29
|
-
# There are three live forms, deliberately distinguishable at the
|
|
30
|
-
# declaration site:
|
|
7
|
+
# Records which `identified_by` form a builder declared; resolution waits for build time.
|
|
31
8
|
#
|
|
32
9
|
# identified_by AccountNumber, as: :number # one identity concept
|
|
33
10
|
# identified_by do ... end # a bespoke concept
|
|
34
11
|
# identified_by :branch, :number # an existing compound key
|
|
35
12
|
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
# `calls:` column, so `GenericDispatch` forwards `identified_by` here unchanged, both
|
|
41
|
-
# after boot (reading the live grammar table) and during it
|
|
42
|
-
# (`GenericDispatch::BOOTSTRAP_CALLS_FALLBACK`, which carries every `calls:`-routed row
|
|
43
|
-
# unconditionally, not a hand-picked bootstrap-reachable subset — though this one is
|
|
44
|
-
# exercised during boot too, since every self-hosted aggregate/entity declares an identity).
|
|
45
|
-
# Dispatches across the three live forms documented above (value-
|
|
46
|
-
# object + block, single type target, single/compound field
|
|
47
|
-
# target), each an early return that sets exactly one pending
|
|
48
|
-
# ivar. Splitting per form would need each branch's own `return`-
|
|
49
|
-
# with-nil semantics and the shared `@name`/`identity_pool`
|
|
50
|
-
# threaded back out as parameters, for no gain beyond what the
|
|
51
|
-
# three-forms comment above already documents.
|
|
52
|
-
#
|
|
53
|
-
# @param targets [Array<Symbol, Module>] zero or more identity targets: a value-object
|
|
54
|
-
# type (a bareword, resolved by `ConstShim` to a `Module`), one or more attribute-name
|
|
55
|
-
# symbols for a field or compound key, or empty when `definition` is given
|
|
56
|
-
# @param as [Symbol, nil] the field name to mint for a value-object-type target; not
|
|
57
|
-
# accepted with a field or compound-key target
|
|
58
|
-
# @yield a bespoke value-object body, `instance_eval`'d by `ValueObjectBuilder.build` to
|
|
59
|
-
# mint the identity's own anonymous value object
|
|
60
|
-
# @return [Array<Symbol>, Array<String>, nil] `targets` when a compound key is declared,
|
|
61
|
-
# the resolved identity paths from `legacy_identified_by` in shadow-parsing mode, or
|
|
62
|
-
# `nil` otherwise; callers reach this through `GenericDispatch`, which discards it
|
|
63
|
-
# @raise [Bluebook::DSL::Malformed] if `identified_by` was already called, combines a
|
|
64
|
-
# block with targets, names no identity, mixes a value-object type with field names,
|
|
65
|
-
# passes `as:` with a field or compound key, or the block declares no attributes
|
|
13
|
+
# @param targets [Array<Symbol, Module>] a value-object type or attribute names
|
|
14
|
+
# @param as [Symbol, nil] the field name to mint for a value-object-type target
|
|
15
|
+
# @yield a bespoke value-object body for the identity's own value object
|
|
16
|
+
# @raise [Bluebook::DSL::Malformed] on a repeat declaration or an invalid mix of forms
|
|
66
17
|
# rubocop:disable-next Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
67
18
|
def identified_by_impl(*targets, as: nil, &definition)
|
|
68
19
|
return legacy_identified_by(*targets, as: as, &definition) if MetaValidator.shadow_parsing?
|
|
@@ -84,20 +35,8 @@ module Hecks
|
|
|
84
35
|
&definition
|
|
85
36
|
)
|
|
86
37
|
rescue NameError => e
|
|
87
|
-
#
|
|
88
|
-
#
|
|
89
|
-
# on to know a normal parse genuinely could not read this text
|
|
90
|
-
# (only `Malformed` triggers its shadow-mode retry, era_guard.rb's
|
|
91
|
-
# own comment). The old `identified_by { name.value }` — a block
|
|
92
|
-
# whose text was never called, only extracted (legacy_
|
|
93
|
-
# identified_by, below) — is exactly this shape: read under the
|
|
94
|
-
# current grammar it is instead instance_eval'd as a value-object
|
|
95
|
-
# definition, and a bare identifier like `name` inside it resolves
|
|
96
|
-
# to nothing WordGate#method_missing recognizes, so Ruby itself
|
|
97
|
-
# raises NameError. Left uncaught, that NameError skipped
|
|
98
|
-
# shadow_parse's rescue entirely and reached callers as a raw
|
|
99
|
-
# crash instead of the frozen-era fallback that exists for
|
|
100
|
-
# precisely this text.
|
|
38
|
+
# Must raise Malformed: EraGuard.shadow_parse retries frozen text only on
|
|
39
|
+
# Malformed, and a bare identifier in an old block form raises NameError here.
|
|
101
40
|
raise Malformed,
|
|
102
41
|
"#{@name}.identified_by do ... end could not be read as a value-object " \
|
|
103
42
|
"definition: #{e.message}"
|
|
@@ -122,10 +61,7 @@ module Hecks
|
|
|
122
61
|
raise Malformed,
|
|
123
62
|
"#{@name}.identified_by takes no as: — name the declared field itself"
|
|
124
63
|
end
|
|
125
|
-
# Transitional
|
|
126
|
-
# corpus still contain this form. Keep it readable until their
|
|
127
|
-
# exemplar-led migration is complete; the final lifecycle cutover
|
|
128
|
-
# replaces this assignment with the targeted refusal.
|
|
64
|
+
# Transitional: the self-hosted language and live corpus still use this form.
|
|
129
65
|
@identity_field_pending = field
|
|
130
66
|
return
|
|
131
67
|
end
|
|
@@ -141,11 +77,7 @@ module Hecks
|
|
|
141
77
|
|
|
142
78
|
private
|
|
143
79
|
|
|
144
|
-
# Resolves
|
|
145
|
-
# pending, against `identity_pool` — the includer's own private
|
|
146
|
-
# hook. Called at build time, not at `identified_by`'s own call
|
|
147
|
-
# time — see `AttributeCollector#resolve_identity_field!`'s own
|
|
148
|
-
# comment on why.
|
|
80
|
+
# Resolves the pending identity against `identity_pool` at build time, not call time.
|
|
149
81
|
def resolve_pending_identity!
|
|
150
82
|
if @identity_type_pending
|
|
151
83
|
type, as, insert_at = @identity_type_pending
|
|
@@ -162,11 +94,7 @@ module Hecks
|
|
|
162
94
|
def identity_type?(target) = target.to_s.match?(/\A[A-Z]/)
|
|
163
95
|
|
|
164
96
|
def refuse_second_identity!
|
|
165
|
-
#
|
|
166
|
-
# may be replaced by the new declaration later in the same builder.
|
|
167
|
-
# This keeps existing builder fixtures/source readable while their
|
|
168
|
-
# exemplar is migrated. Once one-symbol identity is retired this
|
|
169
|
-
# compatibility branch disappears with it.
|
|
97
|
+
# Transitional: a one-symbol declaration may still be replaced by a later one.
|
|
170
98
|
if @identity_field_pending && !@identity_type_pending && !@identity_fields_pending
|
|
171
99
|
@identity_field_pending = nil
|
|
172
100
|
return
|
|
@@ -178,10 +106,7 @@ module Hecks
|
|
|
178
106
|
raise Malformed, "#{@name} declares identified_by more than once"
|
|
179
107
|
end
|
|
180
108
|
|
|
181
|
-
#
|
|
182
|
-
# multi-line block), kept alive only for `EraGuard.shadow_parse`
|
|
183
|
-
# (S0a, ADR 0025) to still make sense of frozen era text that used
|
|
184
|
-
# them; unreachable outside `MetaValidator.shadow_parsing?`.
|
|
109
|
+
# Parses the spellings frozen era text uses, for `EraGuard.shadow_parse`.
|
|
185
110
|
def legacy_identified_by(*targets, as:, &path)
|
|
186
111
|
target = targets.first
|
|
187
112
|
if target
|
|
@@ -2,11 +2,7 @@ require_relative "word_gate"
|
|
|
2
2
|
module Hecks
|
|
3
3
|
module Bluebook
|
|
4
4
|
module DSL
|
|
5
|
-
# Parses a `lifecycle :field, default: ... do transition ... end`
|
|
6
|
-
# block into a `Lifecycle` — the field an aggregate or entity's own
|
|
7
|
-
# state machine lives on, its starting value, and the `command =>
|
|
8
|
-
# target_state` transition table (with an optional `from:` guard)
|
|
9
|
-
# each `transition_impl` call adds a row to.
|
|
5
|
+
# Parses a `lifecycle :field, default: ... do transition ... end` block into a `Lifecycle`.
|
|
10
6
|
class LifecycleBuilder
|
|
11
7
|
GRAMMAR_CONTEXT = "Lifecycle".freeze
|
|
12
8
|
|
|
@@ -22,11 +18,7 @@ module Hecks
|
|
|
22
18
|
|
|
23
19
|
# Records one transition row per command in `mapping`, all sharing its `from:` guard.
|
|
24
20
|
#
|
|
25
|
-
#
|
|
26
|
-
# through its `calls:` column — item #13's full metaprogrammed
|
|
27
|
-
# dispatch (slice 4c). Bootstrap-reachable (syntax.bluebook's
|
|
28
|
-
# own Keyword/Argument entities describe their `status`
|
|
29
|
-
# lifecycle with it), so in `BOOTSTRAP_CALLS_FALLBACK`.
|
|
21
|
+
# Listed in `BOOTSTRAP_CALLS_FALLBACK` because syntax.bluebook uses it during boot.
|
|
30
22
|
#
|
|
31
23
|
# @param mapping [Hash{String, Symbol => String, Symbol, Array<String>}] command name to
|
|
32
24
|
# target state, as in `"Purchase" => "sold"`; the optional `:from` key holds the
|
|
@@ -70,17 +62,11 @@ module Hecks
|
|
|
70
62
|
|
|
71
63
|
private
|
|
72
64
|
|
|
73
|
-
# C5.3 (docs/semantics/bluebook-semantics.md)
|
|
74
|
-
#
|
|
75
|
-
# `
|
|
76
|
-
# machine can be read whole. Two transitions for one command from
|
|
77
|
-
# disjoint states are the legitimate shape (`match_transition`
|
|
78
|
-
# picks by the current state) and stay. A `from:` naming a state
|
|
79
|
-
# nothing declares is not refused here: it is a reachability
|
|
80
|
-
# finding `bin/model_check` already reports (unreachable state,
|
|
81
|
-
# dead transition), and a bluebook may declare it on purpose.
|
|
65
|
+
# C5.3 (docs/semantics/bluebook-semantics.md): overlapping `from:` sets for one command
|
|
66
|
+
# are refused. Disjoint sets are legitimate. An undeclared `from:` state is left to
|
|
67
|
+
# `bin/model_check`.
|
|
82
68
|
def refuse_ambiguity!
|
|
83
|
-
return if MetaValidator.shadow_parsing? # frozen era text is
|
|
69
|
+
return if MetaValidator.shadow_parsing? # frozen era text is exempt
|
|
84
70
|
|
|
85
71
|
@transitions.each_with_index do |(command, transition), index|
|
|
86
72
|
earlier = @transitions[0...index].find do |other_command, other|
|