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
|
@@ -5,33 +5,11 @@ require_relative "../rendering"
|
|
|
5
5
|
|
|
6
6
|
module Hecks
|
|
7
7
|
module Runtime
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
# or did not offer. Built once per dispatch by `Invocation.from_call`, the
|
|
11
|
-
# only place the runtime interprets the shape of a call (`to:` vs `with:`
|
|
12
|
-
# vs the flat facts hash `dispatch_flat` carries, a port operation's
|
|
13
|
-
# reference attribute
|
|
14
|
-
# lifted into `to:`). `Runtime::Routing.envelope`/`.payload` delegate here
|
|
15
|
-
# and no longer hold that logic themselves.
|
|
16
|
-
#
|
|
17
|
-
# `facts` maps a fact name to exactly one of:
|
|
18
|
-
#
|
|
19
|
-
# - `Invocation::Absent` — the key was never offered (every declared
|
|
20
|
-
# attribute the caller left out appears so)
|
|
21
|
-
# - `Invocation::Null` — the key was offered with an explicit nil
|
|
22
|
-
# - `Invocation::Present` — the key was offered with a value
|
|
23
|
-
#
|
|
24
|
-
# Keys are kept exactly as offered: `with:` keys are symbolized (as they
|
|
25
|
-
# always were), a flat facts hash keeps whatever key the wire used. Undeclared keys a caller
|
|
26
|
-
# offered are kept too — refusing them is
|
|
27
|
-
# still `refuse_unknown_arguments`' job, a dispatch step, not this one.
|
|
28
|
-
#
|
|
29
|
-
# I1 changes no behavior: every interpreter still reads `ctx.args`,
|
|
30
|
-
# which is `#to_args` — the same Hash `Routing.payload` returns.
|
|
31
|
-
# Roadmap I2 moves the Ruby `decode_arguments` step onto `facts` itself.
|
|
8
|
+
# One dispatch, as data: the verb, the resolved receiver (`target`, a
|
|
9
|
+
# `Routing::Envelope` or nil), and every fact the caller offered or didn't.
|
|
32
10
|
Invocation = Data.define(:verb, :target, :facts)
|
|
33
11
|
|
|
34
|
-
#
|
|
12
|
+
# Adds the fact wrappers and builders for an `Invocation`.
|
|
35
13
|
class Invocation
|
|
36
14
|
# A fact the caller offered with a real (non-nil) value.
|
|
37
15
|
Present = Data.define(:value) do
|
|
@@ -42,7 +20,6 @@ module Hecks
|
|
|
42
20
|
# The class of the two frozen marker singletons below — never
|
|
43
21
|
# instantiated anywhere else.
|
|
44
22
|
class Marker
|
|
45
|
-
# @param name [String] the marker's own label, used by #inspect/#to_s
|
|
46
23
|
def initialize(name)
|
|
47
24
|
@name = name
|
|
48
25
|
freeze
|
|
@@ -56,51 +33,24 @@ module Hecks
|
|
|
56
33
|
Absent = Marker.new("Absent")
|
|
57
34
|
Null = Marker.new("Null")
|
|
58
35
|
|
|
59
|
-
#
|
|
60
|
-
#
|
|
61
|
-
# the facts carry the identity themselves
|
|
62
|
-
# @param facts [Hash{String, Symbol => Object}] every candidate fact, keyed by
|
|
63
|
-
# offered (or declared) name; frozen, deep-duped, before being stored
|
|
36
|
+
# Dupes and freezes `facts` so a caller can't mutate them after
|
|
37
|
+
# construction.
|
|
64
38
|
def initialize(verb:, target:, facts:)
|
|
65
39
|
super(verb: verb, target: target, facts: facts.dup.freeze)
|
|
66
40
|
end
|
|
67
41
|
|
|
68
|
-
#
|
|
69
|
-
#
|
|
70
|
-
# The fact recorded under `name` — `Absent` for a name never offered
|
|
71
|
-
# and never declared either.
|
|
72
|
-
#
|
|
73
|
-
# @param name [String, Symbol] the fact name to look up
|
|
74
|
-
# @return [Invocation::Present, Invocation::Null, Invocation::Absent] the
|
|
75
|
-
# recorded marker for `name`
|
|
42
|
+
# The fact recorded under `name`; `Absent` when never offered (and not
|
|
43
|
+
# declared either).
|
|
76
44
|
def fact(name) = facts.fetch(name, Absent)
|
|
77
45
|
|
|
78
|
-
# Reports whether `name` was offered with a real, non-nil value.
|
|
79
|
-
#
|
|
80
|
-
# @param name [String, Symbol] the fact name to check
|
|
81
|
-
# @return [Boolean] true if `name` was offered with a non-nil value
|
|
82
46
|
def present?(name) = fact(name).is_a?(Present)
|
|
83
47
|
|
|
84
|
-
# Reports whether `name` was offered with an explicit nil.
|
|
85
|
-
#
|
|
86
|
-
# @param name [String, Symbol] the fact name to check
|
|
87
|
-
# @return [Boolean] true if `name` was offered with an explicit nil
|
|
88
48
|
def null?(name) = fact(name).equal?(Null)
|
|
89
49
|
|
|
90
|
-
# Reports whether `name` was never offered.
|
|
91
|
-
#
|
|
92
|
-
# @param name [String, Symbol] the fact name to check
|
|
93
|
-
# @return [Boolean] true if `name` was never offered (and, if declared, left out)
|
|
94
50
|
def absent?(name) = fact(name).equal?(Absent)
|
|
95
51
|
|
|
96
|
-
# A Present fact's value
|
|
97
|
-
#
|
|
98
|
-
# would re-conflate it with an explicit null, the very ambiguity this
|
|
99
|
-
# type exists to remove. Ask `absent?`/`present?` first.
|
|
100
|
-
#
|
|
101
|
-
# @param name [String, Symbol] the fact name to read
|
|
102
|
-
# @return [Object, nil] the offered value; nil for an explicit Null fact
|
|
103
|
-
# @raise [KeyError] if `name` names an Absent fact (never offered)
|
|
52
|
+
# A Present fact's value (nil for Null). Raises for Absent rather than
|
|
53
|
+
# returning nil, so "never offered" isn't conflated with an explicit null.
|
|
104
54
|
def value(name)
|
|
105
55
|
case (found = fact(name))
|
|
106
56
|
when Present then found.value
|
|
@@ -109,12 +59,8 @@ module Hecks
|
|
|
109
59
|
end
|
|
110
60
|
end
|
|
111
61
|
|
|
112
|
-
# The
|
|
113
|
-
#
|
|
114
|
-
# omitted, Null keys mapped to nil. A fresh Hash every call.
|
|
115
|
-
#
|
|
116
|
-
# @return [Hash{String, Symbol => Object}] the offered facts by name; a fact
|
|
117
|
-
# offered as nil is kept as nil
|
|
62
|
+
# The offered facts as a plain Hash, in offered order: Absent keys
|
|
63
|
+
# omitted, Null mapped to nil. A fresh Hash every call.
|
|
118
64
|
def to_args
|
|
119
65
|
facts.each_with_object({}) do |(name, found), args|
|
|
120
66
|
next if found.equal?(Absent)
|
|
@@ -124,47 +70,10 @@ module Hecks
|
|
|
124
70
|
end
|
|
125
71
|
|
|
126
72
|
class << self
|
|
127
|
-
#
|
|
128
|
-
#
|
|
129
|
-
#
|
|
130
|
-
# that order
|
|
131
|
-
#
|
|
132
|
-
# :aggregate — facts first (`with:` checks), then `to:`
|
|
133
|
-
# :entity — `to:` first, then the block (which resolves the
|
|
134
|
-
# entity chain, UnknownVerb), then facts
|
|
135
|
-
# :port — a reference attribute / identity field lifted into
|
|
136
|
-
# `to:`, then `to:` (which a port operation requires),
|
|
137
|
-
# then facts
|
|
138
|
-
#
|
|
139
|
-
# The block answers the declaring command or port operation (anything
|
|
140
|
-
# with `hecks_name` and `attributes`); it is called exactly once, at
|
|
141
|
-
# the point in that order where the caller always resolved it.
|
|
142
|
-
# `aggregate:` is the owning aggregate construct, read for `:port`
|
|
143
|
-
# only.
|
|
144
|
-
#
|
|
145
|
-
# @param verb [String] the fully qualified verb being dispatched
|
|
146
|
-
# @param to [String, Hash, nil] a bare aggregate identity, or a Hash with
|
|
147
|
-
# `aggregate:` and `entity:`/`entities:`; nil for no explicit receiver
|
|
148
|
-
# @param with [Hash, nil] the command's facts, keyed by attribute name; nil
|
|
149
|
-
# when the caller offers `flat` instead
|
|
150
|
-
# @param flat [Hash] the command's facts as a flat args hash, used when `with`
|
|
151
|
-
# is nil; for `:port`, may also carry the receiver identity under a
|
|
152
|
-
# reference attribute's own name
|
|
153
|
-
# @param receiver [Symbol] which of the three dispatch shapes this is:
|
|
154
|
-
# `:aggregate`, `:entity` or `:port`
|
|
155
|
-
# @param entity_depth [Integer] the number of entity-hop identities `to:`
|
|
156
|
-
# must carry, for `:entity` only
|
|
157
|
-
# @param aggregate [Bluebook::Aggregate, nil] the owning aggregate construct,
|
|
158
|
-
# read for `:port` only
|
|
159
|
-
# @yieldreturn [Class] the declaring command or port-operation class (anything
|
|
160
|
-
# with `hecks_name` and `attributes`)
|
|
161
|
-
# @return [Runtime::Invocation] the built invocation
|
|
162
|
-
# @raise [Runtime::TypeMismatch] if `to:` is malformed, its entity count is
|
|
163
|
-
# wrong, or (`:port` only) the operation resolves no receiving aggregate
|
|
164
|
-
# @raise [Runtime::UnknownArgument] if `with:` names an attribute the command
|
|
165
|
-
# does not declare
|
|
166
|
-
# @raise [Runtime::AbsentArgument] if `with:` omits a required attribute
|
|
167
|
-
# @raise [ArgumentError] if `receiver` is none of `:aggregate`, `:entity` or `:port`
|
|
73
|
+
# Builds an Invocation for one of three call shapes (:aggregate,
|
|
74
|
+
# :entity, :port). Each checks its own parts in a fixed order, because
|
|
75
|
+
# a malformed call's refusal depends on that order; `declaring` is
|
|
76
|
+
# called exactly once, at that shape's point in the order below.
|
|
168
77
|
def from_call(verb, to:, with:, flat:, receiver: :aggregate, entity_depth: 0, aggregate: nil, &declaring)
|
|
169
78
|
case receiver
|
|
170
79
|
when :aggregate
|
|
@@ -182,16 +91,7 @@ module Hecks
|
|
|
182
91
|
end
|
|
183
92
|
end
|
|
184
93
|
|
|
185
|
-
# `to
|
|
186
|
-
#
|
|
187
|
-
# @param to [String, Hash, nil] a bare aggregate identity, or a Hash with
|
|
188
|
-
# `aggregate:` and `entity:`/`entities:`; nil for no receiver
|
|
189
|
-
# @param entity_depth [Integer] the number of entity-hop identities `to`
|
|
190
|
-
# must carry
|
|
191
|
-
# @return [Routing::Envelope, nil] the resolved envelope, or nil when `to`
|
|
192
|
-
# is nil
|
|
193
|
-
# @raise [Runtime::TypeMismatch] if `to` is malformed, or its entity count
|
|
194
|
-
# does not match `entity_depth`
|
|
94
|
+
# `to` as a `Routing::Envelope`, or nil when no `to:` was given.
|
|
195
95
|
def route(to, entity_depth: 0)
|
|
196
96
|
return nil if to.nil?
|
|
197
97
|
|
|
@@ -210,24 +110,8 @@ module Hecks
|
|
|
210
110
|
Routing::Envelope.new(aggregate: aggregate, entities: entities)
|
|
211
111
|
end
|
|
212
112
|
|
|
213
|
-
#
|
|
214
|
-
# keys first
|
|
215
|
-
# not offered, as Absent.
|
|
216
|
-
#
|
|
217
|
-
# @param declaring [Class] the command or port-operation class (anything
|
|
218
|
-
# with `hecks_name` and `attributes`) whose declared attributes are read
|
|
219
|
-
# @param with [Hash, nil] the command's facts, keyed by attribute name; nil
|
|
220
|
-
# when the caller offers `flat` instead
|
|
221
|
-
# @param flat [Hash] the command's facts as a flat args hash, used when `with`
|
|
222
|
-
# is nil
|
|
223
|
-
# @return [Hash{String, Symbol => Invocation::Absent, Invocation::Null,
|
|
224
|
-
# Invocation::Present}] each candidate fact keyed by its offered (or
|
|
225
|
-
# declared) name
|
|
226
|
-
# @raise [Runtime::TypeMismatch] if both `with` and a non-empty `flat` are
|
|
227
|
-
# given, or if `with` is not a Hash
|
|
228
|
-
# @raise [Runtime::UnknownArgument] if `with:` names an attribute `declaring`
|
|
229
|
-
# does not declare
|
|
230
|
-
# @raise [Runtime::AbsentArgument] if `with:` omits a required attribute
|
|
113
|
+
# Every candidate fact for `declaring`, as Absent/Null/Present: offered
|
|
114
|
+
# keys first in offered order, then remaining declared attributes as Absent.
|
|
231
115
|
def facts_for(declaring, with:, flat:)
|
|
232
116
|
offered = offered_facts(declaring, with: with, flat: flat)
|
|
233
117
|
facts = offered.each_with_object({}) do |(name, value), found|
|
|
@@ -242,19 +126,10 @@ module Hecks
|
|
|
242
126
|
|
|
243
127
|
private
|
|
244
128
|
|
|
245
|
-
# **The port operation shape** — moved from `Dispatcher#port_invocation`.
|
|
246
|
-
#
|
|
247
129
|
# A Reference-typed attribute naming the owning aggregate is routing,
|
|
248
130
|
# not a fact: lifted out of the flat facts into `to:` when no `to:`
|
|
249
|
-
# was given.
|
|
250
|
-
#
|
|
251
|
-
# so its receiver is read — not removed — from the plain attribute
|
|
252
|
-
# named for the owner's first `identified_by` field: that attribute
|
|
253
|
-
# is still a declared external fact `refuse_absent_arguments`
|
|
254
|
-
# expects to find (Rust's own comment: "declare only external facts
|
|
255
|
-
# with attribute"; a real AbsentArgument confirmed this before `[]`
|
|
256
|
-
# replaced `delete`). Composite identity is not attempted — `.first`
|
|
257
|
-
# only, no domain in the corpus needs more for a port operation.
|
|
131
|
+
# was given. Only `.first` of a composite identity is used — no
|
|
132
|
+
# domain in the corpus needs more for a port operation.
|
|
258
133
|
def port_call(verb, aggregate, operation, to:, with:, flat:)
|
|
259
134
|
flat = flat.dup
|
|
260
135
|
identity = operation.identity_attribute(aggregate.hecks_name)
|
|
@@ -271,15 +146,9 @@ module Hecks
|
|
|
271
146
|
new(verb: verb, target: target, facts: facts_for(operation, with: with, flat: flat))
|
|
272
147
|
end
|
|
273
148
|
|
|
274
|
-
#
|
|
275
|
-
# `
|
|
276
|
-
#
|
|
277
|
-
# is examined. Surfaced on `examples/roster`'s `Mark`, whose own
|
|
278
|
-
# attribute is literally named `to`: a flat-facts dispatch steals
|
|
279
|
-
# that key into this parameter, and without this check an out-of-range
|
|
280
|
-
# Integer would be accepted as the aggregate identity, leaving Mark's
|
|
281
|
-
# `to` fact absent (AbsentArgument in Ruby, TypeMismatch in Rust). See
|
|
282
|
-
# spec/runtime/routing_envelope_shape_spec.rb.
|
|
149
|
+
# Must be a String, matching Rust's own parity check for `to:` — this
|
|
150
|
+
# keeps a same-named `to` attribute from being stolen as the
|
|
151
|
+
# aggregate identity by a flat-facts dispatch.
|
|
283
152
|
def scalar_envelope(to)
|
|
284
153
|
return [to, []] if to.is_a?(String)
|
|
285
154
|
|
|
@@ -294,13 +163,9 @@ module Hecks
|
|
|
294
163
|
[hash[:aggregate], entity_identities(hash)]
|
|
295
164
|
end
|
|
296
165
|
|
|
297
|
-
#
|
|
298
|
-
#
|
|
299
|
-
#
|
|
300
|
-
# `[].size == 0` would satisfy the depth check and let the degenerate
|
|
301
|
-
# Hash reach the command's own validation. Rust's `RoutingEnvelope::
|
|
302
|
-
# from_json` always refused it at this point. A bare aggregate identity
|
|
303
|
-
# String remains the ordinary aggregate-command shape.
|
|
166
|
+
# An entity route naming no entity is refused here, unconditionally,
|
|
167
|
+
# before entity_depth is checked — otherwise a depth-0 (aggregate)
|
|
168
|
+
# command would let the degenerate `entities: []` Hash slip through.
|
|
304
169
|
def entity_identities(hash)
|
|
305
170
|
raise TypeMismatch, "to: takes entity: or entities:, not both" if hash.key?(:entities) && hash.key?(:entity)
|
|
306
171
|
|
|
@@ -312,9 +177,8 @@ module Hecks
|
|
|
312
177
|
|
|
313
178
|
# `with:` is deliberately strict: a caller choosing the explicit
|
|
314
179
|
# envelope cannot smuggle receiver identity back into the payload,
|
|
315
|
-
# and may not mix it with a flat facts hash. Without `with
|
|
316
|
-
#
|
|
317
|
-
# whether `to:` was given never enters this decision (BUG#17).
|
|
180
|
+
# and may not mix it with a flat facts hash. Without `with:`, the
|
|
181
|
+
# flat facts are taken as-is, unread.
|
|
318
182
|
def offered_facts(declaring, with:, flat:)
|
|
319
183
|
if with && !flat.empty?
|
|
320
184
|
raise TypeMismatch,
|
data/lib/hecks/runtime/loader.rb
CHANGED
|
@@ -8,49 +8,20 @@ require_relative "registry"
|
|
|
8
8
|
|
|
9
9
|
module Hecks
|
|
10
10
|
module Runtime
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
# (era checks, saga rehydration, …), and hands back the Dispatcher
|
|
14
|
-
# (or RemoteDispatcher, for a domain declaring `dispatched_by
|
|
15
|
-
# ("Lambda")`) bound to it — installing the `Widget::Item.Add(...)`
|
|
16
|
-
# facade sugar unless the caller opts out.
|
|
11
|
+
# Boots a domain: loads its bluebook directory into a fresh Registry, runs
|
|
12
|
+
# every boot gate, and hands back the bound Dispatcher (or RemoteDispatcher).
|
|
17
13
|
class Loader
|
|
18
|
-
# `
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
# Ruby constant on `Object` per domain and per aggregate name, with
|
|
23
|
-
# no scoping and no cleanup hook, so a tool booting arbitrary
|
|
24
|
-
# throwaway domains under generic names ("Widget", "Item", "Tag")
|
|
25
|
-
# would otherwise leak those names into the rest of the process —
|
|
26
|
-
# measured, not hypothetical: this exact leak once made an
|
|
27
|
-
# unrelated `dsl_spec.rb` example resolve a bare `Widget` constant
|
|
28
|
-
# to a stale smoke-test facade from a deleted temp directory instead
|
|
29
|
-
# of raising, corrupting that spec's own unrelated build. Skipping
|
|
30
|
-
# the install is safe because nothing downstream of a raw
|
|
31
|
-
# `Dispatcher` needs the sugar — `Dispatcher#dispatch`/`#query` work
|
|
32
|
-
# identically either way.
|
|
33
|
-
# `environment:` — see Adapters::Folder#load_domain's own comment
|
|
34
|
-
# for the mechanism. hecks never reads ENV itself (every other
|
|
35
|
-
# env-var lookup in this codebase lives in app-owned .world/
|
|
36
|
-
# .hecksagon files, never library internals) — a caller resolves
|
|
37
|
-
# its own env var name and passes the resulting string straight
|
|
38
|
-
# through, e.g. `Hecks.boot(path, environment:
|
|
39
|
-
# ENV.fetch("MYAPP_ENV", "development"))`.
|
|
14
|
+
# Boots `path`: loads its bluebook directory into a fresh Registry, runs
|
|
15
|
+
# every registered boot gate, and returns the bound dispatcher. Pass
|
|
16
|
+
# `install_facade: false` to skip the `Widget::Item.Add(...)` global
|
|
17
|
+
# facade sugar (only a caller dispatching by FQN string needs to).
|
|
40
18
|
#
|
|
41
|
-
# @param path [String] a domain directory to boot
|
|
42
|
-
#
|
|
43
|
-
# @param
|
|
44
|
-
# resolves it by walking up from the domain directory
|
|
45
|
-
# @param install_facade [Boolean] whether to install the `Widget::Item.Add(...)`
|
|
46
|
-
# facade sugar
|
|
47
|
-
# @param environment [String, nil] the environment overlay to load after the
|
|
48
|
-
# domain's own files (e.g. `"production"`); nil loads none
|
|
19
|
+
# @param path [String] a domain directory to boot
|
|
20
|
+
# @param shared [String, nil] shared ports/adapters root; nil walks up from `path`
|
|
21
|
+
# @param environment [String, nil] environment overlay loaded after the domain; nil for none
|
|
49
22
|
# @return [Runtime::Dispatcher, Runtime::RemoteDispatcher] the booted dispatcher
|
|
50
|
-
# @raise [Errno::ENOENT] if `path` names
|
|
51
|
-
#
|
|
52
|
-
# @raise [Runtime::WiringError] if a boot gate finds a wiring problem (an undeclared
|
|
53
|
-
# bind, a compute/rekey rule with no persistence plugin loaded, …)
|
|
23
|
+
# @raise [Errno::ENOENT] if `path` names no domain directory
|
|
24
|
+
# @raise [Runtime::WiringError] if a boot gate finds a wiring problem
|
|
54
25
|
def self.boot(path, shared: nil, install_facade: true, environment: nil)
|
|
55
26
|
loading = Ports::Loading.bootstrap
|
|
56
27
|
directory = loading.bluebook_directory(path)
|
|
@@ -70,36 +41,20 @@ module Hecks
|
|
|
70
41
|
install_facade ? bind_runtime(dispatcher) : dispatcher
|
|
71
42
|
end
|
|
72
43
|
|
|
73
|
-
#
|
|
74
|
-
#
|
|
75
|
-
#
|
|
76
|
-
#
|
|
77
|
-
# must already be in memory). `pending` rows are redriven —
|
|
78
|
-
# provably never started; `claimed` rows are surfaced, never
|
|
79
|
-
# auto-redriven — see `Runtime::Outbox`. A remote dispatcher has
|
|
80
|
-
# no local stores to scan.
|
|
81
|
-
#
|
|
82
|
-
# @param dispatcher [Runtime::Dispatcher, Runtime::RemoteDispatcher] the
|
|
83
|
-
# just-booted dispatcher; a no-op unless it exposes an `outbox`
|
|
84
|
-
# @return [void]
|
|
44
|
+
# Redrives pending outbox rows after the dispatcher and saga
|
|
45
|
+
# rehydration both exist (a redriven row may advance a saga, which
|
|
46
|
+
# must already be in memory). Claimed rows are surfaced, never
|
|
47
|
+
# auto-redriven — see `Runtime::Outbox`. A no-op for a remote dispatcher.
|
|
85
48
|
def self.redrive_outbox!(dispatcher)
|
|
86
49
|
return unless dispatcher.respond_to?(:outbox)
|
|
87
50
|
|
|
88
51
|
dispatcher.outbox.redrive!
|
|
89
52
|
end
|
|
90
53
|
|
|
91
|
-
# Turns every `.hecksagon`-declared `
|
|
92
|
-
# `Privacy::Marking.Mark
|
|
93
|
-
#
|
|
94
|
-
#
|
|
95
|
-
# holds itself to above). A no-op when nothing declared one, or when the domain
|
|
96
|
-
# never attached Privacy at all.
|
|
97
|
-
#
|
|
98
|
-
# @param dispatcher [Runtime::Dispatcher, Runtime::RemoteDispatcher] the just-booted
|
|
99
|
-
# dispatcher `Privacy::Marking.Mark` dispatches through
|
|
100
|
-
# @param registry [Runtime::Registry] the just-booted registry `pending_privacy_markings`
|
|
101
|
-
# was recorded on
|
|
102
|
-
# @return [void]
|
|
54
|
+
# Turns every `.hecksagon`-declared `mark_sensitive` fact into a real
|
|
55
|
+
# `Privacy::Marking.Mark`. Idempotent across reboots — a marking already
|
|
56
|
+
# present is never re-dispatched. A no-op when nothing declared one, or
|
|
57
|
+
# the domain never attached Privacy at all.
|
|
103
58
|
def self.seed_privacy_markings!(dispatcher, registry)
|
|
104
59
|
return if registry.pending_privacy_markings.empty?
|
|
105
60
|
return unless registry.bluebook("Privacy")
|
|
@@ -115,40 +70,16 @@ module Hecks
|
|
|
115
70
|
end
|
|
116
71
|
end
|
|
117
72
|
|
|
118
|
-
#
|
|
119
|
-
#
|
|
120
|
-
#
|
|
121
|
-
#
|
|
122
|
-
# `cd`s into), and the wrong one for a caller that wants to declare a
|
|
123
|
-
# narrow, explicit scope and have it booted exactly as declared — a
|
|
124
|
-
# `.behaviors` file's own `loads` line is the motivating caller
|
|
125
|
-
# (`Hecks::Behaviors`), but this carries no behaviors-specific
|
|
126
|
-
# logic and is not gated behind requiring that module.
|
|
73
|
+
# Boots the exact bluebook/hecksagon/world files in `paths`, in place —
|
|
74
|
+
# unlike `boot`, no directory globbing and no copying into a temp dir
|
|
75
|
+
# (a `persisted_by` path must resolve against the real project root,
|
|
76
|
+
# not a copy's).
|
|
127
77
|
#
|
|
128
|
-
#
|
|
129
|
-
#
|
|
130
|
-
#
|
|
131
|
-
# destroys real relative paths, and worse, makes a `persisted_by`
|
|
132
|
-
# path resolve against the temp copy's root instead of the project's
|
|
133
|
-
# own (confirmed there: a file adapter kept reading and writing the
|
|
134
|
-
# same deterministic tmp copy across an entire session, because
|
|
135
|
-
# `Hecks.boot`'s own `root` is always `File.dirname` of whatever
|
|
136
|
-
# directory it was handed). `directory` here is `File.dirname` of the
|
|
137
|
-
# first real path in `paths` — genuinely on disk, not a copy — so
|
|
138
|
-
# every downstream path (`EraCheck`, `persisted_by`, `shared_root`)
|
|
139
|
-
# resolves exactly as an ordinary directory boot's would.
|
|
140
|
-
#
|
|
141
|
-
# @param paths [Array<String>, String] the exact bluebook/hecksagon/world file paths
|
|
142
|
-
# to boot, in the order they should load
|
|
143
|
-
# @param shared [String, nil] an explicit shared ports/adapters root override; nil
|
|
144
|
-
# resolves it by walking up from `File.dirname` of the first path
|
|
145
|
-
# @param install_facade [Boolean] whether to install the `Widget::Item.Add(...)`
|
|
146
|
-
# facade sugar
|
|
147
|
-
# @param environment [String, nil] the environment overlay to load after the
|
|
148
|
-
# named files (e.g. `"production"`); nil loads none
|
|
78
|
+
# @param paths [Array<String>, String] the exact file paths to boot, in load order
|
|
79
|
+
# @param shared [String, nil] shared ports/adapters root; nil walks up from the first path
|
|
80
|
+
# @param environment [String, nil] environment overlay loaded after the named files
|
|
149
81
|
# @return [Runtime::Dispatcher, Runtime::RemoteDispatcher] the booted dispatcher
|
|
150
|
-
# @raise [Runtime::WiringError] if a boot gate finds a wiring problem
|
|
151
|
-
# bind, a compute/rekey rule with no persistence plugin loaded, …)
|
|
82
|
+
# @raise [Runtime::WiringError] if a boot gate finds a wiring problem
|
|
152
83
|
def self.boot_files(paths, shared: nil, install_facade: true, environment: nil)
|
|
153
84
|
loading = Ports::Loading.bootstrap
|
|
154
85
|
files = Array(paths).map { |path| File.expand_path(path) }
|
|
@@ -167,31 +98,10 @@ module Hecks
|
|
|
167
98
|
install_facade ? bind_runtime(dispatcher) : dispatcher
|
|
168
99
|
end
|
|
169
100
|
|
|
170
|
-
# Runs every registered boot gate against `registry`, in order
|
|
171
|
-
#
|
|
172
|
-
#
|
|
173
|
-
#
|
|
174
|
-
# hardcoded, unconditional calls. Ordering is
|
|
175
|
-
# preserved: era-checking (when a persistence plugin contributes one)
|
|
176
|
-
# still runs before `verify!`, saga rehydration still runs after
|
|
177
|
-
# (conservative — see `SagaPersistence#rehydrate_sagas!`'s own
|
|
178
|
-
# comment).
|
|
179
|
-
#
|
|
180
|
-
# ADR 0033 — this loader no longer names `EraCheck`, or any other
|
|
181
|
-
# era-specific class, at all. Every loaded persistence plugin
|
|
182
|
-
# (`Ports::Persistence.each_plugin` — nothing here if nothing was
|
|
183
|
-
# ever `require`d, or brought in by a bound adapter, see
|
|
184
|
-
# `load_bound_adapters!`) is asked to contribute its own `:pre_verify`/
|
|
185
|
-
# `:post_verify` gates generically; `:saga_rehydration` is the one
|
|
186
|
-
# gate core still registers directly, because ADR 0031 already
|
|
187
|
-
# proved it's not era-specific.
|
|
188
|
-
#
|
|
189
|
-
# @param registry [Runtime::Registry] the registry mid-boot, with its bluebooks,
|
|
190
|
-
# hecksagons, ports, adapters and worlds already loaded
|
|
191
|
-
# @param directory [String] the domain directory the gates report against in a refusal
|
|
192
|
-
# @return [Runtime::BootGates] the gates instance built and run for this boot
|
|
193
|
-
# @raise [Runtime::WiringError] if `registry.verify!` or any contributed gate finds
|
|
194
|
-
# a wiring problem
|
|
101
|
+
# Runs every registered boot gate against `registry`, in order:
|
|
102
|
+
# era-checking (if a plugin contributes one) before `verify!`, saga
|
|
103
|
+
# rehydration after. No era-specific class is named here — each loaded
|
|
104
|
+
# persistence plugin contributes its own gates generically (ADR 0031).
|
|
195
105
|
def self.run_boot_gates!(registry, directory)
|
|
196
106
|
gates = BootGates.new
|
|
197
107
|
load_bound_adapters!(registry)
|
|
@@ -208,17 +118,11 @@ module Hecks
|
|
|
208
118
|
end
|
|
209
119
|
|
|
210
120
|
# Resolves the Ruby implementation of every adapter a hecksagon binds.
|
|
211
|
-
#
|
|
212
|
-
#
|
|
213
|
-
#
|
|
214
|
-
#
|
|
215
|
-
#
|
|
216
|
-
# loaded and its era gates registered, without the app requiring the plugin
|
|
217
|
-
# itself. An adapter with no Ruby implementation is left for `verify!`, which
|
|
218
|
-
# refuses it with the bind it came from.
|
|
219
|
-
#
|
|
220
|
-
# @param registry [Runtime::Registry] the registry mid-boot, whose hecksagons name the binds
|
|
221
|
-
# @return [void]
|
|
121
|
+
# An adapter's implementation can register its own persistence plugin as
|
|
122
|
+
# a side effect of loading (e.g. `PostgresEra`) — resolving here, before
|
|
123
|
+
# gates are collected, is what registers those plugins' gates without
|
|
124
|
+
# the app requiring them itself. A bind with no implementation is left
|
|
125
|
+
# for `verify!` to refuse.
|
|
222
126
|
def self.load_bound_adapters!(registry)
|
|
223
127
|
registry.hecksagons.each_value do |hexagon|
|
|
224
128
|
hexagon.binds.each do |bind|
|
|
@@ -229,23 +133,10 @@ module Hecks
|
|
|
229
133
|
end
|
|
230
134
|
end
|
|
231
135
|
|
|
232
|
-
#
|
|
233
|
-
#
|
|
234
|
-
#
|
|
235
|
-
#
|
|
236
|
-
# translation.rb`, core, no era-specific class involved), so this
|
|
237
|
-
# needs nothing plugin-specific to ask "does anything declare a
|
|
238
|
-
# compute/rekey rule at all." A loaded persistence plugin (e.g. the
|
|
239
|
-
# era plugin's own `:era_compute_rules` gate, registered above) runs
|
|
240
|
-
# the real, adapter-aware version of this check and refuses by name
|
|
241
|
-
# ("...is bound to Memory") long before this ever would; this only
|
|
242
|
-
# fires when nothing did, because nothing was loaded to.
|
|
243
|
-
#
|
|
244
|
-
# @param registry [Runtime::Registry] the registry mid-boot, whose declared
|
|
245
|
-
# `translations` are checked
|
|
246
|
-
# @return [void]
|
|
247
|
-
# @raise [Runtime::WiringError] if any translation declares a `computes`/`rekeys`
|
|
248
|
-
# rule while no persistence plugin is loaded to interpret it
|
|
136
|
+
# A backstop only: fires when a translation declares a `computes`/
|
|
137
|
+
# `rekeys` rule but no persistence plugin is loaded to interpret it.
|
|
138
|
+
# Any loaded plugin's own compute-rules gate refuses earlier, by name,
|
|
139
|
+
# whenever one is loaded — this only runs when nothing was.
|
|
249
140
|
def self.check_compute_rules_backstop!(registry)
|
|
250
141
|
return if Ports::Persistence.plugins_loaded?
|
|
251
142
|
|
|
@@ -261,31 +152,11 @@ module Hecks
|
|
|
261
152
|
end
|
|
262
153
|
end
|
|
263
154
|
|
|
264
|
-
# `RemoteDispatcher` for a domain
|
|
265
|
-
# `Dispatcher` otherwise
|
|
266
|
-
#
|
|
267
|
-
#
|
|
268
|
-
#
|
|
269
|
-
# name (insertion order — the target's own bluebook loads before
|
|
270
|
-
# any `uses_framework` chapter, `bin/project_rust`'s own header
|
|
271
|
-
# draws the identical distinction), not a directory basename.
|
|
272
|
-
#
|
|
273
|
-
# `dispatched_by("Lambda")` is its own, explicit verb — not
|
|
274
|
-
# inferred from `deployed_to("AwsLambda")`'s mere presence. Both
|
|
275
|
-
# Banking's and Embryonaut's `.world` files already declare
|
|
276
|
-
# `deployed_to("AwsLambda")` (it only means "a deploy target
|
|
277
|
-
# exists"), so treating that alone as "boot this domain against
|
|
278
|
-
# Lambda" would have silently rerouted Banking's every local
|
|
279
|
-
# boot — every spec, every `bin/console` session — the moment
|
|
280
|
-
# this landed. A domain opts in explicitly, the same way
|
|
281
|
-
# `persisted_by("PostgresEra")` is never inferred from anything
|
|
282
|
-
# else either.
|
|
283
|
-
#
|
|
284
|
-
# @param registry [Runtime::Registry] the just-booted registry, whose just-booted
|
|
285
|
-
# domain's `.world` is checked for `dispatched_by("Lambda")`
|
|
286
|
-
# @return [Runtime::Dispatcher, Runtime::RemoteDispatcher] a `RemoteDispatcher`
|
|
287
|
-
# bound to `registry` if the domain declares `dispatched_by("Lambda")`, a plain
|
|
288
|
-
# `Dispatcher` otherwise
|
|
155
|
+
# `RemoteDispatcher` for a domain declaring `dispatched_by("Lambda")`,
|
|
156
|
+
# `Dispatcher` otherwise. That's an explicit opt-in, never inferred from
|
|
157
|
+
# `deployed_to("AwsLambda")` alone — that verb only means a deploy
|
|
158
|
+
# target exists, and treating it as "dispatch via Lambda" would reroute
|
|
159
|
+
# every local boot of a domain that merely declares one.
|
|
289
160
|
def self.dispatcher_for(registry)
|
|
290
161
|
domain = registry.bluebooks.keys.first
|
|
291
162
|
settings = registry.world(domain)&.for_verb("dispatched_by") || {}
|
|
@@ -294,18 +165,9 @@ module Hecks
|
|
|
294
165
|
RemoteDispatcher.new(registry, region: settings.fetch(:region, "us-east-1"), function: settings[:function])
|
|
295
166
|
end
|
|
296
167
|
|
|
297
|
-
# Installs the facade sugar (`Widget::Item.Add(...)`)
|
|
298
|
-
# `dispatcher
|
|
299
|
-
#
|
|
300
|
-
# The door is installed here, not stamped: the facade's modules close
|
|
301
|
-
# over this dispatcher, so the binding lives in the surface a boot
|
|
302
|
-
# installs rather than in a class-level global (`ruby_class.runtime =`
|
|
303
|
-
# on every aggregate's class) that would make two boots in one process
|
|
304
|
-
# share one name.
|
|
305
|
-
#
|
|
306
|
-
# @param dispatcher [Runtime::Dispatcher, Runtime::RemoteDispatcher] the
|
|
307
|
-
# just-booted dispatcher the facade should call into
|
|
308
|
-
# @return [Runtime::Dispatcher, Runtime::RemoteDispatcher] `dispatcher`, unchanged
|
|
168
|
+
# Installs the facade sugar (`Widget::Item.Add(...)`) closed over
|
|
169
|
+
# `dispatcher`. The binding lives in the facade's own modules, not a
|
|
170
|
+
# class-level global, so two boots in one process don't share one name.
|
|
309
171
|
def self.bind_runtime(dispatcher)
|
|
310
172
|
Facade::Surface.install(dispatcher)
|
|
311
173
|
dispatcher
|