hecks 2.7.0 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/exe/hecks +11 -0
- data/lib/hecks/adapters/driven/claude_code.rb +4 -104
- data/lib/hecks/adapters/driven/d1.rb +44 -237
- data/lib/hecks/adapters/driven/folder.rb +17 -76
- data/lib/hecks/adapters/driven/google_authentication.rb +15 -49
- data/lib/hecks/adapters/driven/governance_authorization.rb +23 -70
- data/lib/hecks/adapters/driven/heki/journal.rb +8 -41
- data/lib/hecks/adapters/driven/heki/saga_store.rb +12 -54
- data/lib/hecks/adapters/driven/heki/snapshot.rb +4 -12
- data/lib/hecks/adapters/driven/heki.rb +13 -42
- data/lib/hecks/adapters/driven/identity_registry.rb +3 -14
- data/lib/hecks/adapters/driven/in_memory_ordering.rb +9 -26
- data/lib/hecks/adapters/driven/in_process_key_vault.rb +2 -14
- data/lib/hecks/adapters/driven/lambda/client.rb +10 -51
- data/lib/hecks/adapters/driven/lambda.rb +10 -84
- data/lib/hecks/adapters/driven/local_storage.rb +5 -40
- data/lib/hecks/adapters/driven/memory.rb +18 -99
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +5 -21
- data/lib/hecks/adapters/driven/postgres/codec.rb +6 -28
- data/lib/hecks/adapters/driven/postgres/outbox.rb +3 -12
- data/lib/hecks/adapters/driven/postgres/reconnect.rb +4 -30
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +34 -108
- data/lib/hecks/adapters/driven/postgres.rb +145 -134
- data/lib/hecks/adapters/driven/postgres_era.adapter +4 -15
- data/lib/hecks/adapters/driven/prism.rb +7 -30
- data/lib/hecks/adapters/driven/sql_query_builder.rb +21 -121
- data/lib/hecks/adapters/driven/sqlite/codec.rb +8 -40
- data/lib/hecks/adapters/driven/sqlite/projection.rb +26 -82
- data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +40 -84
- data/lib/hecks/adapters/driven/sqlite.rb +128 -65
- data/lib/hecks/adapters/driven/tenant_provisioner.rb +15 -37
- data/lib/hecks/adapters/driven.rb +5 -36
- data/lib/hecks/adapters/driving/github_webhook.rb +8 -76
- data/lib/hecks/behaviors/dsl.rb +7 -25
- data/lib/hecks/behaviors/expectations.rb +32 -142
- data/lib/hecks/behaviors/ir.rb +7 -20
- data/lib/hecks/behaviors/rspec.rb +6 -17
- data/lib/hecks/behaviors/runner.rb +10 -34
- data/lib/hecks/behaviors.rb +4 -8
- data/lib/hecks/bluebook/aggregate.rb +9 -75
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +9 -38
- data/lib/hecks/bluebook/assembly/build.rb +4 -15
- data/lib/hecks/bluebook/assembly/contract.rb +15 -136
- data/lib/hecks/bluebook/assembly/contracts.rb +54 -174
- data/lib/hecks/bluebook/assembly/marks.rb +31 -223
- data/lib/hecks/bluebook/assembly/specializer.rb +6 -52
- data/lib/hecks/bluebook/assembly.rb +6 -45
- data/lib/hecks/bluebook/attribute.rb +12 -61
- data/lib/hecks/bluebook/behaviour/aggregate.rb +10 -39
- data/lib/hecks/bluebook/behaviour/attribute.rb +3 -14
- data/lib/hecks/bluebook/behaviour/chapter.rb +17 -42
- data/lib/hecks/bluebook/behaviour/command.rb +14 -66
- data/lib/hecks/bluebook/behaviour/domain_port.rb +4 -20
- data/lib/hecks/bluebook/behaviour/entity.rb +7 -27
- data/lib/hecks/bluebook/behaviour/hexagon.rb +23 -41
- data/lib/hecks/bluebook/behaviour/lifecycle.rb +15 -40
- data/lib/hecks/bluebook/behaviour/policy.rb +23 -52
- data/lib/hecks/bluebook/behaviour/process_manager.rb +30 -57
- data/lib/hecks/bluebook/behaviour/read_model.rb +38 -26
- data/lib/hecks/bluebook/behaviour/traits.rb +27 -64
- data/lib/hecks/bluebook/behaviour/value_object.rb +5 -24
- data/lib/hecks/bluebook/capabilities.rb +17 -49
- data/lib/hecks/bluebook/chapter.rb +10 -48
- data/lib/hecks/bluebook/command.rb +23 -81
- data/lib/hecks/bluebook/domain_port.rb +14 -63
- data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +50 -229
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +50 -377
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +33 -204
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +17 -65
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +86 -708
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +56 -170
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +1 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +74 -546
- data/lib/hecks/bluebook/dsl/const_shim.rb +8 -41
- data/lib/hecks/bluebook/dsl/domain_port_builder.rb +12 -87
- data/lib/hecks/bluebook/dsl/entity_builder.rb +44 -330
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +20 -269
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +26 -189
- data/lib/hecks/bluebook/dsl/identity_declaration.rb +13 -88
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +6 -20
- data/lib/hecks/bluebook/dsl/policy_builder.rb +16 -88
- data/lib/hecks/bluebook/dsl/port_builder.rb +2 -6
- data/lib/hecks/bluebook/dsl/port_operation_builder.rb +22 -96
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +31 -184
- data/lib/hecks/bluebook/dsl/query_builder.rb +11 -42
- data/lib/hecks/bluebook/dsl/read_model_builder.rb +75 -201
- data/lib/hecks/bluebook/dsl/rule_reference.rb +22 -163
- data/lib/hecks/bluebook/dsl/translation_builder.rb +28 -114
- data/lib/hecks/bluebook/dsl/value_object_builder.rb +10 -124
- data/lib/hecks/bluebook/dsl/word_gate.rb +16 -162
- data/lib/hecks/bluebook/dsl/world_builder.rb +19 -106
- data/lib/hecks/bluebook/entity.rb +13 -71
- data/lib/hecks/bluebook/expression/ast_json.rb +24 -190
- data/lib/hecks/bluebook/expression/ast_reader.rb +12 -54
- data/lib/hecks/bluebook/expression/canonical_form.rb +11 -88
- data/lib/hecks/bluebook/expression/evaluator.rb +47 -295
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +30 -147
- data/lib/hecks/bluebook/expression/resolver.rb +37 -660
- data/lib/hecks/bluebook/hexagon.rb +5 -28
- data/lib/hecks/bluebook/lifecycle.rb +5 -16
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -7
- data/lib/hecks/bluebook/meta_validator/judge.rb +111 -361
- data/lib/hecks/bluebook/meta_validator/plan.rb +33 -162
- data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -7
- data/lib/hecks/bluebook/meta_validator/readings.rb +56 -342
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +24 -176
- data/lib/hecks/bluebook/meta_validator/shapes.rb +54 -268
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +47 -308
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +7 -43
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -18
- data/lib/hecks/bluebook/meta_validator.rb +79 -349
- data/lib/hecks/bluebook/model_check/client_profile.rb +10 -91
- data/lib/hecks/bluebook/model_check.rb +102 -600
- data/lib/hecks/bluebook/pattern_subset.rb +11 -69
- data/lib/hecks/bluebook/process_manager.rb +13 -83
- data/lib/hecks/bluebook/project_loader.rb +3 -39
- data/lib/hecks/bluebook/project_register.rb +12 -60
- data/lib/hecks/bluebook/query.rb +9 -48
- data/lib/hecks/bluebook/read_model.rb +57 -81
- data/lib/hecks/bluebook/reference.rb +7 -41
- data/lib/hecks/bluebook/smoke_test.rb +8 -98
- data/lib/hecks/bluebook/synthesizer.rb +13 -62
- data/lib/hecks/bluebook/translation.rb +26 -62
- data/lib/hecks/bluebook/value_object.rb +11 -36
- data/lib/hecks/bluebook.rb +5 -22
- data/lib/hecks/cache_dir.rb +84 -0
- data/lib/hecks/cli/document.rb +86 -0
- data/lib/hecks/cli/ir.rb +45 -0
- data/lib/hecks/cli/mcp.rb +31 -0
- data/lib/hecks/cli/mcp_door.rb +366 -0
- data/lib/hecks/cli/model_check.rb +203 -0
- data/lib/hecks/cli/project_cli.rb +90 -0
- data/lib/hecks/cli/project_diagrams.rb +36 -0
- data/lib/hecks/cli/run.rb +173 -0
- data/lib/hecks/cli/smoke_test.rb +45 -0
- data/lib/hecks/cli/stores.rb +53 -0
- data/lib/hecks/cli.rb +160 -0
- data/lib/hecks/construct.rb +8 -34
- data/lib/hecks/deploy/bluebook/deploy.bluebook +33 -142
- data/lib/hecks/deploy/bluebook/deploy.hecksagon +2 -9
- data/lib/hecks/embryonaut_bluebook/lock.rb +3 -35
- data/lib/hecks/embryonaut_bluebook/shape.rb +1 -17
- data/lib/hecks/embryonaut_bluebook/vendor.rb +8 -53
- data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +4 -19
- data/lib/hecks/embryonaut_bluebook.rb +4 -71
- data/lib/hecks/facade/cli_door.rb +24 -106
- data/lib/hecks/facade/cli_runner.rb +28 -172
- data/lib/hecks/facade/command_request.rb +13 -33
- data/lib/hecks/facade/handle.rb +34 -121
- data/lib/hecks/facade/json_door.rb +31 -146
- data/lib/hecks/facade/surface/aggregate_door.rb +39 -104
- data/lib/hecks/facade/surface/chapter.rb +10 -54
- data/lib/hecks/facade/surface.rb +8 -23
- data/lib/hecks/facade.rb +10 -25
- data/lib/hecks/forms/app.rb +15 -70
- data/lib/hecks/forms/command_form_renderer.rb +10 -29
- data/lib/hecks/forms/field_renderer.rb +17 -156
- data/lib/hecks/forms/field_shape.rb +30 -222
- data/lib/hecks/forms/html.rb +12 -47
- data/lib/hecks/forms/index_renderer.rb +1 -4
- data/lib/hecks/forms/page.rb +3 -9
- data/lib/hecks/forms/params.rb +14 -60
- data/lib/hecks/forms/port_argument.rb +2 -19
- data/lib/hecks/forms/query_form_renderer.rb +4 -79
- data/lib/hecks/forms/record_renderer.rb +8 -75
- data/lib/hecks/forms/record_table.rb +7 -50
- data/lib/hecks/forms/reference_options.rb +3 -30
- data/lib/hecks/forms/value_object_shape.rb +8 -35
- data/lib/hecks/forms.rb +5 -33
- data/lib/hecks/fqn.rb +5 -12
- data/lib/hecks/framework/bluebook/compliance.bluebook +16 -65
- data/lib/hecks/framework/bluebook/console_settings.bluebook +47 -134
- data/lib/hecks/framework/bluebook/framework.hecksagon +5 -14
- data/lib/hecks/framework/bluebook/governance.bluebook +13 -34
- data/lib/hecks/framework/bluebook/identity.bluebook +11 -26
- data/lib/hecks/framework/bluebook/privacy.bluebook +8 -33
- data/lib/hecks/framework.rb +11 -80
- data/lib/hecks/freezer.rb +5 -39
- data/lib/hecks/grammar/expression.bluebook +15 -40
- data/lib/hecks/grammar/translation.bluebook +3 -6
- data/lib/hecks/grammar.rb +16 -41
- data/lib/hecks/ir.rb +14 -83
- data/lib/hecks/language/adapter.bluebook +2 -7
- data/lib/hecks/language/bluebook/aggregate.bluebook +56 -221
- data/lib/hecks/language/bluebook/attaches/paging.bluebook +6 -15
- data/lib/hecks/language/bluebook/bluebook.bluebook +15 -83
- data/lib/hecks/language/bluebook/bluebook.hecksagon +3 -15
- data/lib/hecks/language/bluebook/command.bluebook +27 -144
- data/lib/hecks/language/bluebook/entity.bluebook +24 -97
- data/lib/hecks/language/bluebook/policy.bluebook +16 -67
- data/lib/hecks/language/bluebook/process_manager.bluebook +28 -151
- data/lib/hecks/language/bluebook/projection.bluebook +126 -60
- data/lib/hecks/language/bluebook/query.bluebook +12 -43
- data/lib/hecks/language/bluebook/shape.bluebook +23 -73
- data/lib/hecks/language/bluebook/syntax.bluebook +51 -262
- data/lib/hecks/language/bluebook/vocabulary.bluebook +98 -197
- data/lib/hecks/language/hecksagon/adapter_binding.bluebook +3 -10
- data/lib/hecks/language/hecksagon/domain_port.bluebook +4 -19
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +6 -25
- data/lib/hecks/language/hecksagon/port_operation.bluebook +3 -14
- data/lib/hecks/language/oidc.json +35 -0
- data/lib/hecks/language/port.bluebook +4 -17
- data/lib/hecks/language/translation/translation.bluebook +3 -9
- data/lib/hecks/language/translation/translation_aggregate.bluebook +5 -24
- data/lib/hecks/language/world/wiring.bluebook +1 -3
- data/lib/hecks/language/world/world.bluebook +5 -7
- data/lib/hecks/literal.rb +8 -50
- data/lib/hecks/mcp_door_scope.rb +95 -0
- data/lib/hecks/mcp_stdio_guard.rb +4 -41
- data/lib/hecks/naming.rb +29 -137
- data/lib/hecks/ports/access_control.rb +7 -23
- data/lib/hecks/ports/agent/answers.rb +5 -23
- data/lib/hecks/ports/agent.rb +47 -172
- data/lib/hecks/ports/authentication.rb +12 -39
- data/lib/hecks/ports/authorization.rb +16 -43
- data/lib/hecks/ports/clock.rb +5 -45
- data/lib/hecks/ports/extraction.rb +7 -12
- data/lib/hecks/ports/identity_assignment.rb +8 -29
- data/lib/hecks/ports/identity_generation.rb +6 -29
- data/lib/hecks/ports/identity_resolution.rb +2 -10
- data/lib/hecks/ports/key_vault.rb +9 -45
- data/lib/hecks/ports/persistence/append_only.rb +62 -65
- data/lib/hecks/ports/persistence/binding_policy.rb +4 -14
- data/lib/hecks/ports/persistence/codec_boundary.rb +20 -80
- data/lib/hecks/ports/persistence/null_saga_store.rb +4 -20
- data/lib/hecks/ports/persistence/plugin.rb +13 -42
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +38 -141
- data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +15 -115
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +16 -84
- data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +7 -26
- data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +3 -22
- data/lib/hecks/ports/persistence/plugins/era/lineage.rb +55 -181
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/events.rb +77 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +12 -122
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +28 -128
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +73 -474
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +31 -124
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +45 -219
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +13 -108
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +18 -75
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +9 -49
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +6 -123
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +23 -55
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +14 -72
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +7 -16
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +14 -115
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +13 -45
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +127 -554
- data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +13 -63
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +2 -17
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +3 -14
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +13 -58
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -17
- data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +9 -26
- data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +9 -25
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +22 -122
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +34 -123
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +5 -12
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +3 -9
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -14
- data/lib/hecks/ports/persistence/plugins/era.rb +4 -23
- data/lib/hecks/ports/persistence/postgres_dump/connection.rb +7 -23
- data/lib/hecks/ports/persistence/postgres_dump.rb +4 -35
- data/lib/hecks/ports/persistence/remote_runtime.rb +2 -24
- data/lib/hecks/ports/persistence/repository_factory.rb +8 -27
- data/lib/hecks/ports/persistence/state_codec.rb +23 -103
- data/lib/hecks/ports/persistence.rb +7 -14
- data/lib/hecks/ports/projection.rb +42 -84
- data/lib/hecks/ports/query/in_memory.rb +10 -58
- data/lib/hecks/ports/query/ordering.rb +11 -32
- data/lib/hecks/ports/query.rb +14 -37
- data/lib/hecks/ports.rb +2 -8
- data/lib/hecks/projections/bootstrap_table.rb +11 -43
- data/lib/hecks/projections/deploy/fargate/assembly.rb +2 -15
- data/lib/hecks/projections/deploy/fargate/cdn.rb +1 -48
- data/lib/hecks/projections/deploy/fargate/cdn_default.rb +2 -11
- data/lib/hecks/projections/deploy/fargate/check.rb +5 -14
- data/lib/hecks/projections/deploy/fargate/containers.rb +3 -78
- data/lib/hecks/projections/deploy/fargate/extras.rb +3 -44
- data/lib/hecks/projections/deploy/fargate/monitoring.rb +0 -44
- data/lib/hecks/projections/deploy/fargate/settings.rb +2 -54
- data/lib/hecks/projections/deploy/fargate/yaml.rb +13 -58
- data/lib/hecks/projections/deploy/fargate.rb +35 -202
- data/lib/hecks/projections/deploy/lambda.rb +151 -679
- data/lib/hecks/projections/deploy/preview/access_yaml.rb +1 -33
- data/lib/hecks/projections/deploy/preview/containers.rb +6 -111
- data/lib/hecks/projections/deploy/preview/routing_yaml.rb +4 -56
- data/lib/hecks/projections/deploy/preview/script.rb +2 -14
- data/lib/hecks/projections/deploy/preview/settings.rb +3 -33
- data/lib/hecks/projections/deploy/preview/task_yaml.rb +2 -38
- data/lib/hecks/projections/deploy/preview/template.rb +2 -58
- data/lib/hecks/projections/deploy/preview.rb +2 -67
- data/lib/hecks/projections/deploy/scripts/settings.rb +3 -25
- data/lib/hecks/projections/deploy/scripts.rb +4 -57
- data/lib/hecks/projections/deploy/shared.rb +47 -146
- data/lib/hecks/projections/deploy/smoke.rb +4 -61
- data/lib/hecks/projections/deploy/template_diff/comparer.rb +3 -25
- data/lib/hecks/projections/deploy/template_diff/loader.rb +2 -11
- data/lib/hecks/projections/deploy/template_diff.rb +5 -57
- data/lib/hecks/projections/diagrams.rb +20 -582
- data/lib/hecks/projections/glossary/html.rb +14 -130
- data/lib/hecks/projections/glossary/markdown.rb +8 -69
- data/lib/hecks/projections/glossary/mermaid.rb +9 -66
- data/lib/hecks/projections/glossary/sensitivity.rb +5 -34
- data/lib/hecks/projections/glossary/sentences.rb +14 -159
- data/lib/hecks/projections/glossary.rb +30 -222
- data/lib/hecks/projections/ir.rb +3 -10
- data/lib/hecks/projections/model/deviations.rb +15 -42
- data/lib/hecks/projections/model.rb +12 -51
- data/lib/hecks/projections/oidc.rb +12 -56
- data/lib/hecks/projections/parser_table.rb +9 -28
- data/lib/hecks/projections/reference.rb +9 -16
- data/lib/hecks/projections/rust_vocabulary.rb +12 -250
- data/lib/hecks/projections/shape.rb +3 -29
- data/lib/hecks/projections/statements.rb +7 -86
- data/lib/hecks/projections/vocabulary.rb +6 -22
- data/lib/hecks/projections.rb +2 -16
- data/lib/hecks/projector/cli_projector.rb +60 -375
- data/lib/hecks/projector/docs_projector.rb +10 -201
- data/lib/hecks/projector/exporter.rb +46 -138
- data/lib/hecks/projector/ir_projector.rb +2 -9
- data/lib/hecks/projector/narrate_projector.rb +15 -189
- data/lib/hecks/projector/target.rb +13 -76
- data/lib/hecks/projector.rb +30 -121
- data/lib/hecks/query_specification/common/comparators.rb +5 -26
- data/lib/hecks/query_specification/common/comparison.rb +35 -143
- data/lib/hecks/query_specification/common/dsl.rb +8 -24
- data/lib/hecks/query_specification/common/null_policy.rb +20 -70
- data/lib/hecks/query_specification/common/options.rb +2 -6
- data/lib/hecks/query_specification/common/where_clause.rb +2 -10
- data/lib/hecks/query_specification/field_path.rb +37 -77
- data/lib/hecks/query_specification/hop_path.rb +12 -76
- data/lib/hecks/release/gem_pin.rb +2 -26
- data/lib/hecks/release/runner/ci_publisher.rb +93 -0
- data/lib/hecks/release/runner/commands.rb +66 -0
- data/lib/hecks/release/runner/console.rb +52 -0
- data/lib/hecks/release/runner/gem_publisher.rb +43 -0
- data/lib/hecks/release/runner/git.rb +48 -0
- data/lib/hecks/release/runner/npm_publisher.rb +75 -0
- data/lib/hecks/release/runner/preflight.rb +104 -0
- data/lib/hecks/release/runner/published.rb +55 -0
- data/lib/hecks/release/runner/tagger.rb +80 -0
- data/lib/hecks/release/runner.rb +215 -0
- data/lib/hecks/rendering.rb +4 -26
- data/lib/hecks/router/namespace_installer.rb +12 -36
- data/lib/hecks/router.rb +4 -8
- data/lib/hecks/runtime/aggregate_lock.rb +8 -33
- data/lib/hecks/runtime/boot_gates.rb +3 -18
- data/lib/hecks/runtime/caller.rb +19 -59
- data/lib/hecks/runtime/capability_graph.rb +5 -21
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +16 -78
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +23 -160
- data/lib/hecks/runtime/command_interpreter.rb +125 -307
- data/lib/hecks/runtime/command_rules/admissibility.rb +95 -366
- data/lib/hecks/runtime/command_rules/arithmetic.rb +66 -196
- data/lib/hecks/runtime/command_rules/authorization.rb +13 -45
- data/lib/hecks/runtime/command_rules/emission.rb +8 -21
- data/lib/hecks/runtime/command_rules/references.rb +23 -202
- data/lib/hecks/runtime/dependency_planning.rb +30 -102
- data/lib/hecks/runtime/dispatcher.rb +82 -241
- data/lib/hecks/runtime/entity_element.rb +40 -462
- data/lib/hecks/runtime/entity_interpreter.rb +65 -220
- data/lib/hecks/runtime/errors.rb +32 -115
- data/lib/hecks/runtime/event.rb +3 -25
- data/lib/hecks/runtime/identity.rb +18 -154
- data/lib/hecks/runtime/instance.rb +18 -150
- data/lib/hecks/runtime/interpreting.rb +11 -70
- data/lib/hecks/runtime/invocation.rb +28 -164
- data/lib/hecks/runtime/loader.rb +48 -186
- data/lib/hecks/runtime/outbox.rb +38 -261
- data/lib/hecks/runtime/policy_interpreter.rb +38 -200
- data/lib/hecks/runtime/port_operation_interpreter.rb +26 -87
- data/lib/hecks/runtime/query_interpreter.rb +45 -187
- data/lib/hecks/runtime/reaction_invocation.rb +36 -138
- data/lib/hecks/runtime/read_model_interpreter.rb +139 -208
- data/lib/hecks/runtime/rebuild_sweep.rb +8 -54
- data/lib/hecks/runtime/reference_hop.rb +8 -81
- data/lib/hecks/runtime/refusal_wording.rb +8 -89
- data/lib/hecks/runtime/registry/saga_persistence.rb +10 -102
- data/lib/hecks/runtime/registry/verification.rb +52 -225
- data/lib/hecks/runtime/registry/world_defaults.rb +4 -53
- data/lib/hecks/runtime/registry.rb +103 -244
- data/lib/hecks/runtime/remote_dispatcher.rb +37 -152
- data/lib/hecks/runtime/routing.rb +4 -15
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +14 -61
- data/lib/hecks/runtime/saga_interpreter.rb +79 -263
- data/lib/hecks/runtime/saga_pending_dispatch.rb +2 -43
- data/lib/hecks/runtime/tenant_check.rb +6 -68
- data/lib/hecks/runtime/tenant_scope.rb +3 -28
- data/lib/hecks/runtime/value/admission.rb +16 -67
- data/lib/hecks/runtime/value/coercion.rb +155 -641
- data/lib/hecks/runtime/value/entity_list_coercion.rb +26 -219
- data/lib/hecks/runtime/value.rb +12 -84
- data/lib/hecks/runtime.rb +17 -65
- data/lib/hecks/storehouse.rb +146 -567
- data/lib/hecks/tenancy/bluebook/tenancy.bluebook +8 -32
- data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +6 -23
- data/lib/hecks/vendoring/git_environment.rb +2 -8
- data/lib/hecks/vendoring/git_source.rb +4 -10
- data/lib/hecks/vendoring.rb +7 -46
- data/lib/hecks/version.rb +3 -14
- data/lib/hecks/vocabulary.rb +5 -0
- data/lib/hecks.rb +32 -82
- data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +8 -46
- data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +11 -80
- data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +10 -99
- metadata +30 -59
- data/lib/hecks/bench/cli.rb +0 -74
- data/lib/hecks/bench/environment.rb +0 -100
- data/lib/hecks/bench/postgres_probe.rb +0 -41
- data/lib/hecks/bench/report.rb +0 -116
- data/lib/hecks/bench/ruby_runner.rb +0 -151
- data/lib/hecks/bench/run.rb +0 -55
- data/lib/hecks/bench/rust_runner.rb +0 -165
- data/lib/hecks/bench/stats.rb +0 -75
- data/lib/hecks/bench/suite.rb +0 -172
- data/lib/hecks/bench/workload.rb +0 -137
- data/lib/hecks/bench.rb +0 -28
- data/lib/hecks/codemod.rb +0 -443
- data/lib/hecks/corpus.rb +0 -479
- data/lib/hecks/doc/reference.rb +0 -585
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +0 -684
- data/lib/hecks/fuzzing/combination_miner.rb +0 -178
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +0 -469
- data/lib/hecks/fuzzing/coverage_campaign.rb +0 -161
- data/lib/hecks/fuzzing/differential.rb +0 -192
- data/lib/hecks/fuzzing/domain_generator.rb +0 -871
- data/lib/hecks/fuzzing/era_boundary.rb +0 -154
- data/lib/hecks/fuzzing/form_census.rb +0 -285
- data/lib/hecks/fuzzing/generated_domain_check.rb +0 -171
- data/lib/hecks/fuzzing/invalid_value_generator.rb +0 -125
- data/lib/hecks/fuzzing/isolated_boot.rb +0 -658
- data/lib/hecks/fuzzing/nondeterministic.rb +0 -79
- data/lib/hecks/fuzzing/persistence_parity.rb +0 -253
- data/lib/hecks/fuzzing/properties/corrections.rb +0 -125
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +0 -688
- data/lib/hecks/fuzzing/properties/guards.rb +0 -398
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +0 -399
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +0 -137
- data/lib/hecks/fuzzing/properties/outbox.rb +0 -180
- data/lib/hecks/fuzzing/properties/querying.rb +0 -260
- data/lib/hecks/fuzzing/properties.rb +0 -267
- data/lib/hecks/fuzzing/qa_settings.rb +0 -164
- data/lib/hecks/fuzzing/replay.rb +0 -930
- data/lib/hecks/fuzzing/rotation_priority.rb +0 -114
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +0 -139
- data/lib/hecks/fuzzing/self_consistency.rb +0 -825
- data/lib/hecks/fuzzing/sequence_generator/adversary.rb +0 -532
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +0 -171
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +0 -127
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +0 -116
- data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +0 -138
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +0 -344
- data/lib/hecks/fuzzing/sequence_generator.rb +0 -311
- data/lib/hecks/fuzzing/shrinker.rb +0 -309
- data/lib/hecks/fuzzing/structural_skips.rb +0 -53
- data/lib/hecks/fuzzing/sweep_depth.rb +0 -61
- data/lib/hecks/fuzzing/target_capabilities.rb +0 -255
- data/lib/hecks/fuzzing/value_generator.rb +0 -340
- data/lib/hecks/fuzzing.rb +0 -23
- data/lib/hecks/grammar/evolve.rb +0 -524
- data/lib/hecks/query_ir.rb +0 -482
|
@@ -2,14 +2,8 @@ require_relative "word_gate"
|
|
|
2
2
|
module Hecks
|
|
3
3
|
module Bluebook
|
|
4
4
|
module DSL
|
|
5
|
-
# Parses an `entity "Name" do ... end` block
|
|
6
|
-
#
|
|
7
|
-
# an `Entity` — attributes, relationships (`has_many`/`has_one`/
|
|
8
|
-
# `belongs_to`), its own nested commands/queries/lifecycle, and
|
|
9
|
-
# preconditions shared across them. Threads the owning aggregate's
|
|
10
|
-
# value-object and cross-entity `given` pools through unchanged, so a
|
|
11
|
-
# nested piece resolves identity and shared rules against the same
|
|
12
|
-
# aggregate-wide state a top-level piece does.
|
|
5
|
+
# Parses an `entity "Name" do ... end` block into an `Entity` — attributes, relationships,
|
|
6
|
+
# nested commands/queries/lifecycle, and preconditions shared across them (ADR 0026).
|
|
13
7
|
class EntityBuilder
|
|
14
8
|
GRAMMAR_CONTEXT = "Entity".freeze
|
|
15
9
|
|
|
@@ -18,22 +12,8 @@ module Hecks
|
|
|
18
12
|
include RuleReference
|
|
19
13
|
include WordGate
|
|
20
14
|
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
# objects, threaded through unchanged for this piece's `identified_by` to resolve
|
|
24
|
-
# against
|
|
25
|
-
# @param owner_named_givens [Hash{String => Bluebook::Given}] the aggregate-wide,
|
|
26
|
-
# cross-entity given pool, shared and written through by `given_impl`
|
|
27
|
-
# @param identity_name_prefix [String, nil] the prefix a synthesized identity value
|
|
28
|
-
# object's name takes; nil derives it from `name`
|
|
29
|
-
# @param identity_value_object_installer [#call, nil] called with a synthesized value
|
|
30
|
-
# object to install it onto the owning aggregate; nil when there is none
|
|
31
|
-
# @param aggregate_name [String, nil] the root aggregate's name, for chapter-wide given
|
|
32
|
-
# keys; nil derives it from `name`
|
|
33
|
-
# @param chapter_entity_named_givens [Hash{String => Hash{String => Bluebook::Given}}]
|
|
34
|
-
# the chapter-wide, entity-scoped given pool, shared and written through
|
|
35
|
-
# @param chapter_entity_pending_givens [Array<Hash>] unresolved chapter-wide bare given
|
|
36
|
-
# references, appended to when this piece's own reference cannot resolve yet
|
|
15
|
+
# Builds a piece nested under an aggregate (or another piece), threading the owner's
|
|
16
|
+
# value-object and given pools through unchanged so nested pieces share the same state.
|
|
37
17
|
def initialize(name, owner_value_objects: [], owner_named_givens: {},
|
|
38
18
|
identity_name_prefix: nil, identity_value_object_installer: nil,
|
|
39
19
|
aggregate_name: nil, chapter_entity_named_givens: {}, chapter_entity_pending_givens: [])
|
|
@@ -46,85 +26,36 @@ module Hecks
|
|
|
46
26
|
@owner_value_objects = owner_value_objects
|
|
47
27
|
@identity_name_prefix = identity_name_prefix || Naming.demodulise(name)
|
|
48
28
|
@identity_value_object_installer = identity_value_object_installer
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
# under one aggregate however deep (the identical shape
|
|
52
|
-
# `@owner_value_objects` already threads — see this class'
|
|
53
|
-
# own `entity` comment). `given`'s own block form writes
|
|
54
|
-
# through to it; a sibling piece's bare command-level
|
|
55
|
-
# reference reads from it via `CommandBuilder#
|
|
56
|
-
# reference_named_given`.
|
|
29
|
+
# Threaded unchanged through every nested piece so a sibling's bare given
|
|
30
|
+
# reference can read the same aggregate-wide pool `given_impl` writes to.
|
|
57
31
|
@owner_named_givens = owner_named_givens
|
|
58
|
-
#
|
|
59
|
-
#
|
|
60
|
-
# one level down). `@aggregate_name` names this piece's own
|
|
61
|
-
# root, so the write-through below can key itself
|
|
62
|
-
# "AggregateName.EntityName" — the same dotted addressing
|
|
63
|
-
# convention `declared_by:` already uses chapter-wide, one
|
|
64
|
-
# level up. See `#given_impl`'s own comment for what this
|
|
65
|
-
# closes and `docs/implemented/resolution-rules/
|
|
66
|
-
# chapter-entity-given.md` for the full algorithm.
|
|
32
|
+
# One level wider than `@owner_named_givens`: the chapter-wide, entity-scoped
|
|
33
|
+
# pool, keyed "Aggregate.Entity" so `#given_impl` can resolve across aggregates.
|
|
67
34
|
@aggregate_name = aggregate_name || Naming.demodulise(name)
|
|
68
35
|
@chapter_entity_named_givens = chapter_entity_named_givens
|
|
69
36
|
@chapter_entity_pending_givens = chapter_entity_pending_givens
|
|
70
|
-
#
|
|
71
|
-
#
|
|
72
|
-
# nested piece's own commands (Dispatch inside Handler) see
|
|
73
|
-
# every sibling entity/command/query this piece goes on to
|
|
74
|
-
# declare, not just whatever came before it textually.
|
|
37
|
+
# Deferred: built once every sibling in this block has been seen, so a nested
|
|
38
|
+
# command can resolve a sibling entity/command/query declared later in the block.
|
|
75
39
|
@pending_entities = []
|
|
76
40
|
@pending_commands = []
|
|
77
41
|
@pending_queries = []
|
|
78
42
|
end
|
|
79
43
|
|
|
80
44
|
# Sets the human-readable description shown for this entity.
|
|
81
|
-
#
|
|
82
|
-
# @param value [String] the description text
|
|
83
|
-
# @return [String] the description as stored
|
|
84
45
|
def description(value) = @description = value
|
|
85
46
|
|
|
86
|
-
# Declares a reference from this piece to another aggregate's identity
|
|
87
|
-
#
|
|
88
|
-
# The same field AggregateBuilder's own reference_to builds — a
|
|
89
|
-
# piece can hold a reference to another root exactly the way its
|
|
90
|
-
# own head can (Card.assignee_id, a Team's own id), just never
|
|
91
|
-
# to another piece, since there's no cross-piece addressing
|
|
92
|
-
# anywhere in this language to resolve one against.
|
|
93
|
-
#
|
|
94
|
-
# Answers the `reference_to` word through the table's `calls:`
|
|
95
|
-
# column — item #13's full metaprogrammed
|
|
96
|
-
# dispatch (slice 4b). Bootstrap-reachable, in
|
|
97
|
-
# `GenericDispatch::BOOTSTRAP_CALLS_FALLBACK`.
|
|
98
|
-
#
|
|
99
|
-
# @param type [Module, Symbol, String] the referenced aggregate, written as a bare
|
|
100
|
-
# constant
|
|
101
|
-
# @param as [Symbol, nil] the attribute's name; nil derives it from `type`
|
|
102
|
-
# @param optional [Boolean] whether the reference may be absent
|
|
103
|
-
# @return [void]
|
|
104
|
-
# @raise [Bluebook::DSL::Malformed] if `as` (or the derived name) is already declared
|
|
47
|
+
# Declares a reference from this piece to another aggregate's identity — never to
|
|
48
|
+
# another piece, since this language has no cross-piece addressing to resolve one against.
|
|
105
49
|
def reference_to_impl(type, as: nil, optional: false)
|
|
106
50
|
target = Naming.demodulise(type)
|
|
107
51
|
relationship_attribute(target, :reference_to,
|
|
108
52
|
as || default_reference_name(target), optional: optional)
|
|
109
53
|
end
|
|
110
54
|
|
|
111
|
-
# has_many_impl
|
|
112
|
-
#
|
|
113
|
-
# alongside them) — not real predicates, so renaming to many?/one?
|
|
114
|
-
# per Naming/PredicatePrefix would break every bluebook that
|
|
115
|
-
# declares one. New on Entity (Wave 6, identity-and-relationships
|
|
116
|
-
# arc) — pieces never had relationship words before; named
|
|
117
|
-
# `*_impl` to match AggregateBuilder's own siblings, item #13's
|
|
118
|
-
# full metaprogrammed dispatch convention.
|
|
55
|
+
# `has_many_impl`/`has_one_impl` are DSL keywords (`has_many`/`has_one` in a bluebook),
|
|
56
|
+
# not real predicates, so Naming/PredicatePrefix does not apply here.
|
|
119
57
|
# rubocop:disable Naming/PredicatePrefix
|
|
120
58
|
# Declares a list-typed relationship to another entity, referenced by its plural name.
|
|
121
|
-
#
|
|
122
|
-
# @param type [Module, Symbol, String] the related entity's plural name, a bare constant
|
|
123
|
-
# @param as [Symbol, nil] the attribute's name; nil derives it from `type`
|
|
124
|
-
# @param options [Hash] must be empty; kept only to name which unsupported keyword was
|
|
125
|
-
# given in the refusal message
|
|
126
|
-
# @return [void]
|
|
127
|
-
# @raise [Bluebook::DSL::Malformed] if any keyword argument is given
|
|
128
59
|
def has_many_impl(type, as: nil, **options)
|
|
129
60
|
unless options.empty?
|
|
130
61
|
raise Malformed,
|
|
@@ -137,11 +68,6 @@ module Hecks
|
|
|
137
68
|
end
|
|
138
69
|
|
|
139
70
|
# Declares a single-valued relationship to another entity.
|
|
140
|
-
#
|
|
141
|
-
# @param type [Module, Symbol, String] the related entity, a bare constant
|
|
142
|
-
# @param as [Symbol, nil] the attribute's name; nil derives it from `type`
|
|
143
|
-
# @param optional [Boolean] whether the relationship may be absent
|
|
144
|
-
# @return [void]
|
|
145
71
|
def has_one_impl(type, as: nil, optional: false)
|
|
146
72
|
target = Naming.demodulise(type)
|
|
147
73
|
relationship_attribute(target, :has_one, as || Naming.snake(target).to_sym, optional: optional)
|
|
@@ -149,204 +75,59 @@ module Hecks
|
|
|
149
75
|
# rubocop:enable Naming/PredicatePrefix
|
|
150
76
|
|
|
151
77
|
# Declares a single-valued relationship to the entity that owns this one.
|
|
152
|
-
#
|
|
153
|
-
# @param type [Module, Symbol, String] the owning entity, a bare constant
|
|
154
|
-
# @param as [Symbol, nil] the attribute's name; nil derives it from `type`
|
|
155
|
-
# @param optional [Boolean] whether the relationship may be absent
|
|
156
|
-
# @return [void]
|
|
157
78
|
def belongs_to_impl(type, as: nil, optional: false)
|
|
158
79
|
target = Naming.demodulise(type)
|
|
159
80
|
relationship_attribute(target, :belongs_to, as || Naming.snake(target).to_sym, optional: optional)
|
|
160
81
|
end
|
|
161
82
|
|
|
162
|
-
#
|
|
163
|
-
#
|
|
164
|
-
# what an id actually is — a LedgerEntry is entry 3, not entry
|
|
165
|
-
# {"value":3}. `identified_by` itself is AttributeCollector's own
|
|
166
|
-
# shared method (S9) — the two constructs cannot drift apart in
|
|
167
|
-
# how they spell an identity, including composite
|
|
168
|
-
# (`identified_by :branch_code, :box_number`), which a piece may
|
|
169
|
-
# declare for the same reason a head may.
|
|
83
|
+
# `identified_by` (from AttributeCollector) names the scalar field that is this
|
|
84
|
+
# piece's identity, including composite identity, the same as an aggregate's own.
|
|
170
85
|
|
|
171
86
|
# Queues a command declared on this piece, built later once every sibling has been seen.
|
|
172
|
-
#
|
|
173
|
-
# `from:` — see `AggregateBuilder#command`'s own comment; the
|
|
174
|
-
# same guard, checked against this piece's own lifecycle field
|
|
175
|
-
# (S10, ADR 0025 — a piece's own state machine is checkable the
|
|
176
|
-
# same way a head's is).
|
|
177
|
-
#
|
|
178
|
-
# Answers the `command` word through the table's `calls:` column,
|
|
179
|
-
# along with its siblings `query`/`entity`/`lifecycle` below —
|
|
180
|
-
# item #13's full metaprogrammed dispatch (slice 4c), same
|
|
181
|
-
# reasoning as AggregateBuilder's own siblings: bootstrap-
|
|
182
|
-
# reachable, in `GenericDispatch::BOOTSTRAP_CALLS_FALLBACK`.
|
|
183
|
-
#
|
|
184
|
-
# @param name [String] the command's name
|
|
185
|
-
# @param from [String, Symbol, Array<String, Symbol>, nil] the lifecycle state(s) this
|
|
186
|
-
# command guards from; nil admits from any state
|
|
187
|
-
# @yield the command body, evaluated against a `CommandBuilder` once drained
|
|
188
|
-
# @return [Array<Array>] every pending command queued so far, this one last
|
|
189
87
|
def command_impl(name, from: nil, &block)
|
|
190
88
|
@pending_commands << [name, from, block]
|
|
191
89
|
end
|
|
192
90
|
|
|
193
91
|
# Queues a query declared on this piece, built later once every sibling has been seen.
|
|
194
|
-
#
|
|
195
|
-
# @param name [String] the query's name
|
|
196
|
-
# @yield the query body, evaluated against a `QueryBuilder` once drained
|
|
197
|
-
# @return [Array<Array>] every pending query queued so far, this one last
|
|
198
92
|
def query_impl(name, &block)
|
|
199
93
|
@pending_queries << [name, block]
|
|
200
94
|
end
|
|
201
95
|
|
|
202
96
|
# Queues a piece nested inside this one, built later once every sibling has been seen.
|
|
203
|
-
#
|
|
204
|
-
# S17, ADR 0026 — a piece nested inside a piece. "A `Dispatch`
|
|
205
|
-
# [has] no life outside its `Handler`" (the ADR's own words) —
|
|
206
|
-
# the same reason `Member` nests inside `ValueObject`, one level
|
|
207
|
-
# further in. `owner_value_objects` passes straight through
|
|
208
|
-
# unchanged, not re-derived from this entity's own attributes —
|
|
209
|
-
# a piece mints no value objects of its own at any depth, so a
|
|
210
|
-
# nested piece's bare `identified_by :field` still resolves
|
|
211
|
-
# against the same root aggregate's value objects an outer
|
|
212
|
-
# piece's already does (`AggregateBuilder#entity`'s own comment
|
|
213
|
-
# names this pool ; there is exactly one of them, however deep
|
|
214
|
-
# the nesting goes).
|
|
215
|
-
# @param name [String] the nested piece's name
|
|
216
|
-
# @yield the piece body, evaluated against an `EntityBuilder` once drained
|
|
217
|
-
# @return [Array<Array>] every pending piece queued so far, this one last
|
|
97
|
+
# `owner_value_objects` passes through unchanged since a piece mints none of its own.
|
|
218
98
|
def entity_impl(name, &block)
|
|
219
99
|
@pending_entities << [name, block]
|
|
220
100
|
end
|
|
221
101
|
|
|
222
102
|
# Declares this piece's own state machine.
|
|
223
|
-
#
|
|
224
|
-
# @param field [Symbol, String] the attribute the state machine lives on
|
|
225
|
-
# @param default [String, Symbol] the state a new record starts in
|
|
226
|
-
# @yield the lifecycle body of `transition` rows, evaluated against a `LifecycleBuilder`
|
|
227
|
-
# @return [Bluebook::Lifecycle] the built state machine
|
|
228
|
-
# @raise [Bluebook::DSL::Malformed] if two transitions for one command overlap
|
|
229
103
|
def lifecycle_impl(field, default:, &)
|
|
230
104
|
@lifecycle = LifecycleBuilder.build(field, default: default, &)
|
|
231
105
|
end
|
|
232
106
|
|
|
233
|
-
# A precondition shared across this piece's own commands, declared
|
|
234
|
-
# once — the same move `AggregateBuilder#given` already makes,
|
|
235
|
-
# one level down. Real, live redundancy this closes: banking's
|
|
236
|
-
# own `LedgerEntry.Amend`/`LedgerEntry.Reverse` each repeated
|
|
237
|
-
# `given("customer is active") { parent.customer.status ==
|
|
238
|
-
# "active" }` and `given("account is open") { parent.status ==
|
|
239
|
-
# "open" }`, byte for byte, because a piece had no way to declare
|
|
240
|
-
# either once and reference it back — only the aggregate could.
|
|
241
|
-
# Declare before the commands that reference it, the same
|
|
242
|
-
# ordering `AggregateBuilder#given`'s own comment names — though
|
|
243
|
-
# since ADR 0028, `command` only queues a descriptor and actually
|
|
244
|
-
# builds at `#drain_pending!` time, well after this whole block
|
|
245
|
-
# (including every `given` in it) has already run, so textual
|
|
246
|
-
# order within the block no longer actually matters here; named
|
|
247
|
-
# for the reader anyway, since `given`'s own resolution logic
|
|
248
|
-
# (`CommandBuilder#reference_named_given`) still reads whatever
|
|
249
|
-
# `@named_givens` holds at the command's own build time, not by
|
|
250
|
-
# magic.
|
|
251
107
|
# Declares a rule this piece's own commands must satisfy, or references one a sibling
|
|
252
108
|
# piece anywhere in the chapter already declared.
|
|
253
109
|
#
|
|
254
|
-
#
|
|
255
|
-
#
|
|
256
|
-
# (slice 4b), same reasoning as `reference_to_impl` above.
|
|
257
|
-
#
|
|
258
|
-
# Bare — no block — references another piece's own declaration,
|
|
259
|
-
# anywhere in the chapter, not just a sibling under this same
|
|
260
|
-
# aggregate — one level wider than round 4's own cross-entity
|
|
261
|
-
# sharing, mirroring `AggregateBuilder#given_impl`'s own
|
|
262
|
-
# chapter-wide shape exactly one level down. Real, live corpus
|
|
263
|
-
# this closes: `Account::LedgerEntry` and `SafeDepositBox::Visit`
|
|
264
|
-
# — two pieces under two different aggregates — independently
|
|
265
|
-
# typed `given("customer is active") { parent.customer.status ==
|
|
266
|
-
# "active" }` byte for byte; neither the aggregate-level chapter
|
|
267
|
-
# pool (a different canonical — bare `customer.status`, the
|
|
268
|
-
# wrong scope for a piece's own command) nor the existing
|
|
269
|
-
# same-aggregate cross-entity pool (`@owner_named_givens`, scoped
|
|
270
|
-
# to one aggregate's own entity tree) could reach across the
|
|
271
|
-
# aggregate boundary. Resolved against `@chapter_entity_named_
|
|
272
|
-
# givens`, keyed "AggregateName.EntityName" — see
|
|
273
|
-
# `#reference_named_chapter_entity_given`'s own comment for the
|
|
274
|
-
# algorithm and `docs/implemented/resolution-rules/
|
|
275
|
-
# chapter-entity-given.md` for the full write-up.
|
|
276
|
-
#
|
|
277
|
-
# `declared_by:` is a plain string ("Account.LedgerEntry"), not a
|
|
278
|
-
# constant — unlike `AggregateBuilder#given_impl`'s own
|
|
279
|
-
# `declared_by:`, which names a real aggregate constant. A piece
|
|
280
|
-
# has no first-class, independently-addressable reference
|
|
281
|
-
# anywhere in this language (only its owning aggregate does);
|
|
282
|
-
# inventing one to make this one argument spelling symmetrical
|
|
283
|
-
# with the aggregate-level word is a real, separate, unscoped
|
|
284
|
-
# feature this fix does not need — ships textual now, the same
|
|
285
|
-
# way `admits:` shipped textual before its own constant-bridge
|
|
286
|
-
# existed, revisited only if a genuine, separate need for
|
|
287
|
-
# constant-addressed pieces shows up later.
|
|
288
|
-
#
|
|
289
|
-
# @param description [String] the rule's description; also the name a sibling piece
|
|
290
|
-
# references it by when no block is given
|
|
291
|
-
# @param declared_by [String, nil] disambiguates which piece's own rule to reference,
|
|
292
|
-
# as `"Aggregate.Entity"`, when more than one shares `description`; only meaningful
|
|
293
|
-
# with no block
|
|
294
|
-
# @yield the predicate body; evaluated for its extracted source, never called directly
|
|
295
|
-
# @return [void]
|
|
296
|
-
# @raise [Bluebook::DSL::Malformed] if given a block whose source cannot be extracted;
|
|
297
|
-
# given no block, the description is immediately ambiguous between more than one
|
|
298
|
-
# already-loaded piece with no `declared_by` to disambiguate; an unresolved reference
|
|
299
|
-
# defers instead, and may still raise once the whole chapter has loaded, if it then
|
|
300
|
-
# resolves to none or more than one candidate
|
|
110
|
+
# Order doesn't matter: `command` only queues a descriptor here and builds for real at
|
|
111
|
+
# `#drain_pending!` time, after every `given` in this block has already run.
|
|
301
112
|
def given_impl(description, declared_by: nil, &predicate)
|
|
302
113
|
return reference_named_chapter_entity_given(description, declared_by: declared_by) unless predicate
|
|
303
114
|
|
|
304
115
|
named = build_rule(Given, description, predicate, owner_name: @name, word: "given",
|
|
305
116
|
extraction_failure: "its source could not be read, so no other runtime could ever evaluate it")
|
|
306
117
|
@named_givens[description] = named
|
|
307
|
-
#
|
|
308
|
-
#
|
|
309
|
-
# same description stays purely local to itself (no silent
|
|
310
|
-
# overwrite of whatever the first piece already shared;
|
|
311
|
-
# real, live case a fuzzer or a future codemod could easily
|
|
312
|
-
# surface: two pieces phrasing an unrelated rule identically
|
|
313
|
-
# by coincidence, same as an aggregate-level given already
|
|
314
|
-
# tolerates today).
|
|
118
|
+
# First-declared-wins (`||=`): a second piece under the same aggregate declaring
|
|
119
|
+
# the exact same description independently stays local, never silently overwritten.
|
|
315
120
|
@owner_named_givens[description] ||= named
|
|
316
|
-
#
|
|
317
|
-
#
|
|
318
|
-
#
|
|
319
|
-
# identical reasoning `AggregateBuilder#given_impl`'s own
|
|
320
|
-
# chapter write-through gives: two different pieces (anywhere
|
|
321
|
-
# in the chapter) independently declaring the same description
|
|
322
|
-
# are two distinct candidates a later bare reference chooses
|
|
323
|
-
# between (via `declared_by:` once there is more than one),
|
|
324
|
-
# never silently merged into one slot.
|
|
121
|
+
# Chapter-wide analogue of the line above, keyed by "Aggregate.Entity" rather than
|
|
122
|
+
# description alone, so two different pieces sharing a description stay distinct
|
|
123
|
+
# candidates a later bare reference chooses between via `declared_by:`.
|
|
325
124
|
@chapter_entity_named_givens[description] ||= {}
|
|
326
125
|
@chapter_entity_named_givens[description]["#{@aggregate_name}.#{@name}"] ||= named
|
|
327
126
|
end
|
|
328
127
|
|
|
329
|
-
#
|
|
330
|
-
#
|
|
331
|
-
#
|
|
332
|
-
# every instance of this piece the aggregate holds, not once
|
|
333
|
-
# against the aggregate's own flat state
|
|
334
|
-
# (`Admissibility#enforce_invariants`'s own recursive walk).
|
|
335
|
-
# No reference-by-name form (unlike `given`) — no known corpus
|
|
336
|
-
# need for a piece's own invariant to be shared with a sibling
|
|
337
|
-
# piece yet; if that need shows up, it is `given`'s own
|
|
338
|
-
# cross-entity write-through pattern to extend, not a reason to
|
|
339
|
-
# invent a second one here speculatively.
|
|
340
|
-
# Declares a rule every instance of this piece must satisfy.
|
|
341
|
-
#
|
|
342
|
-
# Answers the `invariant` word through the table's `calls:`
|
|
343
|
-
# column — item #13's full metaprogrammed
|
|
344
|
-
# dispatch (slice 4b), same reasoning as `given_impl` above.
|
|
345
|
-
#
|
|
346
|
-
# @param description [String] the rule's description
|
|
347
|
-
# @yield the predicate body; evaluated for its extracted source, never called directly
|
|
348
|
-
# @return [void]
|
|
349
|
-
# @raise [Bluebook::DSL::Malformed] if the block's source could not be extracted
|
|
128
|
+
# Declares a rule every instance of this piece must satisfy — checked per instance,
|
|
129
|
+
# not once against the aggregate's own flat state. No reference-by-name form (unlike
|
|
130
|
+
# `given`); extend that pattern here if cross-piece sharing is ever needed.
|
|
350
131
|
def invariant_impl(description, &predicate)
|
|
351
132
|
@invariants << build_rule(Invariant, description, predicate, owner_name: @name, word: "invariant",
|
|
352
133
|
extraction_failure: "it would be a rule the IR cannot carry")
|
|
@@ -354,11 +135,6 @@ module Hecks
|
|
|
354
135
|
|
|
355
136
|
# Assembles the declared attributes, relationships, nested constructs and rules into an
|
|
356
137
|
# `Entity`.
|
|
357
|
-
#
|
|
358
|
-
# @return [Bluebook::Entity] the built piece
|
|
359
|
-
# @raise [Bluebook::DSL::Malformed] if identity resolution, a lifecycle guard on a
|
|
360
|
-
# command with no lifecycle, a lifecycle-field mutation outside a transition, or a
|
|
361
|
-
# synthesized closed set colliding with one the aggregate already holds fails
|
|
362
138
|
def build
|
|
363
139
|
drain_pending!
|
|
364
140
|
resolve_pending_identity!
|
|
@@ -379,25 +155,6 @@ module Hecks
|
|
|
379
155
|
end
|
|
380
156
|
|
|
381
157
|
# Evaluates an `entity` block against a fresh builder and returns what it built.
|
|
382
|
-
#
|
|
383
|
-
# @param name [String] the entity's name
|
|
384
|
-
# @param owner_value_objects [Array<Bluebook::ValueObject>] the owning aggregate's value
|
|
385
|
-
# objects, for `identified_by` to resolve against
|
|
386
|
-
# @param owner_named_givens [Hash{String => Bluebook::Given}] the aggregate-wide,
|
|
387
|
-
# cross-entity given pool
|
|
388
|
-
# @param identity_name_prefix [String, nil] the prefix a synthesized identity value
|
|
389
|
-
# object's name takes
|
|
390
|
-
# @param identity_value_object_installer [#call, nil] called to install a synthesized
|
|
391
|
-
# value object onto the owning aggregate
|
|
392
|
-
# @param aggregate_name [String, nil] the root aggregate's name, for chapter-wide given
|
|
393
|
-
# keys
|
|
394
|
-
# @param chapter_entity_named_givens [Hash{String => Hash{String => Bluebook::Given}}]
|
|
395
|
-
# the chapter-wide, entity-scoped given pool
|
|
396
|
-
# @param chapter_entity_pending_givens [Array<Hash>] unresolved chapter-wide bare given
|
|
397
|
-
# references
|
|
398
|
-
# @yield the entity body, evaluated with the builder as `self`; may be omitted
|
|
399
|
-
# @return [Bluebook::Entity] the built piece
|
|
400
|
-
# @raise [Bluebook::DSL::Malformed] if the body fails any check `#build` raises
|
|
401
158
|
def self.build(name, owner_value_objects: [], owner_named_givens: {},
|
|
402
159
|
identity_name_prefix: nil, identity_value_object_installer: nil,
|
|
403
160
|
aggregate_name: nil, chapter_entity_named_givens: {}, chapter_entity_pending_givens: [], &block)
|
|
@@ -413,28 +170,9 @@ module Hecks
|
|
|
413
170
|
|
|
414
171
|
private
|
|
415
172
|
|
|
416
|
-
#
|
|
417
|
-
#
|
|
418
|
-
#
|
|
419
|
-
# this construct's own refusal wording, not shared, matching that
|
|
420
|
-
# method's own precedent (`declared_by:` only exists on `given`
|
|
421
|
-
# so far, at either scope). Unresolved is deferred, not raised
|
|
422
|
-
# here — see `#pending_chapter_entity_given`, below.
|
|
423
|
-
#
|
|
424
|
-
# **Writes through to `@owner_named_givens` too** — not just
|
|
425
|
-
# `@named_givens` — or this piece resolving a description via the
|
|
426
|
-
# wider, chapter pool would leave the narrower, same-aggregate
|
|
427
|
-
# pool (`EntityBuilder#given_impl`'s own block-form write-through)
|
|
428
|
-
# never populated for this description, breaking any sibling
|
|
429
|
-
# piece's existing command-level bare reference
|
|
430
|
-
# (`CommandBuilder#reference_named_given`) that depends on it —
|
|
431
|
-
# real, live corpus: `SafeDepositBox::KeyIssuance.Return`'s own
|
|
432
|
-
# bare `given("customer is active")` resolves through
|
|
433
|
-
# `@owner_named_givens`, populated by `Visit`'s declaration
|
|
434
|
-
# whether `Visit` types the predicate itself or (now) references
|
|
435
|
-
# `Account::LedgerEntry`'s instead — this write keeps that
|
|
436
|
-
# working unchanged either way, `||=` so nothing here overrides
|
|
437
|
-
# an actual local declaration if one is ever added later.
|
|
173
|
+
# Resolves a bare `given` reference against the chapter-wide, entity-scoped pool.
|
|
174
|
+
# Also writes through to `@owner_named_givens`, not just `@named_givens` — otherwise a
|
|
175
|
+
# sibling piece's own same-aggregate bare reference would never see this resolution.
|
|
438
176
|
def reference_named_chapter_entity_given(description, declared_by:)
|
|
439
177
|
verify_resolves_via!("given", "Entity", "owner_keyed")
|
|
440
178
|
candidates = resolve_owner_keyed(@chapter_entity_named_givens, description)
|
|
@@ -459,14 +197,9 @@ module Hecks
|
|
|
459
197
|
@owner_named_givens[description] ||= named
|
|
460
198
|
end
|
|
461
199
|
|
|
462
|
-
# A chapter may be split across files
|
|
463
|
-
#
|
|
464
|
-
#
|
|
465
|
-
# far. Hands back a placeholder `Given`, embedded by Ruby object
|
|
466
|
-
# reference in this piece's own `preconditions`, and queues the
|
|
467
|
-
# request in `@chapter_entity_pending_givens` —
|
|
468
|
-
# `BluebookBuilder#resolve_pending_chapter_entity_givens!`
|
|
469
|
-
# mutates it in place once every file in the chapter has loaded.
|
|
200
|
+
# A chapter may be split across files, so an unresolved bare reference defers rather
|
|
201
|
+
# than raising immediately; `BluebookBuilder#resolve_pending_chapter_entity_givens!`
|
|
202
|
+
# fills in the placeholder once every file in the chapter has loaded.
|
|
470
203
|
def pending_chapter_entity_given(description, declared_by:)
|
|
471
204
|
placeholder = Given.new(description: description, canonical: nil, predicate: nil)
|
|
472
205
|
@chapter_entity_pending_givens << { entity: "#{@aggregate_name}.#{@name}", description: description,
|
|
@@ -474,23 +207,10 @@ module Hecks
|
|
|
474
207
|
placeholder
|
|
475
208
|
end
|
|
476
209
|
|
|
477
|
-
# A piece's own `one_of`
|
|
478
|
-
#
|
|
479
|
-
#
|
|
480
|
-
#
|
|
481
|
-
# value objects, so the synthesized set existed nowhere in the
|
|
482
|
-
# finished graph. The attribute stayed typed "Moved" with nothing
|
|
483
|
-
# to resolve it: runtime admission had no closed set to enforce
|
|
484
|
-
# (the one_of was decorative), and the fuzzer's ValueGenerator
|
|
485
|
-
# crashed every run on the first domain to declare one — a chess
|
|
486
|
-
# King/Rook's own castling flag — with `does not know primitive
|
|
487
|
-
# type "Moved"`. Installed through the same hook an entity's own
|
|
488
|
-
# identity value object already rides to the aggregate
|
|
489
|
-
# (`identity_value_object_installer`, threaded unchanged through
|
|
490
|
-
# nested pieces). Two sibling pieces synthesizing the same set
|
|
491
|
-
# (King's and Rook's own `moved`) install it once; the same name
|
|
492
|
-
# with a different member list is refused as the collision it is,
|
|
493
|
-
# never first-wins silently.
|
|
210
|
+
# A piece's own `one_of` synthesizes a closed-set value object, installed onto the
|
|
211
|
+
# owning aggregate so the runtime has it to admit against — not just on the attribute.
|
|
212
|
+
# Two sibling pieces synthesizing the same name install it once; a name collision with
|
|
213
|
+
# a different member list is refused rather than silently kept.
|
|
494
214
|
def install_closed_sets!
|
|
495
215
|
return unless @identity_value_object_installer
|
|
496
216
|
|
|
@@ -508,10 +228,8 @@ module Hecks
|
|
|
508
228
|
end
|
|
509
229
|
end
|
|
510
230
|
|
|
511
|
-
#
|
|
512
|
-
#
|
|
513
|
-
# built (so a nested command's own `append:` resolution can read
|
|
514
|
-
# a sibling piece's `.attributes`), then commands, then queries.
|
|
231
|
+
# Entities are built first, fully, so a nested command's own `append:` can read a
|
|
232
|
+
# sibling piece's `.attributes`; then commands, then queries.
|
|
515
233
|
def drain_pending!
|
|
516
234
|
@entities = @pending_entities.map do |name, block|
|
|
517
235
|
EntityBuilder.build(name, owner_value_objects: @owner_value_objects,
|
|
@@ -536,14 +254,12 @@ module Hecks
|
|
|
536
254
|
end
|
|
537
255
|
end
|
|
538
256
|
|
|
539
|
-
#
|
|
540
|
-
#
|
|
257
|
+
# Refuses a command that sets the lifecycle field directly, or guards `from:` with no
|
|
258
|
+
# lifecycle declared — a lifecycle field only moves by transition.
|
|
541
259
|
def seal_lifecycle_guards
|
|
542
260
|
@commands.each do |command|
|
|
543
261
|
if @lifecycle && !MetaValidator.shadow_parsing?
|
|
544
|
-
#
|
|
545
|
-
# an aggregate: a `sets` on the lifecycle field (frozen era
|
|
546
|
-
# text excepted, as there).
|
|
262
|
+
# `delegate`/`corrects` are exempt — the frozen-era-text case, not a live mutation.
|
|
547
263
|
command.mutations.each do |mutation|
|
|
548
264
|
next if [:delegate, :corrects].include?(mutation.op)
|
|
549
265
|
next unless mutation.target.to_sym == @lifecycle.field.to_sym
|
|
@@ -563,10 +279,8 @@ module Hecks
|
|
|
563
279
|
end
|
|
564
280
|
end
|
|
565
281
|
|
|
566
|
-
# `identified_by`
|
|
567
|
-
#
|
|
568
|
-
# its own, so a bare field's own type resolves against its owner
|
|
569
|
-
# aggregate's, passed in at declaration (`AggregateBuilder#entity`).
|
|
282
|
+
# A piece mints no value objects of its own, so `identified_by` resolves a bare field's
|
|
283
|
+
# type against the owner aggregate's pool, passed in at declaration.
|
|
570
284
|
def identity_pool = @owner_value_objects
|
|
571
285
|
|
|
572
286
|
def identity_value_object_name = "#{@identity_name_prefix}Identity"
|