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
|
@@ -3,23 +3,11 @@ require_relative "../../bluebook/hexagon"
|
|
|
3
3
|
module Hecks
|
|
4
4
|
module Runtime
|
|
5
5
|
class Registry
|
|
6
|
-
# The wiring gate: every bind names a declared aggregate, every
|
|
7
|
-
#
|
|
8
|
-
# a field the adapter admits, and the default adapter is usable at
|
|
9
|
-
# all. Included into Registry — `verify!` is what a boot calls after
|
|
10
|
-
# loading, and the smaller checks are also called piecemeal by the
|
|
11
|
-
# repository factory.
|
|
6
|
+
# The wiring gate: every bind names a declared aggregate, every adapter satisfies its
|
|
7
|
+
# port's verb, and every world default is usable. `verify!` runs it all at boot.
|
|
12
8
|
module Verification
|
|
13
|
-
# Runs
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
# @return [Runtime::Registry] self
|
|
17
|
-
# @raise [Runtime::WiringError] if a bind names an undeclared aggregate, an
|
|
18
|
-
# adapter cannot satisfy its port's verb or declared `answers`, a world
|
|
19
|
-
# setting names a field its adapter does not declare, the default adapter
|
|
20
|
-
# is unusable, a world's `default_adapter` is not a persistence adapter, a
|
|
21
|
-
# command declares a role with no authorization provider attached, or a
|
|
22
|
-
# membership chapter is loaded with no identity chapter
|
|
9
|
+
# Runs every wiring check against this registry's loaded bluebooks, hexagons, ports
|
|
10
|
+
# and adapters.
|
|
23
11
|
def verify!
|
|
24
12
|
verify_default_adapter!
|
|
25
13
|
verify_world_defaults!
|
|
@@ -35,19 +23,9 @@ module Hecks
|
|
|
35
23
|
refuse_bounded_without_acl!(hexagon)
|
|
36
24
|
|
|
37
25
|
hexagon.binds.each do |bind|
|
|
38
|
-
# A domain-level default (§0)
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
# the bluebook for this row specifically. Still validate its
|
|
42
|
-
# own adapter/verb shape (the same reason
|
|
43
|
-
# `verify_default_adapter!` checks the framework-wide
|
|
44
|
-
# default the same way, aggregate-less). Coverage of real
|
|
45
|
-
# aggregates that only resolve through this default comes
|
|
46
|
-
# from their own dispatch-time `BindingPolicy.resolve` —
|
|
47
|
-
# deliberately not required to be exhaustive here, the same
|
|
48
|
-
# leniency this method already extended to any aggregate
|
|
49
|
-
# left out of an explicit bind list entirely (real test
|
|
50
|
-
# fixtures bind only the aggregates they exercise).
|
|
26
|
+
# A domain-level default (§0) names no aggregate of its own; still validate its
|
|
27
|
+
# adapter/verb shape. Real aggregates resolving through it are covered by their
|
|
28
|
+
# own dispatch-time `BindingPolicy.resolve`, not required to be exhaustive here.
|
|
51
29
|
if bind.aggregate.nil?
|
|
52
30
|
check_verb(bind)
|
|
53
31
|
next
|
|
@@ -67,13 +45,7 @@ module Hecks
|
|
|
67
45
|
self
|
|
68
46
|
end
|
|
69
47
|
|
|
70
|
-
# Checks that the framework-wide default persistence adapter
|
|
71
|
-
# aggregate left out of an explicit bind list) is itself wired correctly.
|
|
72
|
-
#
|
|
73
|
-
# @return [Runtime::Registry] self
|
|
74
|
-
# @raise [Runtime::WiringError] if the default adapter cannot satisfy the
|
|
75
|
-
# persistence port's verb, is missing a declared `answers` method, or has
|
|
76
|
-
# no Ruby implementation
|
|
48
|
+
# Checks that the framework-wide default persistence adapter is itself wired correctly.
|
|
77
49
|
def verify_default_adapter!
|
|
78
50
|
name = Ports::Persistence::DEFAULT_ADAPTER
|
|
79
51
|
|
|
@@ -92,14 +64,7 @@ module Hecks
|
|
|
92
64
|
"aggregate with no bind could not be given one: #{e.message}"
|
|
93
65
|
end
|
|
94
66
|
|
|
95
|
-
# Checks that `bind`'s adapter implements the port it names and satisfies
|
|
96
|
-
# the verb the bind declares.
|
|
97
|
-
#
|
|
98
|
-
# @param bind [Bluebook::Bind] the bind to check
|
|
99
|
-
# @return [void]
|
|
100
|
-
# @raise [Runtime::WiringError] if `bind`'s adapter is unknown, declares an
|
|
101
|
-
# unknown port, is missing a declared `answers` method, or cannot satisfy
|
|
102
|
-
# `bind`'s own verb
|
|
67
|
+
# Checks that `bind`'s adapter implements the port it names and satisfies its verb.
|
|
103
68
|
def check_verb(bind)
|
|
104
69
|
port = port_for(bind)
|
|
105
70
|
check_answers(port, bind.adapter)
|
|
@@ -110,20 +75,8 @@ module Hecks
|
|
|
110
75
|
"and cannot satisfy #{bind.verb}"
|
|
111
76
|
end
|
|
112
77
|
|
|
113
|
-
#
|
|
114
|
-
#
|
|
115
|
-
# verb, and admit every `.world` setting `check_settings` checks,
|
|
116
|
-
# and still be missing the one method a live dispatch will
|
|
117
|
-
# actually call. `answers` is optional per port (an empty list is
|
|
118
|
-
# today's pre-existing behavior, unchecked), so this only ever
|
|
119
|
-
# tightens a port that opted in.
|
|
120
|
-
#
|
|
121
|
-
# @param port [Bluebook::Port] the port whose declared `answers` methods
|
|
122
|
-
# `adapter_name` must respond to
|
|
123
|
-
# @param adapter_name [String] the adapter's declared name to check
|
|
124
|
-
# @return [void]
|
|
125
|
-
# @raise [Runtime::WiringError] if `adapter_name` has no Ruby implementation,
|
|
126
|
-
# or its implementation does not respond to one of `port.answers`
|
|
78
|
+
# `answers` is optional per port, so an adapter can satisfy a port's verb and still
|
|
79
|
+
# miss a method live dispatch will call; this only tightens ports that opt in.
|
|
127
80
|
def check_answers(port, adapter_name)
|
|
128
81
|
answers = Array(port.answers)
|
|
129
82
|
return if answers.empty?
|
|
@@ -138,27 +91,12 @@ module Hecks
|
|
|
138
91
|
"#{answers.map(&:inspect).join(', ')}"
|
|
139
92
|
end
|
|
140
93
|
|
|
141
|
-
#
|
|
142
|
-
#
|
|
143
|
-
# every real `bind` a hexagon declares; a singleton port
|
|
144
|
-
# (`clock`, `authorization`, …) is never bound to an aggregate at
|
|
145
|
-
# all, so nothing above ever resolves one and nothing above ever
|
|
146
|
-
# ran `check_answers` against it. Each one's own `Ports::*.adapter`
|
|
147
|
-
# already refuses zero or multiple implementations, live, at
|
|
148
|
-
# first dispatch — that stays exactly as-is here (0 or 2+ is
|
|
149
|
-
# ambiguity, not a method-contract question, and asserting every
|
|
150
|
-
# declared port must have exactly one adapter would wrongly
|
|
151
|
-
# refuse a boot that simply never wires a port it doesn't use).
|
|
152
|
-
# This only ever tightens the one case those checks don't cover:
|
|
153
|
-
# exactly one adapter, wired, missing a method `answers` names.
|
|
94
|
+
# persistence/projection/loading are per-aggregate bound and already checked via
|
|
95
|
+
# each bind above; a singleton port is never bound to an aggregate at all.
|
|
154
96
|
PER_AGGREGATE_PORTS = %w[persistence projection loading].freeze
|
|
155
97
|
|
|
156
|
-
# Checks every singleton port
|
|
157
|
-
#
|
|
158
|
-
#
|
|
159
|
-
# @return [Runtime::Registry] self
|
|
160
|
-
# @raise [Runtime::WiringError] if a singleton port's one wired adapter is
|
|
161
|
-
# missing one of its declared `answers` methods
|
|
98
|
+
# Checks every singleton port with exactly one wired adapter against its own
|
|
99
|
+
# declared `answers` methods.
|
|
162
100
|
def verify_singleton_port_answers!
|
|
163
101
|
@ports.each_value do |port|
|
|
164
102
|
next if PER_AGGREGATE_PORTS.include?(port.name)
|
|
@@ -172,16 +110,8 @@ module Hecks
|
|
|
172
110
|
self
|
|
173
111
|
end
|
|
174
112
|
|
|
175
|
-
# Checks that every setting `settings` declares (besides `:adapter`) is a
|
|
176
|
-
#
|
|
177
|
-
#
|
|
178
|
-
# @param bind [Bluebook::Bind] the bind naming the adapter to check against;
|
|
179
|
-
# a no-op if its adapter is unknown
|
|
180
|
-
# @param settings [Hash{Symbol => Object}] the world's declared settings for
|
|
181
|
-
# this bind
|
|
182
|
-
# @return [void]
|
|
183
|
-
# @raise [Runtime::WiringError] if `settings` declares a field `bind`'s
|
|
184
|
-
# adapter does not declare
|
|
113
|
+
# Checks that every setting `settings` declares (besides `:adapter`) is a field
|
|
114
|
+
# `bind`'s adapter actually admits.
|
|
185
115
|
def check_settings(bind, settings)
|
|
186
116
|
adapter = @adapters[bind.adapter]
|
|
187
117
|
return unless adapter
|
|
@@ -196,12 +126,6 @@ module Hecks
|
|
|
196
126
|
"Add the field to the adapter, or remove it from the world."
|
|
197
127
|
end
|
|
198
128
|
|
|
199
|
-
# Finds the port `bind`'s adapter declares.
|
|
200
|
-
#
|
|
201
|
-
# @param bind [Bluebook::Bind] the bind naming the adapter to look up
|
|
202
|
-
# @return [Bluebook::Port] the port `bind`'s adapter declares
|
|
203
|
-
# @raise [Runtime::WiringError] if `bind` names an unknown adapter, or one
|
|
204
|
-
# declaring an unknown port
|
|
205
129
|
def port_for(bind)
|
|
206
130
|
adapter = @adapters[bind.adapter]
|
|
207
131
|
raise WiringError, "unknown adapter #{bind.adapter.inspect}" unless adapter
|
|
@@ -210,12 +134,6 @@ module Hecks
|
|
|
210
134
|
raise(WiringError, "adapter #{bind.adapter} declares unknown port #{adapter.port.inspect}")
|
|
211
135
|
end
|
|
212
136
|
|
|
213
|
-
# Finds the Ruby module implementing the adapter declared `name`.
|
|
214
|
-
#
|
|
215
|
-
# @param name [String] the adapter's declared name, such as `"PostgresEra"`
|
|
216
|
-
# @return [Module] the adapter module or class under `Hecks::Adapters`
|
|
217
|
-
# @raise [Runtime::WiringError] if no Ruby implementation named `name` exists
|
|
218
|
-
# under `Hecks::Adapters`
|
|
219
137
|
def adapter_class(name)
|
|
220
138
|
Adapters.const_get(name)
|
|
221
139
|
rescue NameError
|
|
@@ -225,33 +143,10 @@ module Hecks
|
|
|
225
143
|
|
|
226
144
|
private
|
|
227
145
|
|
|
228
|
-
#
|
|
229
|
-
#
|
|
230
|
-
#
|
|
231
|
-
#
|
|
232
|
-
# access control by exact string equality ... Governance ...
|
|
233
|
-
# connected to none of it"). Checked here, at `verify!` — recovered
|
|
234
|
-
# and moved, not new: running this per-block, at hecksagon
|
|
235
|
-
# build time (Bluebook::DSL::HecksagonBuilder#build), breaks
|
|
236
|
-
# the moment a domain is split across multiple hecksagon
|
|
237
|
-
# blocks (base + an `environments/<name>.hecksagon` overlay,
|
|
238
|
-
# Runtime::Loader.boot's `environment:` — see its own comment for
|
|
239
|
-
# the recovery provenance): every block but the one declaring
|
|
240
|
-
# `uses_framework "Governance"` would be refused there, even
|
|
241
|
-
# though `Registry#add_hecksagon` merges every block for a domain
|
|
242
|
-
# into one Hecksagon before anything ever dispatches against it.
|
|
243
|
-
# Checking the merged result once, here, after every file for
|
|
244
|
-
# this domain has loaded, is both more permissive (no need to
|
|
245
|
-
# repeat `uses_framework` in every file) and strictly more
|
|
246
|
-
# correct (a check against an incomplete, not-yet-merged
|
|
247
|
-
# hecksagon can never see the real final shape).
|
|
248
|
-
#
|
|
249
|
-
# A provider is recognised by its declaration, not its name —
|
|
250
|
-
# `authorization_provider_for` answers for the domain's own
|
|
251
|
-
# chapter too, so Governance (which declares `provides
|
|
252
|
-
# "authorization"`) passes here because of what it declares, and
|
|
253
|
-
# the same rule `CommandRules::Authorization#governance_attached?`
|
|
254
|
-
# applies at dispatch time.
|
|
146
|
+
# Checked once against the merged hecksagon so a domain split across multiple
|
|
147
|
+
# hecksagon files sees every uses_framework declaration first. A role is real
|
|
148
|
+
# access control only once an authorization provider exists to check it against
|
|
149
|
+
# (ADR 0025); a provider is recognized by declaring authorization, not by name.
|
|
255
150
|
def refuse_ungoverned_roles!(hexagon)
|
|
256
151
|
return if authorization_provider_for(hexagon.domain)
|
|
257
152
|
|
|
@@ -268,15 +163,9 @@ module Hecks
|
|
|
268
163
|
"without that it is silent decoration, the exact defect this refusal exists to catch"
|
|
269
164
|
end
|
|
270
165
|
|
|
271
|
-
#
|
|
272
|
-
#
|
|
273
|
-
#
|
|
274
|
-
# anti-corruption layer (`translates` field mapping) live on a named
|
|
275
|
-
# sibling hecksagon the consumer must declare. Without that hexagon
|
|
276
|
-
# the package has no wiring of its own, and cross-context field
|
|
277
|
-
# mapping has nowhere to be written. Breaking in 2.0: attaching a
|
|
278
|
-
# vendored chapter without `Hecks.hecksagon "PackageName"` refuses
|
|
279
|
-
# at boot rather than silently sharing the consumer's hexagon.
|
|
166
|
+
# `uses_embryonaut_bluebook` only loads a package's `.bluebook` files; persistence,
|
|
167
|
+
# Governance and the `translates` ACL live on a sibling hecksagon the consumer must
|
|
168
|
+
# declare, or cross-context field mapping has nowhere to be written.
|
|
280
169
|
def refuse_unwired_vendored_bluebooks!(hexagon)
|
|
281
170
|
Array(hexagon.vendored_bluebooks).each do |package|
|
|
282
171
|
chapter_name = Naming.pascal(package)
|
|
@@ -291,10 +180,8 @@ module Hecks
|
|
|
291
180
|
end
|
|
292
181
|
end
|
|
293
182
|
|
|
294
|
-
#
|
|
295
|
-
#
|
|
296
|
-
# is its ACL. Governance/Identity/Privacy already follow this in
|
|
297
|
-
# every real consumer; boot now refuses a silent miss.
|
|
183
|
+
# `uses_framework` loads a bounded context; the consumer must declare the sibling
|
|
184
|
+
# hecksagon that is its ACL (Governance/Identity/Privacy already do).
|
|
298
185
|
def refuse_unwired_framework_members!(hexagon)
|
|
299
186
|
Array(hexagon.framework_members).each do |member|
|
|
300
187
|
next if hecksagon(member)
|
|
@@ -308,19 +195,12 @@ module Hecks
|
|
|
308
195
|
end
|
|
309
196
|
end
|
|
310
197
|
|
|
311
|
-
# An explicit `bounded` mark on a consumer chapter always needs an
|
|
312
|
-
#
|
|
313
|
-
#
|
|
314
|
-
#
|
|
315
|
-
#
|
|
316
|
-
#
|
|
317
|
-
# rust/host Google sign-in reads `ir.json`'s `membership` and
|
|
318
|
-
# `identity` keys (Exporter.membership / Exporter.identity) —
|
|
319
|
-
# never a deploy-time env var. Membership without Identity is
|
|
320
|
-
# the exact gap that produced a live `google_unlinked` after a
|
|
321
|
-
# successful Google handshake: provision cannot Register/Link.
|
|
322
|
-
# Refuse at Ruby boot (and project_rust, which exports the same
|
|
323
|
-
# pair) so a missing sibling cannot ship.
|
|
198
|
+
# An explicit `bounded` mark on a consumer chapter always needs an ACL. `uses_framework`
|
|
199
|
+
# / `uses_embryonaut_bluebook` mark the attached chapter bounded and require the sibling
|
|
200
|
+
# hecksagon above; they don't require a `translates` on it unless the consumer also
|
|
201
|
+
# wrote `bounded`.
|
|
202
|
+
# rust/host Google sign-in reads ir.json's membership/identity keys, never a deploy-time
|
|
203
|
+
# env var; Membership without Identity means provision cannot Register/Link an identity.
|
|
324
204
|
def refuse_membership_without_identity!
|
|
325
205
|
return unless @bluebooks.values.any? { |chapter| chapter.provides?(Bluebook::Capabilities::MEMBERSHIP) }
|
|
326
206
|
return if @bluebooks.values.any? { |chapter| chapter.provides?(Bluebook::Capabilities::IDENTITY) }
|
|
@@ -333,11 +213,8 @@ module Hecks
|
|
|
333
213
|
"identity verbs are exported onto ir.json, not guessed at deploy."
|
|
334
214
|
end
|
|
335
215
|
|
|
336
|
-
# A
|
|
337
|
-
#
|
|
338
|
-
# attaches after the chapter is built, so this is the first point the
|
|
339
|
-
# operation can be checked. Without it, a host reading the declared
|
|
340
|
-
# verb would dispatch to an operation nothing declares.
|
|
216
|
+
# A hecksagon attaches after its chapter builds, so this is the first point a
|
|
217
|
+
# declared `:port_operation` capability can be checked against it.
|
|
341
218
|
def refuse_unresolved_port_operations!
|
|
342
219
|
@bluebooks.each_value do |chapter|
|
|
343
220
|
chapter.provides.each do |row|
|
|
@@ -352,12 +229,6 @@ module Hecks
|
|
|
352
229
|
end
|
|
353
230
|
end
|
|
354
231
|
|
|
355
|
-
# Says whether a chapter declares the port operation an
|
|
356
|
-
# `"Aggregate.Port.Operation"` verb names.
|
|
357
|
-
#
|
|
358
|
-
# @param chapter [Bluebook::Chapter] the chapter whose aggregates' ports are searched
|
|
359
|
-
# @param verb [String] the verb, spelled `"Aggregate.Port.Operation"`
|
|
360
|
-
# @return [Boolean] whether that aggregate has that port with that operation
|
|
361
232
|
def port_operation_declared?(chapter, verb)
|
|
362
233
|
aggregate_name, port_name, operation_name = verb.split(".", 3)
|
|
363
234
|
ports = chapter.aggregate(aggregate_name)&.ports || []
|
|
@@ -377,8 +248,8 @@ module Hecks
|
|
|
377
248
|
"with: { ... } end` (any field) or drop `bounded`."
|
|
378
249
|
end
|
|
379
250
|
|
|
380
|
-
#
|
|
381
|
-
#
|
|
251
|
+
# Derived from whichever framework members actually declare `provides
|
|
252
|
+
# "authorization"` — never a hardcoded name.
|
|
382
253
|
def authorization_attachment_hint
|
|
383
254
|
providers = Framework.providers_of(Bluebook::Capabilities::AUTHORIZATION)
|
|
384
255
|
return "attaches a chapter that provides \"authorization\" (no framework member declares one)" if providers.empty?
|
|
@@ -386,30 +257,17 @@ module Hecks
|
|
|
386
257
|
providers.map { |name| "uses_framework #{name.inspect}" }.join(" or ")
|
|
387
258
|
end
|
|
388
259
|
|
|
389
|
-
# Every command this domain declares, an aggregate's own and every
|
|
390
|
-
#
|
|
391
|
-
# itself needs at dispatch time, just walked ahead of time here.
|
|
260
|
+
# Every command this domain declares, an aggregate's own and every entity nested
|
|
261
|
+
# inside one — the same reach dispatch-time role checking needs.
|
|
392
262
|
def commands_in(bluebook_ir)
|
|
393
263
|
bluebook_ir.aggregates.flat_map { |aggregate| aggregate.commands + aggregate.entities.flat_map(&:commands) }
|
|
394
264
|
end
|
|
395
265
|
|
|
396
|
-
# Two
|
|
397
|
-
#
|
|
398
|
-
#
|
|
399
|
-
#
|
|
400
|
-
#
|
|
401
|
-
# accumulation (several files declaring the same chapter name on
|
|
402
|
-
# purpose — `lib/hecks/language/bluebook/*.bluebook` all open
|
|
403
|
-
# `Hecks.bluebook "Bluebook"`) is never touched here — that merge
|
|
404
|
-
# stays unconditional, checked only after every file has loaded,
|
|
405
|
-
# the same "check the merged final result once" timing
|
|
406
|
-
# `refuse_ungoverned_roles!` already uses and for the same reason
|
|
407
|
-
# (a check against an incomplete load can never see the real
|
|
408
|
-
# shape). What distinguishes intentional accumulation from
|
|
409
|
-
# coincidence is package root, not file identity: files a real
|
|
410
|
-
# gemspec or a `vendor/` boundary already treats as one unit are
|
|
411
|
-
# expected to share a name; files from two different roots never
|
|
412
|
-
# legitimately do.
|
|
266
|
+
# Two packages can share a chapter name by coincidence (found live: a stale
|
|
267
|
+
# vendor/hecksagain fork of Governance/Identity/Deploy, still on 4 apps' load
|
|
268
|
+
# paths). Intentional accumulation (several files declaring the same chapter on
|
|
269
|
+
# purpose) is distinguished by package root, not file identity, and is left
|
|
270
|
+
# untouched here — checked once, after every file has loaded.
|
|
413
271
|
def refuse_cross_package_bluebook_merge!
|
|
414
272
|
@bluebook_sources.each do |name, paths|
|
|
415
273
|
roots = paths.map { |path| package_root_for(path) }.uniq
|
|
@@ -424,15 +282,9 @@ module Hecks
|
|
|
424
282
|
end
|
|
425
283
|
end
|
|
426
284
|
|
|
427
|
-
# The nearest boundary a path
|
|
428
|
-
#
|
|
429
|
-
#
|
|
430
|
-
# root regardless of what gemspec might sit above it: vendored
|
|
431
|
-
# code should never be considered "the same package" as whatever
|
|
432
|
-
# it's vendored into, even when nothing else marks the boundary.
|
|
433
|
-
# Neither found, the path's own directory is the root — two
|
|
434
|
-
# files with no closer marker only "belong together" if they are
|
|
435
|
-
# literally the same file.
|
|
285
|
+
# The nearest boundary a path belongs to: a real gemspec, or a bare `vendor/`
|
|
286
|
+
# component (vendored code is never "the same package" as what vendors it).
|
|
287
|
+
# Falls back to the path's own directory when neither is found.
|
|
436
288
|
def package_root_for(path)
|
|
437
289
|
return path.to_s if path.nil?
|
|
438
290
|
|
|
@@ -448,37 +300,10 @@ module Hecks
|
|
|
448
300
|
end
|
|
449
301
|
end
|
|
450
302
|
|
|
451
|
-
# A domain
|
|
452
|
-
# `
|
|
453
|
-
#
|
|
454
|
-
#
|
|
455
|
-
# see `SagaPersistence#resolve_saga_persistence`) gets sagas that
|
|
456
|
-
# advance correctly in-process and vanish on restart: no
|
|
457
|
-
# checkpoint written, nothing for `rehydrate_sagas!` to find, no
|
|
458
|
-
# compensation ever replayed. That is silent right up until the
|
|
459
|
-
# process actually dies mid-saga — the same "consistency/
|
|
460
|
-
# freshness defect applied to access control, failing open" ADR
|
|
461
|
-
# 0025 named for an unchecked `role`, here applied to saga
|
|
462
|
-
# durability instead.
|
|
463
|
-
#
|
|
464
|
-
# A warning, not a refusal — unlike `refuse_ungoverned_roles!`,
|
|
465
|
-
# running sagas on a store with no `save_saga` is legitimate on
|
|
466
|
-
# purpose in a fast in-memory test/dev boot (this project's own
|
|
467
|
-
# `saga_durability_spec.rb` boots a process manager on `Memory`
|
|
468
|
-
# specifically to exercise the saga_mutex without real I/O), so
|
|
469
|
-
# refusing the boot outright would break a choice an author made
|
|
470
|
-
# deliberately. What a deploy needs is for the gap to be loud and
|
|
471
|
-
# undeniable, not for local dev/test to become impossible.
|
|
472
|
-
# The outbox's twin of `warn_undurable_sagas!` — a domain that
|
|
473
|
-
# declares anything a commit could owe a reaction to (a policy
|
|
474
|
-
# listening to one of its events, or a process manager) but is
|
|
475
|
-
# bound to an adapter with no outbox (`AppendOnly#outbox?`) gets
|
|
476
|
-
# reactions the pre-outbox way: run inline, lost on a crash
|
|
477
|
-
# between commit and reaction. A warning, not a refusal, for the
|
|
478
|
-
# reason `warn_undurable_sagas!` gives — and Memory has an outbox
|
|
479
|
-
# (in-process, like everything else it holds), so a dev/test
|
|
480
|
-
# boot stays quiet; this speaks up for the file/remote adapters
|
|
481
|
-
# that persist state durably but hand reactions to nothing.
|
|
303
|
+
# A domain with policies/a process_manager but no outbox on its bound adapter
|
|
304
|
+
# (`AppendOnly#outbox?`) runs reactions inline — lost on a crash between a
|
|
305
|
+
# commit and its reaction. A warning, not a refusal: Memory has an in-process
|
|
306
|
+
# outbox, so dev/test stays quiet, but file/remote adapters need this to be loud.
|
|
482
307
|
def warn_undurable_outbox!(hexagon)
|
|
483
308
|
bluebook_ir = bluebook(hexagon.domain)
|
|
484
309
|
return unless bluebook_ir
|
|
@@ -505,6 +330,8 @@ module Hecks
|
|
|
505
330
|
@bluebooks.each_value.any? { |candidate| candidate.policies.any? { |policy| emitted.include?(policy.event_name.to_s) } }
|
|
506
331
|
end
|
|
507
332
|
|
|
333
|
+
# A warning, not a refusal: running sagas on a store with no `save_saga` is
|
|
334
|
+
# legitimate on purpose in a fast in-memory test/dev boot.
|
|
508
335
|
def warn_undurable_sagas!(hexagon)
|
|
509
336
|
bluebook_ir = bluebook(hexagon.domain)
|
|
510
337
|
return unless bluebook_ir
|
|
@@ -1,42 +1,11 @@
|
|
|
1
1
|
module Hecks
|
|
2
2
|
module Runtime
|
|
3
3
|
class Registry
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
# the registry's own worlds. Included into Registry; the callers are the
|
|
7
|
-
# persistence binding policy (`default_adapter_for`), every reader of a bind's
|
|
8
|
-
# world settings (`binding_settings`), and `verify!` (`verify_world_defaults!`).
|
|
9
|
-
#
|
|
10
|
-
# **Resolution order**, most specific first — nothing here ever overrides a
|
|
11
|
-
# chapter's own explicit declaration:
|
|
12
|
-
#
|
|
13
|
-
# 1. the chapter's own `persisted_by(...) { database ... }` block, and the
|
|
14
|
-
# hecksagon bind (aggregate-specific, then domain-level) that names its adapter;
|
|
15
|
-
# 2. the default declared by the chapter's own world;
|
|
16
|
-
# 3. the default declared by the project's world — the world of the first
|
|
17
|
-
# chapter the boot loaded, the same convention `Loader#dispatcher_for` uses
|
|
18
|
-
# to find the domain a boot targets;
|
|
19
|
-
# 4. today's behavior: no database setting, and the framework's in-memory
|
|
20
|
-
# adapter for a chapter with no hecksagon.
|
|
21
|
-
#
|
|
22
|
-
# A default is resolved when a bind's settings or binding are asked for, never
|
|
23
|
-
# written into a chapter's world or hecksagon, so a chapter's own declarations
|
|
24
|
-
# stay exactly what its files say and a hecksagon-less chapter still trips the
|
|
25
|
-
# sibling-hecksagon gates the way it always did.
|
|
4
|
+
# The `default_database`/`default_adapter` a `.world` declares once for every chapter;
|
|
5
|
+
# resolved most-specific-first (own bind, own world, project world) and never written back.
|
|
26
6
|
module WorldDefaults
|
|
27
|
-
# The
|
|
28
|
-
# database
|
|
29
|
-
#
|
|
30
|
-
# The default database only ever reaches a persistence bind whose adapter
|
|
31
|
-
# declares a `database` field — a projection or an adapter without one is
|
|
32
|
-
# untouched. A `database` the chapter's own settings name wins; every other
|
|
33
|
-
# setting the chapter declared rides along unchanged.
|
|
34
|
-
#
|
|
35
|
-
# @param domain [String, Symbol] the domain whose world is asked
|
|
36
|
-
# @param verb [String, Symbol] the bind's port verb, such as `"persisted_by"`
|
|
37
|
-
# @param adapter [String, Symbol] the bind's adapter name
|
|
38
|
-
# @return [Hash{Symbol => Object}] the chapter's own settings for the bind, plus
|
|
39
|
-
# `:database` from the default when one applies; `{}` when there is nothing
|
|
7
|
+
# The default database only reaches a persistence bind whose adapter declares a
|
|
8
|
+
# `database` field; a `database` the chapter's own settings name always wins.
|
|
40
9
|
def binding_settings(domain, verb, adapter)
|
|
41
10
|
declared = world(domain)&.for_binding(verb, adapter) || {}
|
|
42
11
|
database = default_database_for(domain)
|
|
@@ -45,28 +14,10 @@ module Hecks
|
|
|
45
14
|
{ adapter: adapter.to_s, database: database }.merge(declared)
|
|
46
15
|
end
|
|
47
16
|
|
|
48
|
-
# The persistence adapter a chapter's aggregates fall back to when their
|
|
49
|
-
# hecksagon does not bind them.
|
|
50
|
-
#
|
|
51
|
-
# @param domain [String, Symbol] the domain to resolve the default for
|
|
52
|
-
# @return [String, nil] the chapter's own world's `default_adapter`, else the
|
|
53
|
-
# project's; `nil` when neither declares one
|
|
54
17
|
def default_adapter_for(domain) = world_default(domain, :default_adapter)
|
|
55
18
|
|
|
56
|
-
# The database connection a chapter's database-taking persistence adapter uses
|
|
57
|
-
# when its own settings name none.
|
|
58
|
-
#
|
|
59
|
-
# @param domain [String, Symbol] the domain to resolve the default for
|
|
60
|
-
# @return [String, nil] the chapter's own world's `default_database`, else the
|
|
61
|
-
# project's; `nil` when neither declares one
|
|
62
19
|
def default_database_for(domain) = world_default(domain, :default_database)
|
|
63
20
|
|
|
64
|
-
# Refuses a `default_adapter` that no persistence adapter answers to.
|
|
65
|
-
#
|
|
66
|
-
# @return [Runtime::Registry] self
|
|
67
|
-
# @raise [Runtime::WiringError] if a world's `default_adapter` names an unknown
|
|
68
|
-
# adapter, one that is not a persistence adapter, or one with no Ruby
|
|
69
|
-
# implementation
|
|
70
21
|
def verify_world_defaults!
|
|
71
22
|
@worlds.each_value do |declared|
|
|
72
23
|
name = declared.default_adapter
|