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
|
@@ -7,45 +7,12 @@ require_relative "registry"
|
|
|
7
7
|
|
|
8
8
|
module Hecks
|
|
9
9
|
module Runtime
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
# synthetic `eq` one, so every engine that already reads `.wheres`
|
|
13
|
-
# answers a hop for free, with no per-engine code and no way for
|
|
14
|
-
# one engine to forget it.
|
|
15
|
-
#
|
|
16
|
-
# A hop's own filtering never happens here — resolving one hop
|
|
17
|
-
# means running one ordinary, adapter-agnostic query against the
|
|
18
|
-
# hop's target aggregate (through the same Ports::Query boundary
|
|
19
|
-
# any other query goes through), and folding the ids it answers
|
|
20
|
-
# back in as a local membership check. A multi-hop chain resolves
|
|
21
|
-
# from the far end inward: `fold` only ever peels off the head hop
|
|
22
|
-
# (QuerySpecification::HopPath.next_hop, the one-step primitive),
|
|
23
|
-
# and hands everything still left in the tail to a recursive
|
|
24
|
-
# `apply` call — so hop 2, hop 3, and so on each get resolved by
|
|
25
|
-
# their own ordinary query against their own target, one recursion
|
|
26
|
-
# level at a time, never by this module trying to see the whole
|
|
27
|
-
# chain at once. It terminates because each recursion is over a
|
|
28
|
-
# strictly shorter dotted string, and
|
|
29
|
-
# BluebookBuilder#validate_query_hops! already refused any chain
|
|
30
|
-
# deep enough to matter before this ever runs.
|
|
10
|
+
# Folds each hop where-clause into a synthetic local `in` clause, the same trick
|
|
11
|
+
# `TenantScope` uses, so any engine that already reads `.wheres` handles a hop for free.
|
|
31
12
|
module ReferenceHop
|
|
32
13
|
module_function
|
|
33
14
|
|
|
34
15
|
# Folds every hop clause in `declared.wheres` into a synthetic local `in` clause.
|
|
35
|
-
#
|
|
36
|
-
# @param declared [Bluebook::Query, Runtime::TenantScope::Scoped,
|
|
37
|
-
# QuerySpecification::Common::Options] the declared query specification to fold hop
|
|
38
|
-
# clauses of
|
|
39
|
-
# @param args [Hash] the query's arguments, read when resolving each hop's own query
|
|
40
|
-
# @param registry [Runtime::Registry] the booted registry to resolve each hop's target
|
|
41
|
-
# repository from
|
|
42
|
-
# @param domain [String] the domain `aggregate` belongs to
|
|
43
|
-
# @param aggregate [Bluebook::Aggregate] the aggregate `declared` queries
|
|
44
|
-
# @return [Bluebook::Query, Runtime::TenantScope::Scoped, QuerySpecification::Common::
|
|
45
|
-
# Options, Hecks::Runtime::ReferenceHop::Folded] `declared` unchanged when it has no
|
|
46
|
-
# hop clauses; otherwise a `Folded` wrapper whose `#wheres` replaces each hop clause
|
|
47
|
-
# with its folded `in` clause
|
|
48
|
-
# @raise [Runtime::WiringError] if a hop's target no longer resolves (see `fold`)
|
|
49
16
|
def apply(declared, args, registry:, domain:, aggregate:)
|
|
50
17
|
hopped, local = declared.wheres.partition { |clause| QuerySpecification::HopPath.hop_head?(clause.field, aggregate.attributes) }
|
|
51
18
|
return declared if hopped.empty?
|
|
@@ -55,28 +22,12 @@ module Hecks
|
|
|
55
22
|
end
|
|
56
23
|
|
|
57
24
|
# Folds one hop clause into a synthetic `in` clause over the hop attribute's own ids.
|
|
58
|
-
#
|
|
59
|
-
# @param clause [QuerySpecification::Common::WhereClause] the hop clause to fold; its
|
|
60
|
-
# `field` names the hop path, dotted past the first segment
|
|
61
|
-
# @param args [Hash] the query's arguments, read when resolving the inner query
|
|
62
|
-
# @param registry [Runtime::Registry] the booted registry to resolve the hop's target
|
|
63
|
-
# repository from
|
|
64
|
-
# @param domain [String] the domain `aggregate` belongs to
|
|
65
|
-
# @param aggregate [Bluebook::Aggregate] the aggregate `clause` is declared against
|
|
66
|
-
# @return [QuerySpecification::Common::WhereClause] a synthetic `in` clause on the hop
|
|
67
|
-
# attribute's name, whose value is every id the inner clause admits on the target
|
|
68
|
-
# @raise [Runtime::WiringError] if the hop's target aggregate no longer resolves
|
|
69
25
|
def fold(clause, args, registry:, domain:, aggregate:)
|
|
70
26
|
step = QuerySpecification::HopPath.next_hop(clause.field, aggregate.attributes)
|
|
71
27
|
hop, rest = step
|
|
72
28
|
|
|
73
|
-
#
|
|
74
|
-
#
|
|
75
|
-
# an unresolvable target folding silently to "matches
|
|
76
|
-
# everything" is precisely the failure shape this whole feature
|
|
77
|
-
# exists to close, and a hop that can no longer resolve (a
|
|
78
|
-
# target aggregate unloaded after boot, say) is a real fact
|
|
79
|
-
# worth a real error, not a query that quietly stops filtering.
|
|
29
|
+
# BluebookBuilder#validate_query_hops! already checked this hop at boot; if it
|
|
30
|
+
# still fails to resolve here, raise rather than silently matching everything.
|
|
80
31
|
unless hop&.target
|
|
81
32
|
raise WiringError,
|
|
82
33
|
"#{clause.field} hops through a reference this domain cannot resolve " \
|
|
@@ -90,23 +41,8 @@ module Hecks
|
|
|
90
41
|
QuerySpecification::Common::WhereClause.new(field: hop.attribute.name, op: "in", value: ids)
|
|
91
42
|
end
|
|
92
43
|
|
|
93
|
-
# Every id the inner clause
|
|
94
|
-
#
|
|
95
|
-
# through the very same Ports::Query boundary the outer ask
|
|
96
|
-
# uses, so a hop is answered by whatever engine the target
|
|
97
|
-
# aggregate is actually bound to (which may not be the engine
|
|
98
|
-
# the outer aggregate is bound to at all) rather than by a
|
|
99
|
-
# second reading of the comparators.
|
|
100
|
-
#
|
|
101
|
-
# @param domain [String] the domain `target` belongs to
|
|
102
|
-
# @param target [Bluebook::Aggregate] the hop's target aggregate to query
|
|
103
|
-
# @param wheres [Array<QuerySpecification::Common::WhereClause>] the inner clause(s) to
|
|
104
|
-
# run against `target`
|
|
105
|
-
# @param args [Hash] the outer query's arguments, read when resolving the inner query
|
|
106
|
-
# @param registry [Runtime::Registry] the booted registry to resolve `target`'s
|
|
107
|
-
# repository from
|
|
108
|
-
# @return [Array<String>] every distinct id the inner clause(s) admit on `target`
|
|
109
|
-
# @raise [Runtime::WiringError] if a hop nested inside `wheres` no longer resolves
|
|
44
|
+
# Every id the inner clause(s) admit on `target`, queried through `target`'s own
|
|
45
|
+
# repository — which may be bound to a different engine than the outer aggregate.
|
|
110
46
|
def matching_ids(domain, target, wheres, args, registry:)
|
|
111
47
|
spec = apply(QuerySpecification::Common::Options.new(wheres: wheres), args,
|
|
112
48
|
registry: registry, domain: domain, aggregate: target)
|
|
@@ -117,18 +53,9 @@ module Hecks
|
|
|
117
53
|
rows.map { |row| row.id.to_s }.uniq
|
|
118
54
|
end
|
|
119
55
|
|
|
120
|
-
#
|
|
121
|
-
#
|
|
122
|
-
# against the original object, not this override — the exact
|
|
123
|
-
# caution TenantScope::Scoped's own comment gives, for the exact
|
|
124
|
-
# same reason: SimpleDelegator only intercepts calls made
|
|
125
|
-
# directly on the wrapper.
|
|
56
|
+
# SimpleDelegator only intercepts calls made directly on this wrapper, so never
|
|
57
|
+
# hand it to a caller that reads `wheres` via an IR-level method like `to_h`.
|
|
126
58
|
class Folded < SimpleDelegator
|
|
127
|
-
# @param declared [Bluebook::Query, Runtime::TenantScope::Scoped,
|
|
128
|
-
# QuerySpecification::Common::Options] the wrapped query specification, delegated to
|
|
129
|
-
# for everything but `#wheres`
|
|
130
|
-
# @param wheres [Array<QuerySpecification::Common::WhereClause>] the replacement
|
|
131
|
-
# where-clauses, hop clauses folded to synthetic `in` clauses
|
|
132
59
|
def initialize(declared, wheres)
|
|
133
60
|
super(declared)
|
|
134
61
|
@wheres = wheres
|
|
@@ -2,25 +2,8 @@ require_relative "../vocabulary"
|
|
|
2
2
|
|
|
3
3
|
module Hecks
|
|
4
4
|
module Runtime
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
# read at dispatch time off the command or value object that declared
|
|
8
|
-
# them. These are different in kind: language-level refusals, the same
|
|
9
|
-
# wording for every domain, not authored per-bluebook.
|
|
10
|
-
#
|
|
11
|
-
# Read off the generated table, not typed a second time. The rows are
|
|
12
|
-
# Vocabulary::RefusalTemplate (language/bluebook/vocabulary.bluebook),
|
|
13
|
-
# projected into lib/hecks/vocabulary.rb by bin/project_vocabulary and
|
|
14
|
-
# into rust/src/kernel/vocab/refusal_template.rs by
|
|
15
|
-
# bin/project_rust_vocabulary; both regenerations are diffed in CI, so
|
|
16
|
-
# there is no hand copy left here to drift. Declared order is kept.
|
|
17
|
-
#
|
|
18
|
-
# **The arguments are data too**. Vocabulary::RefusalSiteArgument names the
|
|
19
|
-
# values each site takes and how each is written (a list's separator,
|
|
20
|
-
# its sort, its empty reading, its quoting). Call sites use
|
|
21
|
-
# `render_site` and hand over raw values; the Rust kernel's typed
|
|
22
|
-
# `render_args` applies the same rows, and the projection that writes it
|
|
23
|
-
# pins every site's output against `format_argument`/`substitute` here.
|
|
5
|
+
# Language-level DomainRefusal wording, the same for every domain.
|
|
6
|
+
# Templates and argument formats are read from the generated Vocabulary tables.
|
|
24
7
|
module RefusalWording
|
|
25
8
|
TEMPLATES = Hecks::Vocabulary.rows("RefusalTemplate")
|
|
26
9
|
.to_h { |row| [[row["refusal"], row["site"]].freeze, row["template"]] }
|
|
@@ -31,40 +14,13 @@ module Hecks
|
|
|
31
14
|
|
|
32
15
|
module_function
|
|
33
16
|
|
|
34
|
-
# Renders `refusal`/`site`'s template, substituting `values
|
|
35
|
-
#
|
|
36
|
-
# Plain text substitution, never expression syntax — a template is
|
|
37
|
-
# read, not evaluated. Values arrive already formatted; prefer
|
|
38
|
-
# `render_site`, which formats them off the declared rows.
|
|
39
|
-
#
|
|
40
|
-
# @param refusal [String] the `DomainRefusal` class name, such as `"UnknownArgument"`
|
|
41
|
-
# @param site [String] the template site within `refusal`, such as `"unknown_args"`
|
|
42
|
-
# @param values [Hash{Symbol => #to_s}] each `{name}` placeholder's already-formatted
|
|
43
|
-
# replacement text
|
|
44
|
-
# @return [String] the rendered refusal message
|
|
45
|
-
# @raise [KeyError] if no `RefusalTemplate` row declares `refusal`/`site`
|
|
17
|
+
# Renders `refusal`/`site`'s template, substituting already-formatted `values`.
|
|
46
18
|
def render(refusal, site, **values)
|
|
47
19
|
substitute(template(refusal, site), values)
|
|
48
20
|
end
|
|
49
21
|
|
|
50
|
-
#
|
|
51
|
-
#
|
|
52
|
-
# any wording exists), each formatted by its RefusalSiteArgument row,
|
|
53
|
-
# substituted in declared order.
|
|
54
|
-
#
|
|
55
|
-
# RefusalWording.render_site("UnknownArgument", "unknown_args",
|
|
56
|
-
# command: "Close", unknown: [:parcel], declared: [])
|
|
57
|
-
# # => "Close does not declare parcel — it takes none"
|
|
58
|
-
#
|
|
59
|
-
# @param refusal [String] the `DomainRefusal` class name, such as `"UnknownArgument"`
|
|
60
|
-
# @param site [String] the template site within `refusal`, such as `"unknown_args"`
|
|
61
|
-
# @param arguments [Hash{Symbol => Object}] raw values, one per `RefusalSiteArgument`
|
|
62
|
-
# row declared for `refusal`/`site`; formatted per row before substitution
|
|
63
|
-
# @return [String] the rendered refusal message
|
|
64
|
-
# @raise [ArgumentError] if `arguments` is missing a declared argument or offers one
|
|
65
|
-
# `refusal`/`site` does not declare
|
|
66
|
-
# @raise [KeyError] if no `RefusalTemplate`/`RefusalSiteArgument` rows declare
|
|
67
|
-
# `refusal`/`site`
|
|
22
|
+
# Renders a site's template from raw `arguments`, formatting each per its row.
|
|
23
|
+
# Raises ArgumentError on a missing or undeclared argument, KeyError on an unknown site.
|
|
68
24
|
def render_site(refusal, site, **arguments)
|
|
69
25
|
specs = argument_rows(refusal, site)
|
|
70
26
|
declared = specs.map { |spec| spec["argument"].to_sym }
|
|
@@ -78,15 +34,7 @@ module Hecks
|
|
|
78
34
|
render_with(template(refusal, site), specs, arguments)
|
|
79
35
|
end
|
|
80
36
|
|
|
81
|
-
# `render_site` without the registry lookups
|
|
82
|
-
# argument rows, and raw values. The Rust projection calls this with
|
|
83
|
-
# the chapter's own rows to compute the expected wording it pins.
|
|
84
|
-
#
|
|
85
|
-
# @param template [String] the raw template, `{name}` placeholders unsubstituted
|
|
86
|
-
# @param specs [Array<Hash>] the `RefusalSiteArgument` rows to format `arguments`
|
|
87
|
-
# against, one per declared argument name
|
|
88
|
-
# @param arguments [Hash{Symbol => Object}] raw values, one per entry in `specs`
|
|
89
|
-
# @return [String] the rendered refusal message
|
|
37
|
+
# `render_site` without the registry lookups; the Rust projection calls it with its own rows.
|
|
90
38
|
def render_with(template, specs, arguments)
|
|
91
39
|
values = specs.to_h do |spec|
|
|
92
40
|
name = spec["argument"].to_sym
|
|
@@ -95,15 +43,7 @@ module Hecks
|
|
|
95
43
|
substitute(template, values)
|
|
96
44
|
end
|
|
97
45
|
|
|
98
|
-
#
|
|
99
|
-
# (before quoting), then each item quoted, then joined; an empty list
|
|
100
|
-
# reads `when_empty`. A scalar is quoted or taken as its own text.
|
|
101
|
-
#
|
|
102
|
-
# @param spec [Hash] the argument's `RefusalSiteArgument` row (`"shape"`, `"quoting"`,
|
|
103
|
-
# and, for a list, `"sorted"`, `"separator"`, `"when_empty"`)
|
|
104
|
-
# @param value [Object, Array] the raw value to format; an Array (or anything
|
|
105
|
-
# `Array()`-coercible) for a `"list"`-shaped spec, a scalar otherwise
|
|
106
|
-
# @return [String] the formatted text
|
|
46
|
+
# A list is sorted, then quoted, then joined; an empty list reads `when_empty`.
|
|
107
47
|
def format_argument(spec, value)
|
|
108
48
|
inspect = spec.fetch("quoting") == "inspect"
|
|
109
49
|
return inspect ? value.inspect : value.to_s unless spec.fetch("shape") == "list"
|
|
@@ -114,22 +54,10 @@ module Hecks
|
|
|
114
54
|
items.empty? ? spec.fetch("when_empty") : items.join(spec.fetch("separator"))
|
|
115
55
|
end
|
|
116
56
|
|
|
117
|
-
# Replaces each `{name}` placeholder in `template` with its value's text.
|
|
118
|
-
#
|
|
119
|
-
# @param template [String] the raw template, `{name}` placeholders unsubstituted
|
|
120
|
-
# @param values [Hash{Symbol => #to_s}] each placeholder name mapped to its
|
|
121
|
-
# replacement text
|
|
122
|
-
# @return [String] `template` with every `{name}` placeholder substituted
|
|
123
57
|
def substitute(template, values)
|
|
124
58
|
values.reduce(template) { |text, (key, value)| text.gsub("{#{key}}", value.to_s) }
|
|
125
59
|
end
|
|
126
60
|
|
|
127
|
-
# Looks up the raw template text declared for one refusal site.
|
|
128
|
-
#
|
|
129
|
-
# @param refusal [String] the `DomainRefusal` class name, such as `"UnknownArgument"`
|
|
130
|
-
# @param site [String] the template site within `refusal`, such as `"unknown_args"`
|
|
131
|
-
# @return [String] the raw `RefusalTemplate` text, `{name}` placeholders unsubstituted
|
|
132
|
-
# @raise [KeyError] if no `RefusalTemplate` row declares `refusal`/`site`
|
|
133
61
|
def template(refusal, site)
|
|
134
62
|
TEMPLATES.fetch([refusal, site]) do
|
|
135
63
|
raise KeyError, "no refusal template for #{refusal}/#{site} — declare it in " \
|
|
@@ -137,16 +65,7 @@ module Hecks
|
|
|
137
65
|
end
|
|
138
66
|
end
|
|
139
67
|
|
|
140
|
-
#
|
|
141
|
-
#
|
|
142
|
-
# Read lazily, not into a constant: bin/project_vocabulary boots
|
|
143
|
-
# `hecks` (and so this file) before it writes the table a newly
|
|
144
|
-
# declared site's rows live in.
|
|
145
|
-
#
|
|
146
|
-
# @param refusal [String] the `DomainRefusal` class name, such as `"UnknownArgument"`
|
|
147
|
-
# @param site [String] the template site within `refusal`, such as `"unknown_args"`
|
|
148
|
-
# @return [Array<Hash>] the `RefusalSiteArgument` rows declared for `refusal`/`site`
|
|
149
|
-
# @raise [KeyError] if no `RefusalSiteArgument` rows declare `refusal`/`site`
|
|
68
|
+
# Read lazily: bin/project_vocabulary boots this file before it writes these rows.
|
|
150
69
|
def argument_rows(refusal, site)
|
|
151
70
|
@argument_rows ||= Hecks::Vocabulary.rows("RefusalSiteArgument")
|
|
152
71
|
.group_by { |row| [row["refusal"], row["site"]] }
|
|
@@ -3,52 +3,10 @@ require_relative "../saga_pending_dispatch"
|
|
|
3
3
|
module Hecks
|
|
4
4
|
module Runtime
|
|
5
5
|
class Registry
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
# durability, its sagas use the same one, automatically: three
|
|
9
|
-
# optional adapter methods (`save_saga`/`delete_saga`/`each_saga`),
|
|
10
|
-
# `respond_to?`-checked the same way `Ports::Persistence::AppendOnly`
|
|
11
|
-
# already treats an adapter's own optional methods
|
|
12
|
-
# (`find`/`all`/`count`/`reset!`/`events`/`record_event`).
|
|
6
|
+
# A domain's sagas persist through whatever adapter its aggregates already use;
|
|
7
|
+
# `save_saga`/`delete_saga`/`each_saga` are optional, `respond_to?`-checked capabilities.
|
|
13
8
|
module SagaPersistence
|
|
14
|
-
#
|
|
15
|
-
# declared in the domain's own bluebook is the resolution
|
|
16
|
-
# anchor. `Ports::Persistence::BindingPolicy.resolve` for that
|
|
17
|
-
# aggregate already falls back to a domain-level default bind
|
|
18
|
-
# (§0's `Hecksagon#bind_for`) before falling back to Memory, so
|
|
19
|
-
# this needs no separate "was a default declared" branch of its
|
|
20
|
-
# own — whatever adapter that anchor resolves to already is the
|
|
21
|
-
# domain's own default in the normal case (every aggregate
|
|
22
|
-
# shares one adapter), and is the honest, documented fallback
|
|
23
|
-
# for the rarer domain genuinely split across more than one
|
|
24
|
-
# local adapter with no default declared.
|
|
25
|
-
#
|
|
26
|
-
# Genuinely lazy, genuinely POST-boot — unlike `rehydrate_sagas!`
|
|
27
|
-
# below (boot-only), this is called from live dispatch
|
|
28
|
-
# (`SagaInterpreter#checkpoint`/`#end_saga`, on every saga
|
|
29
|
-
# transition), so the first call for a given domain can come from
|
|
30
|
-
# any dispatching thread, not just the boot thread. `@saga_persistence`
|
|
31
|
-
# itself is a plain Hash stood up once in `Registry#initialize` (no
|
|
32
|
-
# race on the container), but `resolve_saga_persistence` is real work
|
|
33
|
-
# (a `BindingPolicy.resolve` plus a lazy `repository` build) whose
|
|
34
|
-
# result — the actual adapter instance a domain's sagas persist
|
|
35
|
-
# through — must be the same object for every caller: two threads
|
|
36
|
-
# racing the first lookup and each building their own adapter would
|
|
37
|
-
# silently split one domain's saga writes across two adapter
|
|
38
|
-
# instances (worse than `Dispatcher#reaction_depth`'s M20 — that bug
|
|
39
|
-
# corrupted a counter; this one can corrupt which store a saga's
|
|
40
|
-
# state lands in). Double-checked locking against a dedicated mutex
|
|
41
|
-
# — never `@saga_mutex` — see `Registry#initialize`'s own comment for
|
|
42
|
-
# why reusing that one would deadlock.
|
|
43
|
-
# Resolves and memoizes the adapter a domain's sagas persist through.
|
|
44
|
-
#
|
|
45
|
-
# @param domain [String, Symbol] the domain to resolve saga persistence for
|
|
46
|
-
# @return [Adapters::Heki, Adapters::Postgres, Adapters::Sqlite, Adapters::D1,
|
|
47
|
-
# Ports::Persistence::Plugins::Era::PostgresEra, Ports::Persistence::NullSagaStore]
|
|
48
|
-
# the same adapter instance the domain's anchor aggregate persists through, when it
|
|
49
|
-
# implements `save_saga`; `NULL_SAGA_STORE` for a domain with no anchor aggregate, an
|
|
50
|
-
# adapter that does not implement the capability, a `RemoteRuntime`-shaped adapter,
|
|
51
|
-
# or a `Runtime::WiringError` resolving the anchor's own bind
|
|
9
|
+
# Memoized per domain via double-checked locking; never reuse @saga_mutex, see #initialize.
|
|
52
10
|
def saga_persistence(domain)
|
|
53
11
|
key = domain.to_s
|
|
54
12
|
@saga_persistence[key] || @saga_persistence_mutex.synchronize do
|
|
@@ -56,34 +14,11 @@ module Hecks
|
|
|
56
14
|
end
|
|
57
15
|
end
|
|
58
16
|
|
|
59
|
-
# Every domain whose sagas can persist somewhere: one with a hecksagon, or one a
|
|
60
|
-
# world's `default_adapter` binds though it has none.
|
|
61
|
-
#
|
|
62
|
-
# @return [Array<String>] the domain names, hecksagon domains first
|
|
63
17
|
def saga_domains = @hecksagons.keys | @bluebooks.keys.select { |domain| default_adapter_for(domain) }
|
|
64
18
|
|
|
65
|
-
#
|
|
66
|
-
#
|
|
67
|
-
# for a domain whose adapter answers the capability, `each_saga`
|
|
68
|
-
# yielding real rows; `NULL_SAGA_STORE`'s own `each_saga` for
|
|
69
|
-
# everything else, which never yields at all, so this needs no
|
|
70
|
-
# `respond_to?` branch of its own — the same reason every other
|
|
71
|
-
# call site in this capability never needs one. Called once at
|
|
72
|
-
# boot (`Loader.boot`, between `verify!` and dispatcher
|
|
73
|
-
# construction) — a process that's been running has no reason to
|
|
74
|
-
# re-walk its own already-current `saga_instances`.
|
|
75
|
-
#
|
|
76
|
-
# Boot-time-only (or its test-runner equivalent) — this method's
|
|
77
|
-
# only callers are `Loader.run_boot_gates!` (single-threaded, before
|
|
78
|
-
# `dispatcher_for` ever exists) and `Registry#reset_runtime_state!`
|
|
79
|
-
# (single-threaded test runner — see that method's own comment).
|
|
80
|
-
# Never called from live dispatch, so `@saga_instances` mutation
|
|
81
|
-
# here has no concurrent caller to race, unlike its other two write
|
|
82
|
-
# points inside `@saga_mutex.synchronize` blocks (`saga_interpreter.
|
|
83
|
-
# rb`), which genuinely do and are guarded accordingly.
|
|
19
|
+
# Boot-time-only (Loader.run_boot_gates!, before dispatch exists); no concurrent
|
|
20
|
+
# writer to race here, unlike saga_interpreter.rb's writes under @saga_mutex.
|
|
84
21
|
# rubocop:disable-next Hecks/ThreadSharedIvarMutation
|
|
85
|
-
#
|
|
86
|
-
# @return [Hecks::Runtime::Registry] self
|
|
87
22
|
def rehydrate_sagas!
|
|
88
23
|
saga_domains.each do |domain|
|
|
89
24
|
saga_persistence(domain).each_saga do |process_manager, correlation, state, memory, completed_compensations = []|
|
|
@@ -98,33 +33,12 @@ module Hecks
|
|
|
98
33
|
|
|
99
34
|
private
|
|
100
35
|
|
|
101
|
-
#
|
|
102
|
-
#
|
|
103
|
-
# process left it standing, means the row's own `state` was
|
|
104
|
-
# checkpointed but the dispatch cascade that justifies it may
|
|
105
|
-
# never have run. Stripped out of `memory` before it becomes
|
|
106
|
-
# this instance's live `:memory` (so nothing downstream — a
|
|
107
|
-
# `given`, a `with:` mapping, the fuzzer — ever sees it), and
|
|
108
|
-
# surfaced loudly instead: a warning plus a `saga_log` entry,
|
|
109
|
-
# never an automatic redrive (see saga_pending_dispatch.rb for
|
|
110
|
-
# why redriving without idempotent delivery would be worse than
|
|
111
|
-
# the stall). This is real, durable crash-recovery visibility —
|
|
112
|
-
# still not the reconciliation itself, which stays a human's
|
|
113
|
-
# call until hecks has idempotent redelivery to make it safe.
|
|
36
|
+
# A pending dispatch marker left by a crash: state was checkpointed but the dispatch
|
|
37
|
+
# cascade it justifies may never have run. Surfaced as a warning, never auto-redriven.
|
|
114
38
|
# rubocop:disable-next Hecks/ThreadSharedIvarMutation -- same
|
|
115
|
-
# justification as `rehydrate_sagas!`'s own disable comment
|
|
116
|
-
# above: this method's only caller is that boot-time-only walk,
|
|
117
|
-
# never live dispatch, so `@saga_log` has no concurrent writer
|
|
118
|
-
# to race here.
|
|
119
39
|
def warn_stalled_saga(domain, process_manager, correlation, state, pending)
|
|
120
|
-
#
|
|
121
|
-
#
|
|
122
|
-
# own `transform_keys`, one level deep); a value nested under
|
|
123
|
-
# one of those keys, like this marker, comes back with plain
|
|
124
|
-
# string keys from Heki specifically, symbol keys already from
|
|
125
|
-
# Postgres/SQLite/D1's own `symbolize_names: true` parse. Normalizing
|
|
126
|
-
# here, once, is simpler than teaching every adapter's own
|
|
127
|
-
# shallow/deep parsing convention about this one reserved key.
|
|
40
|
+
# Heki's each_saga only symbolizes memory's top-level keys, not nested values;
|
|
41
|
+
# Postgres/SQLite/D1 already return symbol keys. Normalize here once for all adapters.
|
|
128
42
|
pending = pending.transform_keys(&:to_sym)
|
|
129
43
|
dispatches = Array(pending[:dispatches]).join(", ")
|
|
130
44
|
warn "[hecks] #{domain} rehydrated #{process_manager} instance #{correlation.inspect} in state " \
|
|
@@ -146,13 +60,7 @@ module Hecks
|
|
|
146
60
|
adapter = repository(domain, anchor).adapter
|
|
147
61
|
adapter.respond_to?(:save_saga) ? adapter : Ports::Persistence::NULL_SAGA_STORE
|
|
148
62
|
rescue WiringError
|
|
149
|
-
#
|
|
150
|
-
# persistence (a test fixture binding only the aggregates it
|
|
151
|
-
# exercises, say) degrades saga persistence to the same no-op
|
|
152
|
-
# default an unbound domain gets — never raises out of a
|
|
153
|
-
# dispatch that would otherwise have succeeded. Matches this
|
|
154
|
-
# capability's own framing throughout: automatic wherever it's
|
|
155
|
-
# cleanly supported, silently absent wherever it isn't.
|
|
63
|
+
# An unwired domain degrades to no saga persistence rather than raising mid-dispatch.
|
|
156
64
|
Ports::Persistence::NULL_SAGA_STORE
|
|
157
65
|
end
|
|
158
66
|
end
|