hecks 3.9.1 → 3.11.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/examples/pizzas/bluebook/pizzas.bluebook +29 -0
- data/examples/pizzas/bluebook/pizzas.hecksagon +7 -0
- data/exe/hecks +4 -4
- data/lib/hecks/adapters/driven/d1.rb +2 -10
- data/lib/hecks/adapters/driven/heki.adapter +1 -1
- data/lib/hecks/adapters/driven/heki.rb +2 -12
- data/lib/hecks/adapters/driven/lambda.adapter +1 -1
- data/lib/hecks/adapters/driven/lambda.rb +3 -18
- data/lib/hecks/adapters/driven/postgres.rb +4 -11
- data/lib/hecks/adapters/driven/sqlite.adapter +1 -1
- data/lib/hecks/adapters/driven/sqlite.rb +2 -10
- data/lib/hecks/adapters/driving/admission.rb +46 -0
- data/lib/hecks/adapters/driving/cli/nesting.rb +36 -0
- data/lib/hecks/adapters/driving/cli/shorthand.rb +88 -0
- data/lib/hecks/adapters/driving/cli.rb +127 -0
- data/lib/hecks/adapters/driving/cli_runner/answers.rb +160 -0
- data/lib/hecks/adapters/driving/cli_runner/resolution.rb +155 -0
- data/lib/hecks/adapters/driving/cli_runner/settling.rb +120 -0
- data/lib/hecks/adapters/driving/cli_runner/streaming.rb +93 -0
- data/lib/hecks/adapters/driving/cli_runner/suggestions.rb +47 -0
- data/lib/hecks/adapters/driving/cli_runner.rb +69 -0
- data/lib/hecks/adapters/driving/command_request.rb +121 -0
- data/lib/hecks/adapters/driving/handle.rb +214 -0
- data/lib/hecks/adapters/driving/json.rb +136 -0
- data/lib/hecks/adapters/driving/launcher_options.rb +267 -0
- data/lib/hecks/adapters/driving/mcp/properties.rb +49 -0
- data/lib/hecks/adapters/driving/mcp/tool_calls.rb +116 -0
- data/lib/hecks/adapters/driving/mcp/tool_definitions/auditing.rb +53 -0
- data/lib/hecks/adapters/driving/mcp/tool_definitions/calling.rb +71 -0
- data/lib/hecks/adapters/driving/mcp/tool_definitions/reading.rb +99 -0
- data/lib/hecks/adapters/driving/mcp/tool_definitions.rb +18 -0
- data/lib/hecks/adapters/driving/mcp.rb +159 -0
- data/lib/hecks/adapters/driving/mcp_guide_cache.rb +78 -0
- data/lib/hecks/adapters/driving/mcp_scope/argument_policy.rb +97 -0
- data/lib/hecks/adapters/driving/mcp_scope/env_problems.rb +69 -0
- data/lib/hecks/adapters/driving/mcp_scope/presenter.rb +83 -0
- data/lib/hecks/adapters/driving/mcp_scope.rb +213 -0
- data/lib/hecks/adapters/driving/ruby/aggregate_module.rb +171 -0
- data/lib/hecks/adapters/driving/ruby/chapter.rb +91 -0
- data/lib/hecks/adapters/driving/ruby.rb +83 -0
- data/lib/hecks/adapters/driving/usage_cache.rb +144 -0
- data/lib/hecks/{doors.rb → adapters/driving.rb} +10 -6
- data/lib/hecks/behaviors/expectations/boot.rb +1 -1
- data/lib/hecks/bench/ruby_runner.rb +1 -1
- data/lib/hecks/bluebook/ask_resolution.rb +130 -0
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +8 -2
- data/lib/hecks/bluebook/assembly/contracts/rules.rb +4 -2
- data/lib/hecks/bluebook/assembly/contracts/structure.rb +3 -1
- data/lib/hecks/bluebook/assembly/marks.rb +1 -0
- data/lib/hecks/bluebook/attribute.rb +1 -1
- data/lib/hecks/bluebook/behaviour/command.rb +13 -8
- data/lib/hecks/bluebook/behaviour/policy.rb +30 -0
- data/lib/hecks/bluebook/capabilities/attribute_values.rb +72 -0
- data/lib/hecks/bluebook/capabilities.rb +91 -9
- data/lib/hecks/bluebook/domain_port.rb +16 -4
- data/lib/hecks/bluebook/dsl/adapter_builder.rb +18 -6
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +13 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/computed_sources.rb +98 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/fan_out_rows.rb +42 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/projected_fields.rb +14 -2
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/provisions.rb +69 -3
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/with_projections.rb +17 -10
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +5 -0
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +2 -0
- data/lib/hecks/bluebook/dsl/command_builder/mutations.rb +8 -1
- data/lib/hecks/bluebook/dsl/command_builder/operands.rb +121 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +2 -0
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +10 -1
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +45 -2
- data/lib/hecks/bluebook/dsl/policy_builder.rb +47 -10
- data/lib/hecks/bluebook/dsl/rule_reference.rb +7 -4
- data/lib/hecks/bluebook/dsl/world_builder.rb +1 -1
- data/lib/hecks/bluebook/expression/ast_json/emitters.rb +6 -0
- data/lib/hecks/bluebook/expression/ast_json.rb +9 -6
- data/lib/hecks/bluebook/expression/ast_reader.rb +14 -9
- data/lib/hecks/bluebook/expression/projection.json +36 -0
- data/lib/hecks/bluebook/expression/resolver/operations.rb +31 -0
- data/lib/hecks/bluebook/expression/resolver/parsing.rb +38 -5
- data/lib/hecks/bluebook/expression/resolver/scanning.rb +22 -5
- data/lib/hecks/bluebook/expression/resolver/values.rb +10 -0
- data/lib/hecks/bluebook/expression/resolver.rb +20 -1
- data/lib/hecks/bluebook/hecksagon.rb +23 -3
- data/lib/hecks/bluebook/lifecycle.rb +22 -3
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +13 -1
- data/lib/hecks/bluebook/meta_validator/modes.rb +4 -1
- data/lib/hecks/bluebook/meta_validator/readings.rb +18 -1
- data/lib/hecks/bluebook/meta_validator/reconstruction/heads.rb +2 -1
- data/lib/hecks/bluebook/meta_validator/shapes.rb +5 -0
- data/lib/hecks/bluebook/meta_validator/verdict_cache.rb +1 -1
- data/lib/hecks/bluebook/meta_validator.rb +12 -12
- data/lib/hecks/bluebook/model_check/ask_checks.rb +71 -0
- data/lib/hecks/bluebook/model_check/policy_checks.rb +2 -1
- data/lib/hecks/bluebook/model_check/reference_checks.rb +70 -0
- data/lib/hecks/bluebook/model_check.rb +8 -2
- data/lib/hecks/bluebook/policy.rb +4 -2
- data/lib/hecks/bluebook/smoke_test.rb +1 -1
- data/lib/hecks/bluebook/synthesizer.rb +2 -0
- data/lib/hecks/bluebook.rb +1 -0
- data/lib/hecks/cli/command_table.rb +1 -1
- data/lib/hecks/cli/console.rb +2 -1
- data/lib/hecks/cli/document.rb +1 -1
- data/lib/hecks/cli/launcher_words.rb +4 -4
- data/lib/hecks/cli/mcp.rb +4 -4
- data/lib/hecks/cli/project_cli/launcher_source.rb +2 -2
- data/lib/hecks/cli/project_cli/templates.rb +5 -5
- data/lib/hecks/cli/project_cli.rb +9 -6
- data/lib/hecks/cli/run.rb +2 -2
- data/lib/hecks/cli/smoke_http/checks.rb +4 -1
- data/lib/hecks/cli/smoke_http/transport.rb +3 -3
- data/lib/hecks/cli/smoke_http.rb +3 -0
- data/lib/hecks/codemod.rb +5 -2
- data/lib/hecks/corpus/routes.rb +7 -0
- data/lib/hecks/corpus/rust.rb +3 -2
- data/lib/hecks/deploy/bluebook/deploy.bluebook +124 -2
- data/lib/hecks/deploy/bluebook/deploy.hecksagon +8 -0
- data/lib/hecks/deploy/oidc.json +16 -3
- data/lib/hecks/doc/reference/rendering.rb +6 -3
- data/lib/hecks/forms/app/commands.rb +8 -7
- data/lib/hecks/forms/app/queries.rb +2 -1
- data/lib/hecks/forms/app.rb +1 -1
- data/lib/hecks/forms/record_renderer.rb +1 -1
- data/lib/hecks/framework/bluebook/privacy.bluebook +11 -0
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +4 -1
- data/lib/hecks/fuzzing/failure_triage.rb +2 -1
- data/lib/hecks/fuzzing/mutation/run.rb +11 -4
- data/lib/hecks/fuzzing/properties/catalog.rb +6 -4
- data/lib/hecks/fuzzing/properties/guaranteed_by_construction.rb +18 -11
- data/lib/hecks/fuzzing/properties/guards.rb +1 -1
- data/lib/hecks/fuzzing/self_consistency/saga_redelivery.rb +1 -1
- data/lib/hecks/fuzzing/self_consistency.rb +6 -2
- data/lib/hecks/fuzzing/shrinker.rb +3 -1
- data/lib/hecks/fuzzing/value_generator.rb +19 -5
- data/lib/hecks/gate/stages.yml +4 -10
- data/lib/hecks/grammar/evolve.rb +1 -1
- data/lib/hecks/grammar/expression_operators.json +372 -0
- data/lib/hecks/grammar/operators.rb +3 -1
- data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +10 -10
- data/lib/hecks/hecks/adapters/codebase/inspection/rubycritic.rb +35 -0
- data/lib/hecks/hecks/adapters/codebase/inspection.rb +104 -0
- data/lib/hecks/hecks/adapters/codebase/publishing.rb +2 -1
- data/lib/hecks/hecks/adapters/codebase/release_facts.rb +12 -2
- data/lib/hecks/hecks/adapters/codebase/source_tree.rb +2 -1
- data/lib/hecks/hecks/adapters/codebase/test_runner.rb +1 -1
- data/lib/hecks/hecks/adapters/cost_explorer.rb +8 -5
- data/lib/hecks/hecks/adapters/deploy_toolchain/clearing.rb +51 -0
- data/lib/hecks/hecks/adapters/deploy_toolchain/statuses.rb +2 -1
- data/lib/hecks/hecks/adapters/deploy_toolchain.rb +2 -0
- data/lib/hecks/hecks/adapters/finding_github.rb +13 -6
- data/lib/hecks/hecks/adapters/first_admin.rb +2 -2
- data/lib/hecks/hecks/adapters/github_rulesets.rb +6 -3
- data/lib/hecks/hecks/adapters/in_process_boot.rb +1 -1
- data/lib/hecks/hecks/adapters/journal_store/compaction.rb +1 -1
- data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +10 -20
- data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +28 -5
- data/lib/hecks/hecks/adapters/local_files.rb +2 -2
- data/lib/hecks/hecks/adapters/rehearsal/audit_report.rb +107 -0
- data/lib/hecks/hecks/adapters/rehearsal/census.rb +71 -0
- data/lib/hecks/hecks/adapters/rehearsal/declaration.rb +133 -0
- data/lib/hecks/hecks/adapters/rehearsal/environment.rb +83 -0
- data/lib/hecks/hecks/adapters/rehearsal/inquiry.rb +142 -0
- data/lib/hecks/hecks/adapters/rehearsal/memory_store.rb +96 -0
- data/lib/hecks/hecks/adapters/rehearsal/postgres_census.rb +100 -0
- data/lib/hecks/hecks/adapters/rehearsal/postgres_reading.rb +69 -0
- data/lib/hecks/hecks/adapters/rehearsal/postgres_store.rb +129 -0
- data/lib/hecks/hecks/adapters/rehearsal/rows.rb +41 -0
- data/lib/hecks/hecks/adapters/rehearsal/rust_audit.rb +83 -0
- data/lib/hecks/hecks/adapters/rehearsal/subject.rb +104 -0
- data/lib/hecks/hecks/adapters/rehearsal.rb +54 -0
- data/lib/hecks/hecks/adapters/rehearsal_store.adapter +7 -0
- data/lib/hecks/hecks/adapters/rehearsal_store.rb +81 -0
- data/lib/hecks/hecks/adapters/site_toolchain/role_prober.rb +78 -0
- data/lib/hecks/hecks/adapters/site_toolchain.rb +29 -4
- data/lib/hecks/hecks/adapters/terminal.rb +13 -11
- data/lib/hecks/hecks/adapters/world_clearing.rb +65 -0
- data/lib/hecks/hecks/codebase.behaviors +13 -1
- data/lib/hecks/hecks/codebase.bluebook +239 -5
- data/lib/hecks/hecks/custodian.behaviors +24 -6
- data/lib/hecks/hecks/custodian.bluebook +6 -1227
- data/lib/hecks/hecks/deploy.behaviors +1 -1
- data/lib/hecks/hecks/deploy.world +1 -3
- data/lib/hecks/hecks/hecks.behaviors +1 -1
- data/lib/hecks/hecks/hecks.hecksagon +61 -18
- data/lib/hecks/hecks/hecks.world +11 -10
- data/lib/hecks/hecks/rehearsal.bluebook +477 -0
- data/lib/hecks/hecks/site.behaviors +1 -1
- data/lib/hecks/hecks/site.world +0 -1
- data/lib/hecks/hecks/tooling.bluebook +1238 -0
- data/lib/hecks/indifferent_key.rb +20 -0
- data/lib/hecks/language/adapter.bluebook +13 -3
- data/lib/hecks/language/bluebook/aggregate.bluebook +23 -0
- data/lib/hecks/language/bluebook/bluebook.bluebook +15 -0
- data/lib/hecks/language/bluebook/entity.bluebook +18 -0
- data/lib/hecks/language/bluebook/policy.bluebook +9 -1
- data/lib/hecks/language/bluebook/query.bluebook +1 -1
- data/lib/hecks/language/bluebook/vocabulary.bluebook +11 -4
- data/lib/hecks/language/hecksagon/domain_port.bluebook +1 -1
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +22 -0
- data/lib/hecks/language/oidc.json +10 -0
- data/lib/hecks/language/port.bluebook +4 -4
- data/lib/hecks/literal.rb +12 -3
- data/lib/hecks/ports/key_vault.rb +7 -2
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +21 -10
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/boot.rb +4 -2
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +2 -1
- data/lib/hecks/ports/persistence/repository_factory.rb +6 -3
- data/lib/hecks/projections/deploy/box/templates/deploy-box.sh.tmpl +29 -0
- data/lib/hecks/projections/deploy/box/templates/deploy-service.sh.tmpl +1 -1
- data/lib/hecks/projections/deploy/fargate/settings/tuning.rb +15 -0
- data/lib/hecks/projections/deploy/fargate/settings.rb +3 -1
- data/lib/hecks/projections/deploy/fargate/stack/readers.rb +1 -0
- data/lib/hecks/projections/deploy/preview/preview.sh.erb +1 -1
- data/lib/hecks/projections/deploy/shared.rb +5 -2
- data/lib/hecks/projections/deploy/templates/fargate/Makefile.tmpl +7 -4
- data/lib/hecks/projections/model/deviations.rb +2 -2
- data/lib/hecks/projections/model.rb +2 -2
- data/lib/hecks/projections/oidc.rb +13 -1
- data/lib/hecks/projections/shape.rb +5 -2
- data/lib/hecks/projections/site/cms_editor/attributes.rb +95 -0
- data/lib/hecks/projections/site/cms_editor/blocks.rb +157 -0
- data/lib/hecks/projections/site/cms_editor/checks.rb +77 -0
- data/lib/hecks/projections/site/cms_editor/clearing.rb +70 -0
- data/lib/hecks/projections/site/cms_editor/color.rb +124 -0
- data/lib/hecks/projections/site/cms_editor/composition.rb +42 -0
- data/lib/hecks/projections/site/cms_editor/destructive.rb +61 -0
- data/lib/hecks/projections/site/cms_editor/drafts.rb +102 -0
- data/lib/hecks/projections/site/cms_editor/hints.rb +74 -0
- data/lib/hecks/projections/site/cms_editor/icons.rb +86 -0
- data/lib/hecks/projections/site/cms_editor/key_kinds.rb +31 -0
- data/lib/hecks/projections/site/cms_editor/limits.rb +72 -0
- data/lib/hecks/projections/site/cms_editor/media.rb +85 -0
- data/lib/hecks/projections/site/cms_editor/moment.rb +34 -0
- data/lib/hecks/projections/site/cms_editor/palette.rb +115 -0
- data/lib/hecks/projections/site/cms_editor/pickers.rb +85 -0
- data/lib/hecks/projections/site/cms_editor/pretty.rb +40 -0
- data/lib/hecks/projections/site/cms_editor/preview.rb +91 -0
- data/lib/hecks/projections/site/cms_editor/relations.rb +92 -0
- data/lib/hecks/projections/site/cms_editor/scale_checks.rb +66 -0
- data/lib/hecks/projections/site/cms_editor/scheduling.rb +150 -0
- data/lib/hecks/projections/site/cms_editor/schema.rb +161 -0
- data/lib/hecks/projections/site/cms_editor/setting.rb +130 -0
- data/lib/hecks/projections/site/cms_editor/targets.rb +86 -0
- data/lib/hecks/projections/site/cms_editor/templates/package.json.tmpl +36 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/app.ts.tmpl +370 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/assets.ts.tmpl +98 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/auth/membership.ts.tmpl +87 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/auth/session.ts.tmpl +36 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/auth/sso.ts.tmpl +20 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/app.css.tmpl +412 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/autosave.js.tmpl +144 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/blocks.js.tmpl +500 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/body_doc.js.tmpl +175 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/body_editor.js.tmpl +418 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/epoch.js.tmpl +61 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/forms.js.tmpl +210 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/lists.js.tmpl +40 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/main.js.tmpl +26 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/media_picker.js.tmpl +232 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/moments.js.tmpl +73 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/pickers.js.tmpl +152 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/preview.js.tmpl +98 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/shell.js.tmpl +140 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/toast.js.tmpl +66 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/choices.ts.tmpl +99 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/commands.ts.tmpl +133 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/config.ts.tmpl +29 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/flash.ts.tmpl +52 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/host.ts.tmpl +43 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/media/handler.ts.tmpl +177 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/media/multipart.ts.tmpl +53 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/media/sniff.ts.tmpl +94 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/media/storage.ts.tmpl +50 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/names.ts.tmpl +36 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/schema.ts.tmpl +214 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/server.ts.tmpl +65 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/availability.ts.tmpl +15 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/block_list.js.tmpl +213 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/blocks.ts.tmpl +275 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/body_model.js.tmpl +123 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/body_parse.js.tmpl +320 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/detail.ts.tmpl +88 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/dialogs.ts.tmpl +43 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/fields.ts.tmpl +275 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/html.ts.tmpl +61 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/icons.ts.tmpl +15 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/input.ts.tmpl +92 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/links.ts.tmpl +100 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/moments.ts.tmpl +44 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/outline.ts.tmpl +63 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/pages.ts.tmpl +213 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/paging.ts.tmpl +82 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/pickers.ts.tmpl +110 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/preview.ts.tmpl +87 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/related.ts.tmpl +97 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/schedule.ts.tmpl +160 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/shell.ts.tmpl +211 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/table.ts.tmpl +151 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/theme.js.tmpl +16 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/values.ts.tmpl +69 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/words.ts.tmpl +97 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/world.ts.tmpl +35 -0
- data/lib/hecks/projections/site/cms_editor/templates/tsconfig.json.tmpl +17 -0
- data/lib/hecks/projections/site/cms_editor/theme.rb +29 -0
- data/lib/hecks/projections/site/cms_editor/theme_checks.rb +57 -0
- data/lib/hecks/projections/site/cms_editor.rb +133 -0
- data/lib/hecks/projections/site/role_probe.rb +74 -0
- data/lib/hecks/projector/cli_audience.rb +2 -1
- data/lib/hecks/projector/cli_projector/listing.rb +1 -1
- data/lib/hecks/projector/cli_projector/option_specs.rb +1 -1
- data/lib/hecks/projector/docs_projector/closing.rb +1 -1
- data/lib/hecks/projector/docs_projector.rb +1 -1
- data/lib/hecks/projector/exporter/bindings.rb +40 -10
- data/lib/hecks/projector/exporter/capability_values.rb +55 -0
- data/lib/hecks/projector/narrate_projector/reactions.rb +1 -1
- data/lib/hecks/projector/target.rb +11 -0
- data/lib/hecks/projector.rb +32 -5
- data/lib/hecks/quality_control/adapters/github_checks.rb +12 -8
- data/lib/hecks/quality_control/adapters/github_issues.rb +8 -4
- data/lib/hecks/quality_control/cli/qa_open_pr.rb +2 -2
- data/lib/hecks/quality_control/cli/qa_sweep/checks/shrinking.rb +1 -1
- data/lib/hecks/quality_control/cli/qa_sweep/finding_report.rb +1 -1
- data/lib/hecks/quality_control/cli/qa_sweep.rb +1 -1
- data/lib/hecks/quality_control/quality_control.bluebook +6 -2
- data/lib/hecks/release/approval.rb +64 -0
- data/lib/hecks/router/{door.rb → aggregate_reader.rb} +5 -4
- data/lib/hecks/router/namespace_installer.rb +16 -16
- data/lib/hecks/router.rb +1 -1
- data/lib/hecks/runtime/best_effort.rb +22 -0
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +12 -2
- data/lib/hecks/runtime/command_interpreter.rb +3 -2
- data/lib/hecks/runtime/command_rules/emission.rb +1 -1
- data/lib/hecks/runtime/dispatcher.rb +4 -4
- data/lib/hecks/runtime/entity_element/location.rb +1 -1
- data/lib/hecks/runtime/event.rb +5 -0
- data/lib/hecks/runtime/identity.rb +7 -6
- data/lib/hecks/runtime/interpreting.rb +2 -1
- data/lib/hecks/runtime/invocation_builder.rb +1 -1
- data/lib/hecks/runtime/loader/boot_steps.rb +8 -5
- data/lib/hecks/runtime/loader.rb +10 -10
- data/lib/hecks/runtime/policy_interpreter/arguments.rb +7 -4
- data/lib/hecks/runtime/policy_interpreter/fan_out.rb +3 -3
- data/lib/hecks/runtime/policy_interpreter.rb +6 -6
- data/lib/hecks/runtime/port_operation_interpreter.rb +1 -1
- data/lib/hecks/runtime/reaction_invocation.rb +1 -1
- data/lib/hecks/runtime/rebuild_sweep.rb +11 -1
- data/lib/hecks/runtime/registry/ask_verification.rb +35 -0
- data/lib/hecks/runtime/registry/hecksagon_rules.rb +10 -0
- data/lib/hecks/runtime/registry/merging.rb +1 -1
- data/lib/hecks/runtime/registry/providers.rb +16 -0
- data/lib/hecks/runtime/registry/read_repository.rb +6 -4
- data/lib/hecks/runtime/registry/verification.rb +4 -1
- data/lib/hecks/runtime/registry/world_defaults.rb +29 -0
- data/lib/hecks/runtime/registry.rb +1 -1
- data/lib/hecks/runtime/saga_interpreter/compensation.rb +1 -1
- data/lib/hecks/runtime/saga_interpreter/delivery.rb +4 -4
- data/lib/hecks/runtime/saga_interpreter/transitions.rb +1 -1
- data/lib/hecks/runtime/saga_interpreter.rb +3 -3
- data/lib/hecks/runtime/tenant_check.rb +5 -4
- data/lib/hecks/runtime/value/coercion.rb +2 -2
- data/lib/hecks/runtime/value/validation.rb +16 -4
- data/lib/hecks/runtime.rb +9 -9
- data/lib/hecks/rust_build/project_rust/target_ir.rb +1 -1
- data/lib/hecks/rust_build/wasm.rb +1 -1
- data/lib/hecks/rust_build/wasm_browser.rb +1 -1
- data/lib/hecks/rust_build.rb +11 -0
- data/lib/hecks/served_options.rb +53 -0
- data/lib/hecks/site/bluebook/site.bluebook +29 -1
- data/lib/hecks/site/bluebook/site.ports.hecksagon +6 -0
- data/lib/hecks/storehouse/audit.rb +1 -1
- data/lib/hecks/storehouse/dispatching.rb +8 -6
- data/lib/hecks/storehouse/introspection.rb +2 -2
- data/lib/hecks/storehouse/querying.rb +6 -4
- data/lib/hecks/storehouse.rb +4 -4
- data/lib/hecks/tools/comment_style/source_file.rb +4 -1
- data/lib/hecks/tools/deploy_recipe_lint/fixtures.rb +4 -1
- data/lib/hecks/tools/lanes/rows.rb +6 -0
- data/lib/hecks/tools/oidc_manifests.rb +4 -5
- data/lib/hecks/tools/regeneration_run.rb +11 -4
- data/lib/hecks/tools/site_routes/cli.rb +1 -1
- data/lib/hecks/tools/site_routes/editor_files.rb +45 -0
- data/lib/hecks/tools/site_routes.rb +14 -7
- data/lib/hecks/tools/tenant_provisioning.rb +2 -2
- data/lib/hecks/tools/tools_doc.rb +4 -4
- data/lib/hecks/version.rb +1 -1
- data/lib/hecks/vocabulary.rb +4 -4
- data/lib/hecks.rb +15 -15
- data/lib/rubocop/cop/hecks/env_dump.rb +69 -0
- data/lib/rubocop/cop/hecks/monotonic_duration.rb +53 -0
- data/lib/rubocop/cop/hecks/no_wall_clock_in_runtime.rb +34 -0
- data/lib/rubocop/cop/hecks/raw_shell_interpolation.rb +79 -0
- data/lib/rubocop/cop/hecks/sleep_in_spec.rb +34 -0
- data/lib/rubocop/cop/hecks/swallowed_rescue.rb +37 -0
- data/lib/rubocop/cop/hecks/symbol_string_key_mix.rb +50 -0
- data/lib/rubocop/cop/hecks/untyped_raise.rb +37 -0
- data/prebuilt/05c358d38d661a3774f813d49c66f5b68939af94432d66257a56f49ee2598994.marshal +0 -0
- data/prebuilt/26c40c61f09b09b11651c64668eda3ceb180f83cf2a3802d3033d2fd99ac841b.marshal +0 -0
- data/prebuilt/verdicts-230ac18c25abfd3d92ede032bee2661a4c2cd2773ab0cf0e2ae52546ba2f7af9.json +1 -0
- data/rust/.gitignore +6 -0
- data/rust/Cargo.toml +9 -1
- data/rust/build/src/binding_pass.rs +103 -0
- data/rust/build/src/cargo_sync.rs +6 -0
- data/rust/build/src/lineage_pass.rs +3 -3
- data/rust/build/src/main.rs +17 -5
- data/rust/build/src/pipeline.rs +48 -5
- data/rust/build/src/seams_pass.rs +123 -0
- data/rust/build/src/translation_pass.rs +167 -0
- data/rust/codegen/src/asks.rs +103 -0
- data/rust/codegen/src/bridging.rs +1 -1
- data/rust/codegen/src/commands.rs +13 -8
- data/rust/codegen/src/constraints.rs +25 -0
- data/rust/codegen/src/domain_generator.rs +11 -9
- data/rust/codegen/src/expr_emitter.rs +13 -0
- data/rust/codegen/src/json_codec.rs +54 -15
- data/rust/codegen/src/main.rs +2 -1
- data/rust/codegen/src/mutations.rs +174 -4
- data/rust/codegen/src/naming.rs +30 -0
- data/rust/codegen/src/queries.rs +11 -2
- data/rust/codegen/src/reactions.rs +1 -1
- data/rust/codegen/src/types.rs +166 -8
- data/rust/host/HECKS_RELEASE +1 -1
- data/rust/host/src/api.rs +4 -4
- data/rust/host/src/bin/validate_harness.rs +43 -0
- data/rust/host/src/boundary_fuzz/expr_json.rs +2 -2
- data/rust/host/src/boundary_fuzz/ir.rs +1 -0
- data/rust/host/src/boundary_fuzz/server.rs +1 -1
- data/rust/host/src/checkout.rs +35 -19
- data/rust/host/src/commerce_ir.rs +408 -2
- data/rust/host/src/expr_json.rs +118 -0
- data/rust/host/src/mint.rs +1 -1
- data/rust/host/src/payments/tests.rs +27 -1
- data/rust/host/src/payments.rs +12 -4
- data/rust/host/src/query_step.rs +22 -4
- data/rust/host/src/reference_validate.rs +653 -108
- data/rust/host/src/resend.rs +2 -0
- data/rust/host/src/server.rs +19 -6
- data/rust/host/src/ui_schema.rs +132 -5
- data/rust/host/src/web/newsletter.rs +7 -8
- data/rust/host/src/web/newsletter_send.rs +38 -13
- data/rust/host/src/web/registrations.rs +229 -26
- data/rust/host/src/web.rs +3 -3
- data/rust/parser/src/emit.rs +38 -6
- data/rust/parser/src/expr/ast_json.rs +7 -1
- data/rust/parser/src/expr/resolver.rs +171 -6
- data/rust/parser/src/ir.rs +7 -0
- data/rust/parser/src/keywords.rs +24 -0
- data/rust/parser/src/main.rs +3 -0
- data/rust/parser/src/parse/aggregate.rs +2 -1
- data/rust/parser/src/parse/chapter.rs +2 -2
- data/rust/parser/src/parse/command.rs +2 -0
- data/rust/parser/src/parse/hecksagon.rs +5 -2
- data/rust/parser/src/parse/lifecycle.rs +81 -0
- data/rust/parser/src/parse/mod.rs +15 -1
- data/rust/parser/src/parse/policy.rs +13 -2
- data/rust/parser/src/parse/value_object.rs +13 -8
- data/rust/parser/src/ruby_value.rs +1 -1
- data/rust/src/exemplar/commands.rs +4 -4
- data/rust/src/exemplar/constraints.rs +1 -1
- data/rust/src/exemplar/json.rs +43 -1
- data/rust/src/kernel/cli.rs +7 -5
- data/rust/src/kernel/dispatch.rs +2 -2
- data/rust/src/kernel/dispatch_guard_tests.rs +1 -1
- data/rust/src/kernel/expr.rs +73 -4
- data/rust/src/kernel/expression_operators/arithmetic.rs +130 -5
- data/rust/src/kernel/expression_operators/presence.rs +41 -3
- data/rust/src/kernel/expression_operators/text.rs +26 -2
- data/rust/src/kernel/json.rs +15 -0
- data/rust/src/kernel/mod.rs +1 -1
- data/rust/src/kernel/orchestrate.rs +54 -5
- data/rust/src/kernel/orchestrate_guard_tests.rs +67 -0
- data/rust/src/kernel/pattern.rs +60 -0
- data/rust/src/kernel/reference_lookup.rs +90 -7
- metadata +174 -36
- data/lib/hecks/doors/cli_door/nesting.rb +0 -34
- data/lib/hecks/doors/cli_door/shorthand.rb +0 -85
- data/lib/hecks/doors/cli_door.rb +0 -124
- data/lib/hecks/doors/cli_runner/answers.rb +0 -138
- data/lib/hecks/doors/cli_runner/resolution.rb +0 -146
- data/lib/hecks/doors/cli_runner/settling.rb +0 -115
- data/lib/hecks/doors/cli_runner/streaming.rb +0 -90
- data/lib/hecks/doors/cli_runner/suggestions.rb +0 -43
- data/lib/hecks/doors/cli_runner.rb +0 -66
- data/lib/hecks/doors/command_request.rb +0 -119
- data/lib/hecks/doors/handle.rb +0 -208
- data/lib/hecks/doors/json_door.rb +0 -132
- data/lib/hecks/doors/launcher_options.rb +0 -247
- data/lib/hecks/doors/mcp_door/properties.rb +0 -47
- data/lib/hecks/doors/mcp_door/tool_calls.rb +0 -113
- data/lib/hecks/doors/mcp_door/tool_definitions/auditing.rb +0 -51
- data/lib/hecks/doors/mcp_door/tool_definitions/calling.rb +0 -69
- data/lib/hecks/doors/mcp_door/tool_definitions/reading.rb +0 -97
- data/lib/hecks/doors/mcp_door/tool_definitions.rb +0 -15
- data/lib/hecks/doors/mcp_door.rb +0 -156
- data/lib/hecks/doors/mcp_door_scope/argument_policy.rb +0 -92
- data/lib/hecks/doors/mcp_door_scope/env_problems.rb +0 -55
- data/lib/hecks/doors/mcp_door_scope/presenter.rb +0 -78
- data/lib/hecks/doors/mcp_door_scope.rb +0 -201
- data/lib/hecks/doors/mcp_guide_cache.rb +0 -75
- data/lib/hecks/doors/ruby_door/aggregate_door.rb +0 -162
- data/lib/hecks/doors/ruby_door/chapter.rb +0 -89
- data/lib/hecks/doors/ruby_door.rb +0 -80
- data/lib/hecks/doors/usage_cache.rb +0 -139
- data/prebuilt/0ee7f83cba59ce7d1c45c65ba166b071779f70143449f584f33ff7989f64eccb.marshal +0 -0
- data/prebuilt/6e4a6bcf0aa880e2e6b056e1846b70e5a768090b9dc998bbadeaf5d6bcfd3db8.marshal +0 -0
- data/prebuilt/verdicts-91aaf93ce8981bd9a754948f075d95650dc2ec6435015376f5c60992b36a24b1.json +0 -1
|
@@ -46,8 +46,8 @@ module Hecks
|
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
def apply_set(instance, aggregate, mutation, args, pre)
|
|
49
|
-
from_state = mutation.source.is_a?(StateRef)
|
|
50
|
-
value =
|
|
49
|
+
from_state = mutation.source.is_a?(StateRef) || mutation.source.is_a?(Computed)
|
|
50
|
+
value = set_source_value(mutation.source, args, pre)
|
|
51
51
|
# A plain `sets` of a list takes the whole list; only `append:` and `remove:` take
|
|
52
52
|
# one element.
|
|
53
53
|
list_attribute = aggregate.attribute(mutation.target)
|
|
@@ -55,6 +55,16 @@ module Hecks
|
|
|
55
55
|
instance[mutation.target] = Value.for(aggregate, mutation.target, value)
|
|
56
56
|
end
|
|
57
57
|
|
|
58
|
+
# A `state(:field)` reads the pre-dispatch record; an expression is evaluated over the
|
|
59
|
+
# command's arguments, then that record; anything else resolves as an argument or literal.
|
|
60
|
+
def set_source_value(source, args, pre)
|
|
61
|
+
case source
|
|
62
|
+
when StateRef then pre[source.name]
|
|
63
|
+
when Computed then Bluebook::Expression::Resolver.resolve(source.text, pre, args)
|
|
64
|
+
else @rules.resolve_source(source, args)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
58
68
|
def apply_append(instance, aggregate, mutation, args, pre)
|
|
59
69
|
instance[mutation.target] = appended(pre, aggregate, mutation, args)
|
|
60
70
|
end
|
|
@@ -65,7 +65,7 @@ module Hecks
|
|
|
65
65
|
# @return [Array] the settled instance, events, plan, persistence outcome, and outbox rows
|
|
66
66
|
# @raise [StandardError] a domain refusal (Runtime::DOMAIN_REFUSALS) when a rule refuses
|
|
67
67
|
# @raise [Runtime::StaleWrite, Runtime::WiringError] every retry loses, or resolve fails
|
|
68
|
-
# rubocop:disable-next Metrics/ParameterLists -- the public dispatch signature every
|
|
68
|
+
# rubocop:disable-next Metrics/ParameterLists -- the public dispatch signature every entry point calls
|
|
69
69
|
def call(domain, aggregate, command, invocation, correlation = nil, dry_run: false)
|
|
70
70
|
args = invocation.to_args
|
|
71
71
|
settings = { invocation: invocation, route: invocation.target, correlation: correlation, dry_run: dry_run }
|
|
@@ -181,7 +181,8 @@ module Hecks
|
|
|
181
181
|
|
|
182
182
|
# `ctx.pending_delegation` is only ever set by `step_delegate_to_entity`, and only when this
|
|
183
183
|
# command carries a `:delegate` mutation. The same dispatch, so the same correlation —
|
|
184
|
-
# without threading `ctx.correlation` through, a saga-driven
|
|
184
|
+
# without threading `ctx.correlation` through, a saga-driven entry point's events would lose
|
|
185
|
+
# their
|
|
185
186
|
# stamp here.
|
|
186
187
|
def emit_events(ctx)
|
|
187
188
|
command, args = ctx.pending_delegation || [ctx.command, ctx.args]
|
|
@@ -20,7 +20,7 @@ module Hecks
|
|
|
20
20
|
stamp = { aggregate: "#{domain}::#{aggregate.hecks_name}", id: instance.id,
|
|
21
21
|
payload: args, correlation: correlation }
|
|
22
22
|
command.emits.map do |event_name|
|
|
23
|
-
record_emitted(Event.new(name: event_name, occurred_at:
|
|
23
|
+
record_emitted(Event.new(name: event_name, occurred_at: Event.stamp, **stamp), repository)
|
|
24
24
|
end
|
|
25
25
|
end
|
|
26
26
|
|
|
@@ -37,8 +37,8 @@ module Hecks
|
|
|
37
37
|
@entities = EntityInterpreter.new(registry, rules: rules)
|
|
38
38
|
@queries = QueryInterpreter.new(registry)
|
|
39
39
|
@read_models = ReadModelInterpreter.new(registry)
|
|
40
|
-
@policies = PolicyInterpreter.new(registry,
|
|
41
|
-
@sagas = SagaInterpreter.new(registry,
|
|
40
|
+
@policies = PolicyInterpreter.new(registry, dispatcher: self)
|
|
41
|
+
@sagas = SagaInterpreter.new(registry, dispatcher: self)
|
|
42
42
|
# One relay per registry: interpreters enqueue through it inside the save transaction.
|
|
43
43
|
@registry.outbox.attach(policies: @policies, sagas: @sagas)
|
|
44
44
|
end
|
|
@@ -141,7 +141,7 @@ module Hecks
|
|
|
141
141
|
|
|
142
142
|
# Runs one port operation named by its parts, then the reactions its events owe.
|
|
143
143
|
#
|
|
144
|
-
# The
|
|
144
|
+
# The dispatcher for an adapter outside the bluebook; no wire spelling packs a port verb.
|
|
145
145
|
#
|
|
146
146
|
# @param to [String, Hash, nil] the receiver; when nil it is read from the facts
|
|
147
147
|
# @param with [Hash, nil] the operation's facts, keyed by argument name
|
|
@@ -150,7 +150,7 @@ module Hecks
|
|
|
150
150
|
# @raise [Runtime::UnknownVerb] if the domain, aggregate, port or operation is undeclared
|
|
151
151
|
# @raise [Runtime::TypeMismatch] if no receiving identity is found, or `to:`/`with:` is bad
|
|
152
152
|
# @raise [Runtime::NotFound] if the receiving record does not exist
|
|
153
|
-
# rubocop:disable-next Metrics/ParameterLists -- the public
|
|
153
|
+
# rubocop:disable-next Metrics/ParameterLists -- the public dispatcher's parts, one argument per verb segment
|
|
154
154
|
def dispatch_port(domain, aggregate_name, port_name, operation_name, to: nil, with: nil, flat: {})
|
|
155
155
|
verb = "#{domain}::#{aggregate_name}.#{port_name}.#{operation_name}"
|
|
156
156
|
aggregate = resolve_aggregate(domain, aggregate_name, verb)
|
|
@@ -17,7 +17,7 @@ module Hecks
|
|
|
17
17
|
# Walks `chain` one hop at a time and returns the located element (or `instance`
|
|
18
18
|
# itself when `chain` is empty). `route`, when given, offers each hop's identity
|
|
19
19
|
# before falling back to `args`.
|
|
20
|
-
# rubocop:disable-next Metrics/ParameterLists -- the positional
|
|
20
|
+
# rubocop:disable-next Metrics/ParameterLists -- the positional entry point EntityInterpreter and delegation call
|
|
21
21
|
def locate_chain(root_aggregate, chain, instance, args, command_name, route = nil)
|
|
22
22
|
container = instance
|
|
23
23
|
owner = root_aggregate
|
data/lib/hecks/runtime/event.rb
CHANGED
|
@@ -5,6 +5,11 @@ module Hecks
|
|
|
5
5
|
# An emitted domain event. `correlation` (saga head -> value) is runtime bookkeeping
|
|
6
6
|
# and deliberately absent from `to_h`.
|
|
7
7
|
Event = Struct.new(:name, :aggregate, :id, :payload, :occurred_at, :correlation, keyword_init: true) do
|
|
8
|
+
# The one place the runtime reads the wall clock, so every event is stamped the same way.
|
|
9
|
+
#
|
|
10
|
+
# @return [String] the current UTC time as ISO 8601
|
|
11
|
+
def self.stamp = Time.now.utc.iso8601
|
|
12
|
+
|
|
8
13
|
# Freezes the event deep, payload and correlation included.
|
|
9
14
|
#
|
|
10
15
|
# @return [void]
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require_relative "../naming"
|
|
2
|
+
require_relative "best_effort"
|
|
2
3
|
require_relative "value"
|
|
3
4
|
|
|
4
5
|
module Hecks
|
|
@@ -82,12 +83,12 @@ module Hecks
|
|
|
82
83
|
# Resolves a best-effort identity for `construct` to use as a lock key; never raises.
|
|
83
84
|
# Returns nil when nothing resolves, and the caller then locks by aggregate type alone.
|
|
84
85
|
def best_effort(construct, args, route = nil, reference_key: nil)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
86
|
+
BestEffort.call(nil) do
|
|
87
|
+
route&.aggregate ||
|
|
88
|
+
of(construct, args) ||
|
|
89
|
+
from(construct, args, :id) ||
|
|
90
|
+
(reference_key && from(construct, args, reference_key))
|
|
91
|
+
end
|
|
91
92
|
end
|
|
92
93
|
end
|
|
93
94
|
end
|
|
@@ -32,7 +32,8 @@ module Hecks
|
|
|
32
32
|
|
|
33
33
|
# Gives each argument the caller left out the default its attribute declares
|
|
34
34
|
# (`attribute :runs, Count, default: 30`), so a declared default holds on every way in and
|
|
35
|
-
# not only where
|
|
35
|
+
# not only where an entry point spells it out. An argument the caller passed is kept, whatever
|
|
36
|
+
# it is.
|
|
36
37
|
#
|
|
37
38
|
# @param command [Class] the command being dispatched
|
|
38
39
|
# @param args [Hash{Symbol => Object}] the arguments the caller passed
|
|
@@ -18,7 +18,7 @@ module Hecks
|
|
|
18
18
|
# :entity, :port). Each checks its own parts in a fixed order, because
|
|
19
19
|
# a malformed call's refusal depends on that order; `declaring` is
|
|
20
20
|
# called exactly once, at that shape's point in the order below.
|
|
21
|
-
# rubocop:disable-next Metrics/ParameterLists -- the public keyword
|
|
21
|
+
# rubocop:disable-next Metrics/ParameterLists -- the public keyword entry point every dispatch calls
|
|
22
22
|
def from_call(verb, to:, with:, flat:, receiver: :aggregate, entity_depth: 0, aggregate: nil, &declaring)
|
|
23
23
|
call = Call.new(verb, to, with, flat, entity_depth, aggregate, declaring)
|
|
24
24
|
case receiver
|
|
@@ -15,20 +15,23 @@ module Hecks
|
|
|
15
15
|
# the domain never attached Privacy at all.
|
|
16
16
|
def seed_privacy_markings!(dispatcher, registry)
|
|
17
17
|
return if registry.pending_privacy_markings.empty?
|
|
18
|
-
return unless registry.bluebook("Privacy")
|
|
19
18
|
|
|
20
|
-
|
|
19
|
+
provider = registry.provider_of(Bluebook::Capabilities::PRIVACY)
|
|
20
|
+
return unless provider
|
|
21
|
+
|
|
22
|
+
already_marked = already_marked_by_domain(dispatcher, registry, provider)
|
|
21
23
|
registry.pending_privacy_markings.each do |marking|
|
|
22
24
|
next if already_marked[marking[:domain]].include?(marking[:attribute_path])
|
|
23
25
|
|
|
24
|
-
dispatcher.dispatch_flat(
|
|
26
|
+
dispatcher.dispatch_flat(provider.provided_verb(Bluebook::Capabilities::PRIVACY, :mark_sensitive), marking)
|
|
25
27
|
end
|
|
26
28
|
end
|
|
27
29
|
|
|
28
30
|
# Each domain with a pending marking, with the attribute paths Privacy already marks for it.
|
|
29
|
-
def already_marked_by_domain(dispatcher, registry)
|
|
31
|
+
def already_marked_by_domain(dispatcher, registry, provider)
|
|
32
|
+
verb = provider.provided_verb(Bluebook::Capabilities::PRIVACY, :markings_for)
|
|
30
33
|
registry.pending_privacy_markings.map { |marking| marking[:domain] }.uniq.to_h do |domain|
|
|
31
|
-
[domain, dispatcher.query(
|
|
34
|
+
[domain, dispatcher.query(verb, domain: domain).map { |row| row[:attribute_path][:value] }]
|
|
32
35
|
end
|
|
33
36
|
end
|
|
34
37
|
|
data/lib/hecks/runtime/loader.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require_relative "../
|
|
1
|
+
require_relative "../adapters/driving/ruby"
|
|
2
2
|
require_relative "../ports/loading"
|
|
3
3
|
require_relative "../ports/persistence"
|
|
4
4
|
require_relative "dispatcher"
|
|
@@ -21,7 +21,7 @@ module Hecks
|
|
|
21
21
|
|
|
22
22
|
# Boots `path`: loads its bluebook directory into a fresh Registry, runs
|
|
23
23
|
# every registered boot gate, and returns the bound dispatcher. Pass
|
|
24
|
-
# `
|
|
24
|
+
# `install_driving: false` to skip the `Widget::Item.Add(...)` global
|
|
25
25
|
# facade sugar (only a caller dispatching by FQN string needs to).
|
|
26
26
|
#
|
|
27
27
|
# @param path [String] a domain directory to boot
|
|
@@ -31,25 +31,25 @@ module Hecks
|
|
|
31
31
|
# @return [Runtime::Dispatcher, Runtime::RemoteDispatcher] the booted dispatcher
|
|
32
32
|
# @raise [Errno::ENOENT] if `path` names no domain directory
|
|
33
33
|
# @raise [Runtime::WiringError] if a boot gate finds a wiring problem
|
|
34
|
-
def self.boot(path, shared: nil,
|
|
34
|
+
def self.boot(path, shared: nil, install_driving: true, environment: FROM_ENV)
|
|
35
35
|
described = describe(path, shared: shared, environment: environment)
|
|
36
|
-
boot_described(described,
|
|
36
|
+
boot_described(described, install_driving: install_driving)
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
# Finishes a boot from declarations `describe` already loaded: runs every boot gate and binds
|
|
40
40
|
# the dispatcher, without reading the domain's files again.
|
|
41
41
|
#
|
|
42
42
|
# @param described [Described] what `describe` answered for the domain to boot
|
|
43
|
-
# @param
|
|
43
|
+
# @param install_driving [Boolean] install the `Widget::Item.Add(...)` global facade sugar
|
|
44
44
|
# @return [Runtime::Dispatcher, Runtime::RemoteDispatcher] the booted dispatcher
|
|
45
45
|
# @raise [Runtime::WiringError] if a boot gate finds a wiring problem
|
|
46
|
-
def self.boot_described(described,
|
|
46
|
+
def self.boot_described(described, install_driving: true)
|
|
47
47
|
registry = described.registry
|
|
48
48
|
run_boot_gates!(registry, described.directory)
|
|
49
49
|
dispatcher = dispatcher_for(registry)
|
|
50
50
|
redrive_outbox!(dispatcher)
|
|
51
51
|
seed_privacy_markings!(dispatcher, registry)
|
|
52
|
-
|
|
52
|
+
install_driving ? bind_runtime(dispatcher) : dispatcher
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
# Loads `path`'s declarations into a fresh Registry and stops: no boot gate runs, no
|
|
@@ -118,7 +118,7 @@ module Hecks
|
|
|
118
118
|
# defaults to `HECKS_ENVIRONMENT`, and an explicit nil loads none
|
|
119
119
|
# @return [Runtime::Dispatcher, Runtime::RemoteDispatcher] the booted dispatcher
|
|
120
120
|
# @raise [Runtime::WiringError] if a boot gate finds a wiring problem
|
|
121
|
-
def self.boot_files(paths, shared: nil,
|
|
121
|
+
def self.boot_files(paths, shared: nil, install_driving: true, environment: FROM_ENV)
|
|
122
122
|
loading = Ports::Loading.bootstrap
|
|
123
123
|
files = Array(paths).map { |path| File.expand_path(path) }
|
|
124
124
|
directory = File.dirname(files.first)
|
|
@@ -126,7 +126,7 @@ module Hecks
|
|
|
126
126
|
|
|
127
127
|
run_boot_gates!(registry, directory)
|
|
128
128
|
dispatcher = dispatcher_for(registry)
|
|
129
|
-
|
|
129
|
+
install_driving ? bind_runtime(dispatcher) : dispatcher
|
|
130
130
|
end
|
|
131
131
|
|
|
132
132
|
# Loads exactly `files` into a fresh Registry rooted beside their directory, answering it.
|
|
@@ -160,7 +160,7 @@ module Hecks
|
|
|
160
160
|
# `dispatcher`. The binding lives in the facade's own modules, not a
|
|
161
161
|
# class-level global, so two boots in one process don't share one name.
|
|
162
162
|
def self.bind_runtime(dispatcher)
|
|
163
|
-
|
|
163
|
+
Adapters::Driving::Ruby.install(dispatcher)
|
|
164
164
|
dispatcher
|
|
165
165
|
end
|
|
166
166
|
end
|
|
@@ -4,7 +4,7 @@ module Hecks
|
|
|
4
4
|
module Runtime
|
|
5
5
|
class PolicyInterpreter
|
|
6
6
|
# What a policy's trigger is given: the event payload or its `with:` projection, the
|
|
7
|
-
# emitting record's identity, and the invocation the
|
|
7
|
+
# emitting record's identity, and the invocation the entry point re-enters with. Mixed into
|
|
8
8
|
# {PolicyInterpreter}.
|
|
9
9
|
module Arguments
|
|
10
10
|
private
|
|
@@ -12,12 +12,15 @@ module Hecks
|
|
|
12
12
|
# What the trigger is given: the whole event payload verbatim when no `with:` is
|
|
13
13
|
# declared, otherwise the projection (a Symbol names a payload field, anything else
|
|
14
14
|
# is a literal). `extra` is a fan-out's row key, merged into the source before the
|
|
15
|
-
# projection so a `with:` can name the row it acts on.
|
|
16
|
-
|
|
15
|
+
# projection so a `with:` can name the row it acts on. `row` is the fan-out row itself:
|
|
16
|
+
# its fields are offered to a projection only, below the emitter identity and the
|
|
17
|
+
# payload, and never reach an unprojected payload.
|
|
18
|
+
def trigger_args(policy, event, extra = {}, row = {})
|
|
17
19
|
payload = event.payload.transform_keys(&:to_sym).merge(extra)
|
|
18
20
|
return payload unless ReactionInvocation.projection_declared?(policy)
|
|
19
21
|
|
|
20
|
-
|
|
22
|
+
source = row.transform_keys(&:to_sym).merge(emitter_identity(event)).merge(payload)
|
|
23
|
+
projected_args(policy, event, source)
|
|
21
24
|
end
|
|
22
25
|
|
|
23
26
|
def projected_args(policy, event, payload)
|
|
@@ -20,7 +20,7 @@ module Hecks
|
|
|
20
20
|
|
|
21
21
|
rows, reference_key = for_each_rows(policy, event, domain, target)
|
|
22
22
|
Array(rows).map do |row|
|
|
23
|
-
args = trigger_args(policy, event, reference_key => row[:id])
|
|
23
|
+
args = trigger_args(policy, event, { reference_key => row[:id] }, row)
|
|
24
24
|
deliver_for_each_row(target, record.merge(for_row: row[:id]), args, policy, event)
|
|
25
25
|
end
|
|
26
26
|
rescue *DOMAIN_REFUSALS => e
|
|
@@ -74,10 +74,10 @@ module Hecks
|
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
def deliver_for_each_row(target, row_record, args, policy, event)
|
|
77
|
-
return depth_refusal(row_record) if @
|
|
77
|
+
return depth_refusal(row_record) if @dispatcher.reaction_depth_reached?
|
|
78
78
|
|
|
79
79
|
# The row key is already merged by `trigger_args`, so a projection can name it.
|
|
80
|
-
@
|
|
80
|
+
@dispatcher.reenter(target, **reaction_invocation(target, args, policy, event))
|
|
81
81
|
row_record.merge(delivered: true)
|
|
82
82
|
rescue *DOMAIN_REFUSALS => e
|
|
83
83
|
row_record.merge(delivered: false, reason: e.message)
|
|
@@ -20,11 +20,11 @@ module Hecks
|
|
|
20
20
|
|
|
21
21
|
# @param registry [Runtime::Registry] the booted registry whose loaded
|
|
22
22
|
# bluebooks are scanned for candidate policies
|
|
23
|
-
# @param
|
|
23
|
+
# @param dispatcher [Runtime::Dispatcher] the dispatcher reactions re-enter through,
|
|
24
24
|
# and whose reaction-depth guard is checked before each delivery
|
|
25
|
-
def initialize(registry,
|
|
25
|
+
def initialize(registry, dispatcher:)
|
|
26
26
|
@registry = registry
|
|
27
|
-
@
|
|
27
|
+
@dispatcher = dispatcher
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
# Fires every declared policy `event` triggers, recording each outcome on
|
|
@@ -96,15 +96,15 @@ module Hecks
|
|
|
96
96
|
# may go.
|
|
97
97
|
def fire(policy, event, target, record)
|
|
98
98
|
return nil unless where_holds?(policy, event)
|
|
99
|
-
return depth_refusal(record) if @
|
|
99
|
+
return depth_refusal(record) if @dispatcher.reaction_depth_reached?
|
|
100
100
|
|
|
101
101
|
args = trigger_args(policy, event)
|
|
102
|
-
@
|
|
102
|
+
@dispatcher.reenter(target, **reaction_invocation(target, args, policy, event))
|
|
103
103
|
record.merge(delivered: true)
|
|
104
104
|
end
|
|
105
105
|
|
|
106
106
|
def depth_refusal(record)
|
|
107
|
-
record.merge(delivered: false, reason: "reaction depth #{@
|
|
107
|
+
record.merge(delivered: false, reason: "reaction depth #{@dispatcher.max_reaction_depth} reached")
|
|
108
108
|
end
|
|
109
109
|
|
|
110
110
|
# A defect, not a refusal: recorded with `defect: true` and warned, never
|
|
@@ -90,7 +90,7 @@ module Hecks
|
|
|
90
90
|
# @raise [Runtime::UnknownVerb] if `verb` does not resolve (only when `explicit`)
|
|
91
91
|
# @raise [Runtime::TypeMismatch] if no receiver identity resolves for an explicit target
|
|
92
92
|
# @raise [Runtime::UnknownArgument] if an explicit projection has an undeclared fact
|
|
93
|
-
# rubocop:disable-next Metrics/ParameterLists -- the keyword
|
|
93
|
+
# rubocop:disable-next Metrics/ParameterLists -- the keyword entry point both interpreters call
|
|
94
94
|
def build(registry:, verb:, projected:, explicit:, passthrough: [], source_receiver: nil)
|
|
95
95
|
args = projected.transform_keys(&:to_sym)
|
|
96
96
|
return forwarded(registry, verb, args, source_receiver) unless explicit
|
|
@@ -49,7 +49,17 @@ module Hecks
|
|
|
49
49
|
return nil if id.nil?
|
|
50
50
|
|
|
51
51
|
remote = registry.repository(domain, target).find(id.to_s)
|
|
52
|
-
remote&.[](field.remote_field)
|
|
52
|
+
unwrap_single_field(target, field, remote&.[](field.remote_field))
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# A remote field typed by a single-field value object is copied as its one scalar, so the
|
|
56
|
+
# projecting aggregate holds `123`, never `{ value: 123 }`. Any other value is copied as is.
|
|
57
|
+
def unwrap_single_field(target, field, value)
|
|
58
|
+
attribute = target.attribute(field.remote_field)
|
|
59
|
+
sole = attribute && target.value_object(attribute.type)&.sole_attribute
|
|
60
|
+
return value unless sole && !value.nil?
|
|
61
|
+
|
|
62
|
+
value.is_a?(Hash) ? value.fetch(sole.name) { value[sole.name.to_s] } : value[sole.name]
|
|
53
63
|
end
|
|
54
64
|
end
|
|
55
65
|
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require_relative "../../bluebook/ask_resolution"
|
|
2
|
+
|
|
3
|
+
module Hecks
|
|
4
|
+
module Runtime
|
|
5
|
+
class Registry
|
|
6
|
+
# The boot gate for `ask`: every policy's ask must resolve to one declared port operation,
|
|
7
|
+
# so a name the hecksagon never declared stops the boot instead of firing at nothing.
|
|
8
|
+
# Mixed into {Verification}.
|
|
9
|
+
module AskVerification
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
# A port operation a chapter provides, and an ask a policy makes, each name a port
|
|
13
|
+
# operation the hecksagon declared.
|
|
14
|
+
def refuse_unresolved_ports!
|
|
15
|
+
refuse_unresolved_port_operations!
|
|
16
|
+
refuse_unresolved_asks!
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Binds each ask to the operation it resolves to, refusing the first that resolves to none.
|
|
20
|
+
#
|
|
21
|
+
# @raise [WiringError] naming the policy, the ask and what the hecksagon would need
|
|
22
|
+
def refuse_unresolved_asks!
|
|
23
|
+
@declared.bluebooks.each_value do |chapter|
|
|
24
|
+
chapter.policies.select(&:asks?).each do |policy|
|
|
25
|
+
outcome = Bluebook::AskResolution.call(chapter, policy)
|
|
26
|
+
raise WiringError, outcome.detail unless outcome.resolved?
|
|
27
|
+
|
|
28
|
+
policy.resolve_ask!(outcome.verb)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -27,6 +27,16 @@ module Hecks
|
|
|
27
27
|
"without that it is silent decoration, the exact defect this refusal exists to catch"
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
# `driven_by` names a driving adapter; a name none answers to would silently admit nothing.
|
|
31
|
+
def refuse_unknown_driving!(hecksagon)
|
|
32
|
+
unknown = hecksagon.driving - Bluebook::Hecksagon::DRIVING_ADAPTERS
|
|
33
|
+
return if unknown.empty?
|
|
34
|
+
|
|
35
|
+
raise WiringError,
|
|
36
|
+
"#{hecksagon.domain} is driven_by #{unknown.map(&:inspect).join(", ")}, which no driving " \
|
|
37
|
+
"adapter answers to — the adapters are #{Bluebook::Hecksagon::DRIVING_ADAPTERS.join(", ")}"
|
|
38
|
+
end
|
|
39
|
+
|
|
30
40
|
# `attaches` loads a bounded context; the consumer must declare the sibling hecksagon
|
|
31
41
|
# that is its ACL (Governance/Identity/Privacy already do). A vendored package only
|
|
32
42
|
# loads its `.bluebook` files, so persistence, Governance and the `translates` ACL live
|
|
@@ -17,7 +17,7 @@ module Hecks
|
|
|
17
17
|
def merge_hecksagons(base, overlay)
|
|
18
18
|
# Order-independent: list facts uniq, so loading context_map before or after the
|
|
19
19
|
# domain file yields the same merged hecksagon.
|
|
20
|
-
lists = %i[subscriptions attachments translates].to_h do |facet|
|
|
20
|
+
lists = %i[subscriptions attachments translates driving].to_h do |facet|
|
|
21
21
|
[facet, (base.public_send(facet) + overlay.public_send(facet)).uniq]
|
|
22
22
|
end
|
|
23
23
|
Bluebook::Hecksagon.new(domain: base.domain, binds: base.binds + overlay.binds,
|
|
@@ -101,6 +101,16 @@ module Hecks
|
|
|
101
101
|
vendored_provider_for(domain, Bluebook::Capabilities::PAYMENT_CONNECTION)
|
|
102
102
|
end
|
|
103
103
|
|
|
104
|
+
# The chapter that owns the checkout boundary for `domain` — resolved by what it
|
|
105
|
+
# declares (`provides "checkout"`). Nil when none does.
|
|
106
|
+
#
|
|
107
|
+
# @param domain [String, Symbol] the domain whose checkout chapter is being resolved
|
|
108
|
+
# @return [Bluebook::Chapter, nil] the chapter that owns `domain`'s checkout windows,
|
|
109
|
+
# or nil if none does
|
|
110
|
+
def checkout_provider_for(domain)
|
|
111
|
+
vendored_provider_for(domain, Bluebook::Capabilities::CHECKOUT)
|
|
112
|
+
end
|
|
113
|
+
|
|
104
114
|
# The chapter that takes payments for `domain`: the domain's own chapter, a
|
|
105
115
|
# framework member, or a vendored embryonaut bluebook it attaches, that
|
|
106
116
|
# declares `provides "payments"`.
|
|
@@ -112,6 +122,12 @@ module Hecks
|
|
|
112
122
|
vendored_provider_for(domain, Bluebook::Capabilities::PAYMENTS)
|
|
113
123
|
end
|
|
114
124
|
|
|
125
|
+
# The first loaded chapter that declares `capability`, whichever domain asks.
|
|
126
|
+
#
|
|
127
|
+
# @param capability [String] a `Bluebook::Capabilities` name
|
|
128
|
+
# @return [Bluebook::Chapter, nil] the providing chapter, or nil if none loaded does
|
|
129
|
+
def provider_of(capability) = bluebooks.values.find { |chapter| chapter.provides?(capability) }
|
|
130
|
+
|
|
115
131
|
# The chapter that provides `capability` for `domain`: the domain's own chapter,
|
|
116
132
|
# a framework member its hecksagon attaches, or a vendored embryonaut bluebook
|
|
117
133
|
# it attaches, that declares it.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require_relative "../best_effort"
|
|
2
|
+
|
|
1
3
|
module Hecks
|
|
2
4
|
module Runtime
|
|
3
5
|
class Registry
|
|
@@ -37,10 +39,10 @@ module Hecks
|
|
|
37
39
|
# `authoritative`, in the same order; false on any mismatch, or if comparing
|
|
38
40
|
# them raises
|
|
39
41
|
def projection_current?(projection, authoritative)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
BestEffort.call(false) do
|
|
43
|
+
entries_match?(projection.entries, authoritative.entries) &&
|
|
44
|
+
sorted_rows(projection) == sorted_rows(authoritative)
|
|
45
|
+
end
|
|
44
46
|
end
|
|
45
47
|
|
|
46
48
|
private
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require_relative "../../bluebook/hecksagon"
|
|
2
2
|
require_relative "hecksagon_rules"
|
|
3
|
+
require_relative "ask_verification"
|
|
3
4
|
require_relative "query_verification"
|
|
4
5
|
require_relative "chapter_verification"
|
|
5
6
|
require_relative "durability_warnings"
|
|
@@ -11,6 +12,7 @@ module Hecks
|
|
|
11
12
|
# port's verb, and every world default is usable. `verify!` runs it all at boot.
|
|
12
13
|
module Verification
|
|
13
14
|
include HecksagonRules
|
|
15
|
+
include AskVerification
|
|
14
16
|
include QueryVerification
|
|
15
17
|
include ChapterVerification
|
|
16
18
|
include DurabilityWarnings
|
|
@@ -24,7 +26,7 @@ module Hecks
|
|
|
24
26
|
refuse_cross_package_bluebook_merge!
|
|
25
27
|
refuse_reserved_chapter_names!
|
|
26
28
|
refuse_membership_without_identity!
|
|
27
|
-
|
|
29
|
+
refuse_unresolved_ports!
|
|
28
30
|
refuse_unanswerable_queries!
|
|
29
31
|
|
|
30
32
|
@declared.hecksagons.each_value { |hecksagon| verify_hecksagon!(hecksagon) }
|
|
@@ -126,6 +128,7 @@ module Hecks
|
|
|
126
128
|
# warnings for its chapter.
|
|
127
129
|
def verify_hecksagon!(hecksagon)
|
|
128
130
|
refuse_ungoverned_roles!(hecksagon)
|
|
131
|
+
refuse_unknown_driving!(hecksagon)
|
|
129
132
|
refuse_unwired_attachments!(hecksagon)
|
|
130
133
|
refuse_bounded_without_acl!(hecksagon)
|
|
131
134
|
hecksagon.binds.each { |bind| verify_bind!(hecksagon, bind) }
|
|
@@ -28,8 +28,37 @@ module Hecks
|
|
|
28
28
|
self
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
+
# The defaults an adapter's `.adapter` declares for its fields, with each `{name}` or
|
|
32
|
+
# `{storage_name}` in a string filled from `aggregate`. A world's own setting always wins.
|
|
33
|
+
#
|
|
34
|
+
# @param adapter [String, Symbol] the adapter's name
|
|
35
|
+
# @param aggregate [Bluebook::Aggregate] the aggregate the adapter is built for
|
|
36
|
+
# @return [Hash{Symbol => Object}] the defaults, empty when the adapter declares none
|
|
37
|
+
def adapter_defaults(adapter, aggregate)
|
|
38
|
+
declared = @declared.adapters[adapter.to_s]&.declared_defaults || {}
|
|
39
|
+
declared.transform_values { |value| fill_placeholders(value, aggregate) }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# `settings` laid over the adapter's declared defaults. A field a world gives as `:default`
|
|
43
|
+
# asks for the declared default, so it is left out and the default shows through.
|
|
44
|
+
#
|
|
45
|
+
# @param adapter [String, Symbol] the adapter's name
|
|
46
|
+
# @param aggregate [Bluebook::Aggregate] the aggregate the adapter is built for
|
|
47
|
+
# @param settings [Hash{Symbol => Object}] the settings the world gave
|
|
48
|
+
# @return [Hash{Symbol => Object}] the defaults, overridden by the settings given
|
|
49
|
+
def with_adapter_defaults(adapter, aggregate, settings)
|
|
50
|
+
adapter_defaults(adapter, aggregate).merge(settings.reject { |_, value| value == :default })
|
|
51
|
+
end
|
|
52
|
+
|
|
31
53
|
private
|
|
32
54
|
|
|
55
|
+
# A string default with its placeholders filled from the aggregate; any other value as is.
|
|
56
|
+
def fill_placeholders(value, aggregate)
|
|
57
|
+
return value unless value.is_a?(String)
|
|
58
|
+
|
|
59
|
+
value.gsub(/\{(name|storage_name)\}/) { aggregate.public_send(Regexp.last_match(1)) }
|
|
60
|
+
end
|
|
61
|
+
|
|
33
62
|
# The chapter's own world answers first; the project's world fills the gap.
|
|
34
63
|
def world_default(domain, field)
|
|
35
64
|
world(domain)&.public_send(field) || project_world&.public_send(field)
|
|
@@ -45,7 +45,7 @@ module Hecks
|
|
|
45
45
|
# against; nil for a registry with no such root
|
|
46
46
|
def initialize(root: nil)
|
|
47
47
|
@root = root
|
|
48
|
-
# Recorded at hecksagon-build time (
|
|
48
|
+
# Recorded at hecksagon-build time (AggregateModule#mark_sensitive), Loader.boot's
|
|
49
49
|
# post-dispatch step turns each pending privacy marking into a real Privacy::Marking.Mark,
|
|
50
50
|
# idempotently. `resolved_eras` and `superseded_eras` are eager, not lazy, so no two
|
|
51
51
|
# dispatching threads race to create them; all writes still happen at boot,
|
|
@@ -7,7 +7,7 @@ module Hecks
|
|
|
7
7
|
module Compensation
|
|
8
8
|
private
|
|
9
9
|
|
|
10
|
-
# Recorded before dispatching, not after `@
|
|
10
|
+
# Recorded before dispatching, not after `@dispatcher.reenter` returns —
|
|
11
11
|
# reenter can recursively re-enter this interpreter and refuse
|
|
12
12
|
# before ever returning here, and recording only on success would
|
|
13
13
|
# be too late for that nested refusal to see this leg's own
|
|
@@ -24,7 +24,7 @@ module Hecks
|
|
|
24
24
|
record = { process_manager: process_manager.name, instance: correlation, dispatch: spec.command_name }
|
|
25
25
|
|
|
26
26
|
log_dispatch_inputs(leg, spec, args) unless spec.with_spec.to_a.empty?
|
|
27
|
-
return refuse_at_depth_ceiling(leg, record) if @
|
|
27
|
+
return refuse_at_depth_ceiling(leg, record) if @dispatcher.reaction_depth_reached?
|
|
28
28
|
|
|
29
29
|
attempt_dispatch(leg, spec, args, record)
|
|
30
30
|
end
|
|
@@ -46,7 +46,7 @@ module Hecks
|
|
|
46
46
|
# it unwinds like a refusal rather than stranding the instance.
|
|
47
47
|
def refuse_at_depth_ceiling(leg, record)
|
|
48
48
|
@registry.saga_log << record.merge(delivered: false,
|
|
49
|
-
reason: "reaction depth #{@
|
|
49
|
+
reason: "reaction depth #{@dispatcher.max_reaction_depth} reached")
|
|
50
50
|
unwind(leg)
|
|
51
51
|
end
|
|
52
52
|
|
|
@@ -95,14 +95,14 @@ module Hecks
|
|
|
95
95
|
nil
|
|
96
96
|
end
|
|
97
97
|
|
|
98
|
-
# Dispatches `command_name` through the
|
|
98
|
+
# Dispatches `command_name` through the dispatcher, stamped with this saga's correlation.
|
|
99
99
|
def reenter_command(leg, command_name, projected, explicit:, source_receiver:)
|
|
100
100
|
head = leg.process_manager.correlation_head
|
|
101
101
|
verb = qualified(command_name, leg.domain)
|
|
102
102
|
invocation = ReactionInvocation.build(registry: @registry, verb: verb, projected: projected,
|
|
103
103
|
explicit: explicit, passthrough: [head],
|
|
104
104
|
source_receiver: source_receiver)
|
|
105
|
-
@
|
|
105
|
+
@dispatcher.reenter(verb, saga_correlation: { head.to_s => leg.correlation }, **invocation)
|
|
106
106
|
end
|
|
107
107
|
|
|
108
108
|
# Unlike a refusal, a crash isn't a domain decision, so it
|
|
@@ -21,7 +21,7 @@ module Hecks
|
|
|
21
21
|
|
|
22
22
|
# The mutex covers only the check-mutate-checkpoint step, never the
|
|
23
23
|
# dispatch cascade that follows — `deliver_saga_dispatch`'s
|
|
24
|
-
# `@
|
|
24
|
+
# `@dispatcher.reenter` can recursively re-enter this interpreter on the
|
|
25
25
|
# same thread, and `Mutex` is not reentrant.
|
|
26
26
|
def remembered_leg_taken?(leg)
|
|
27
27
|
leg.instance = @registry.saga_instances[leg.process_manager.name][leg.correlation]
|