hecks 3.10.0 → 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 +18 -2
- 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/statuses.rb +2 -1
- 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/terminal.rb +13 -11
- 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 +53 -18
- data/lib/hecks/hecks/hecks.world +10 -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/preview/preview.sh.erb +1 -1
- data/lib/hecks/projections/deploy/shared.rb +5 -2
- 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 +26 -6
- data/lib/hecks/projections/site/cms_editor/blocks.rb +157 -0
- data/lib/hecks/projections/site/cms_editor/checks.rb +14 -1
- 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 +1 -1
- 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/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 +96 -19
- data/lib/hecks/projections/site/cms_editor/setting.rb +52 -9
- data/lib/hecks/projections/site/cms_editor/targets.rb +86 -0
- data/lib/hecks/projections/site/cms_editor/templates/package.json.tmpl +18 -1
- data/lib/hecks/projections/site/cms_editor/templates/src/app.ts.tmpl +251 -57
- 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 +32 -24
- 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 +78 -24
- data/lib/hecks/projections/site/cms_editor/templates/src/config.ts.tmpl +6 -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 +19 -2
- data/lib/hecks/projections/site/cms_editor/templates/src/media/handler.ts.tmpl +31 -8
- 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 +131 -2
- 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 +8 -5
- 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 +229 -34
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/html.ts.tmpl +40 -81
- 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 +29 -12
- 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 +53 -17
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/pages.ts.tmpl +178 -88
- 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 +2 -1
- 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 +49 -23
- data/lib/hecks/projections/site/role_probe.rb +2 -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 +1 -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/editor_files.rb +12 -5
- 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 +6 -0
- 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/commands.rs +13 -8
- data/rust/codegen/src/constraints.rs +25 -0
- data/rust/codegen/src/domain_generator.rs +2 -0
- data/rust/codegen/src/expr_emitter.rs +13 -0
- data/rust/codegen/src/json_codec.rs +54 -15
- data/rust/codegen/src/main.rs +1 -0
- data/rust/codegen/src/mutations.rs +128 -3
- 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 +66 -3
- data/rust/src/kernel/expression_operators/arithmetic.rs +130 -5
- 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 +140 -38
- 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/lib/hecks/projections/site/cms_editor/templates/src/ui/body_widget.js.tmpl +0 -282
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/media_picker.js.tmpl +0 -109
- data/prebuilt/c28d6d9db14eea3e17161e9d9c262efee30b256cf97693a7cfd552bce24b2f7f.marshal +0 -0
- data/prebuilt/cb375cba61ca0dbe8ddb9739c306510fe05e5f4b7a9b6955caff8224c63ea0e0.marshal +0 -0
- data/prebuilt/verdicts-d6d584ad43b5f3cebf88aafbbdbf024c38574acf18e06adffbc555f7786b1c2f.json +0 -1
|
@@ -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]
|
|
@@ -55,11 +55,11 @@ module Hecks
|
|
|
55
55
|
|
|
56
56
|
# @param registry [Runtime::Registry] the booted registry whose declared
|
|
57
57
|
# process managers and saga persistence this interpreter runs against
|
|
58
|
-
# @param
|
|
58
|
+
# @param dispatcher [Runtime::Dispatcher] the dispatcher a saga leg's own dispatch
|
|
59
59
|
# re-enters through
|
|
60
|
-
def initialize(registry,
|
|
60
|
+
def initialize(registry, dispatcher:)
|
|
61
61
|
@registry = registry
|
|
62
|
-
@
|
|
62
|
+
@dispatcher = dispatcher
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
# Runs `domain`'s declared process managers against `event`: begins,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require_relative "../ports/persistence/binding_policy"
|
|
2
|
+
require_relative "best_effort"
|
|
2
3
|
|
|
3
4
|
module Hecks
|
|
4
5
|
module Runtime
|
|
@@ -37,10 +38,10 @@ module Hecks
|
|
|
37
38
|
# Same defensive shape as EraCheck#lineage_capable? — a class that
|
|
38
39
|
# doesn't respond at all, or whose lookup raises, is false, not an error.
|
|
39
40
|
def tenant_capable?(registry, adapter_name)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
BestEffort.call(false) do
|
|
42
|
+
adapter_class = registry.adapters[adapter_name] && registry.adapter_class(adapter_name)
|
|
43
|
+
adapter_class.respond_to?(:tenant_capable?) && adapter_class.tenant_capable?
|
|
44
|
+
end
|
|
44
45
|
end
|
|
45
46
|
end
|
|
46
47
|
end
|
|
@@ -37,9 +37,9 @@ module Hecks
|
|
|
37
37
|
# Coerces `value` for a single, already-resolved `attribute`, branching on
|
|
38
38
|
# its declared shape (list, reference, composite, or bare scalar).
|
|
39
39
|
#
|
|
40
|
-
# `boundary: false` is the query
|
|
40
|
+
# `boundary: false` is the query entry point, where a declared type documents the
|
|
41
41
|
# argument for callers/generators rather than naming a shape to enforce.
|
|
42
|
-
# `argument: true` is the command/entity/port dispatch
|
|
42
|
+
# `argument: true` is the command/entity/port dispatch entry point, where a nil for
|
|
43
43
|
# a required attribute is a left-empty argument (C3.7), not ordinary state nil.
|
|
44
44
|
#
|
|
45
45
|
# @raise [Runtime::TypeMismatch] if `value` cannot be coerced, or a required
|
|
@@ -34,7 +34,11 @@ module Hecks
|
|
|
34
34
|
fields
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
-
# Fills every declared attribute `fields` lacks with its own `default
|
|
37
|
+
# Fills every declared attribute `fields` lacks with its own `default:`, and every required
|
|
38
|
+
# list it lacks with an empty one: a list left out reads as no members, the one shape the
|
|
39
|
+
# Rust runtime (a `Vec`) can hold, so a value object built from nothing (a required
|
|
40
|
+
# argument left empty, C3.7) is `{blocks: []}` on both sides rather than `{}` here.
|
|
41
|
+
# An optional list stays absent, and an offered list, empty or not, is kept as offered.
|
|
38
42
|
#
|
|
39
43
|
# @param value_object [Class] the `Bluebook::ValueObject` subclass whose
|
|
40
44
|
# declared defaults are read
|
|
@@ -42,11 +46,11 @@ module Hecks
|
|
|
42
46
|
# @return [Hash{Symbol => Object}] `fields`, with defaults filled in
|
|
43
47
|
def apply_defaults(value_object, fields)
|
|
44
48
|
value_object.attributes.each_with_object(fields) do |attribute, completed|
|
|
45
|
-
completed
|
|
49
|
+
fill_absent(completed, attribute) unless completed.key?(attribute.name)
|
|
46
50
|
end
|
|
47
51
|
end
|
|
48
52
|
|
|
49
|
-
# The full
|
|
53
|
+
# The full entry point a value object's own fields pass through — shared by
|
|
50
54
|
# `build` and `normalize_composite_fields`, so a nested field refuses
|
|
51
55
|
# exactly like the same type declared directly on a command.
|
|
52
56
|
#
|
|
@@ -85,6 +89,13 @@ module Hecks
|
|
|
85
89
|
|
|
86
90
|
private
|
|
87
91
|
|
|
92
|
+
# The default an absent attribute declares, else an empty list for a required list.
|
|
93
|
+
def fill_absent(fields, attribute)
|
|
94
|
+
return fields[attribute.name] = attribute.default unless attribute.default.nil?
|
|
95
|
+
|
|
96
|
+
fields[attribute.name] = [] if attribute.list? && !attribute.optional?
|
|
97
|
+
end
|
|
98
|
+
|
|
88
99
|
def normalize_composite_field(aggregate, attribute, fields)
|
|
89
100
|
# A list member hydrates the same as a top-level list, so a value
|
|
90
101
|
# read back from the store matches the shape a live dispatch wrote.
|
|
@@ -109,7 +120,8 @@ module Hecks
|
|
|
109
120
|
validate_input_list(aggregate, attribute, fields)
|
|
110
121
|
end
|
|
111
122
|
|
|
112
|
-
# Runs each value-object member of an input list through the same
|
|
123
|
+
# Runs each value-object member of an input list through the same entry point a nested
|
|
124
|
+
# single
|
|
113
125
|
# value goes through, so a member's own invariants and nested lists refuse on dispatch
|
|
114
126
|
# exactly as they do when the list sits directly on a command. The members stay as offered.
|
|
115
127
|
def validate_input_list(aggregate, attribute, fields)
|
data/lib/hecks/runtime.rb
CHANGED
|
@@ -42,12 +42,12 @@ module Hecks
|
|
|
42
42
|
#
|
|
43
43
|
# @param path [String] path to a domain directory, or a file inside one
|
|
44
44
|
# @param shared [String, nil] a shared-root override
|
|
45
|
-
# @param
|
|
45
|
+
# @param install_driving [Boolean] whether to install the Ruby facade constants
|
|
46
46
|
# @param environment [String, nil] the environment name for `Adapters::Folder#load_domain`
|
|
47
47
|
# @return [Runtime::Dispatcher, Runtime::RemoteDispatcher] the dispatcher bound
|
|
48
48
|
# to the booted domain
|
|
49
|
-
def boot(path, shared: nil,
|
|
50
|
-
Loader.boot(path, shared: shared,
|
|
49
|
+
def boot(path, shared: nil, install_driving: true, environment: Runtime::Loader::FROM_ENV)
|
|
50
|
+
Loader.boot(path, shared: shared, install_driving: install_driving, environment: environment)
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
# Loads a domain's declarations without binding any adapter. See Loader.describe.
|
|
@@ -63,23 +63,23 @@ module Hecks
|
|
|
63
63
|
# Finishes a boot from declarations `describe` already loaded. See Loader.boot_described.
|
|
64
64
|
#
|
|
65
65
|
# @param described [Runtime::Loader::Described] what `describe` answered
|
|
66
|
-
# @param
|
|
66
|
+
# @param install_driving [Boolean] whether to install the Ruby facade constants
|
|
67
67
|
# @return [Runtime::Dispatcher, Runtime::RemoteDispatcher] the dispatcher bound
|
|
68
68
|
# to the booted domain
|
|
69
|
-
def boot_described(described,
|
|
70
|
-
Loader.boot_described(described,
|
|
69
|
+
def boot_described(described, install_driving: true)
|
|
70
|
+
Loader.boot_described(described, install_driving: install_driving)
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
# Loads only the given files of a domain; otherwise like `boot`. See Loader.boot_files.
|
|
74
74
|
#
|
|
75
75
|
# @param paths [String, Array<String>] one or more file paths within the domain
|
|
76
76
|
# @param shared [String, nil] a shared-root override
|
|
77
|
-
# @param
|
|
77
|
+
# @param install_driving [Boolean] whether to install the Ruby facade constants
|
|
78
78
|
# @param environment [String, nil] the environment name for the selected-file loader
|
|
79
79
|
# @return [Runtime::Dispatcher, Runtime::RemoteDispatcher] the dispatcher bound
|
|
80
80
|
# to the booted domain
|
|
81
|
-
def boot_files(paths, shared: nil,
|
|
82
|
-
Loader.boot_files(paths, shared: shared,
|
|
81
|
+
def boot_files(paths, shared: nil, install_driving: true, environment: Runtime::Loader::FROM_ENV)
|
|
82
|
+
Loader.boot_files(paths, shared: shared, install_driving: install_driving, environment: environment)
|
|
83
83
|
end
|
|
84
84
|
|
|
85
85
|
# Bind the ambient registry for the duration of the block, restoring
|
|
@@ -11,7 +11,7 @@ module Hecks
|
|
|
11
11
|
# The optional attachments `rust/host` reads from `ir.json`, each omitted when nothing
|
|
12
12
|
# attached provides it: exporter method, then the key it is written under.
|
|
13
13
|
SEAMS = %i[authorization membership identity newsletter newsletter_issues payments
|
|
14
|
-
registrations payment_connection].freeze
|
|
14
|
+
registrations payment_connection checkout].freeze
|
|
15
15
|
|
|
16
16
|
# Round-trips a value through JSON so generators see the string-keyed shape a real
|
|
17
17
|
# `ir.json` carries, never live Ruby symbols.
|
|
@@ -60,7 +60,7 @@ module Hecks
|
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
def require_target!
|
|
63
|
-
return if
|
|
63
|
+
return if RustBuild.target_installed?(TARGET)
|
|
64
64
|
|
|
65
65
|
raise Failure, <<~MSG
|
|
66
66
|
#{TARGET} isn't installed for this toolchain. Install it once with:
|
|
@@ -52,7 +52,7 @@ module Hecks
|
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
def require_target!
|
|
55
|
-
return if
|
|
55
|
+
return if RustBuild.target_installed?(TARGET)
|
|
56
56
|
|
|
57
57
|
raise Failure, <<~MSG
|
|
58
58
|
#{TARGET} isn't installed for this toolchain. Install it once with:
|
data/lib/hecks/rust_build.rb
CHANGED
|
@@ -83,6 +83,17 @@ module Hecks
|
|
|
83
83
|
raise Failure, "`#{command.join(" ")}` failed#{" in #{chdir}" if chdir}"
|
|
84
84
|
end
|
|
85
85
|
|
|
86
|
+
# Asks rustup whether a compile target is installed for the active toolchain.
|
|
87
|
+
#
|
|
88
|
+
# @param target [String] the target triple, such as `wasm32-unknown-unknown`
|
|
89
|
+
# @return [Boolean] false when rustup is missing or does not list the target
|
|
90
|
+
def target_installed?(target)
|
|
91
|
+
listed = IO.popen(["rustup", "target", "list", "--installed", { err: File::NULL }], &:read)
|
|
92
|
+
listed.split("\n").include?(target)
|
|
93
|
+
rescue SystemCallError
|
|
94
|
+
false
|
|
95
|
+
end
|
|
96
|
+
|
|
86
97
|
# Runs a tool and holds what it printed.
|
|
87
98
|
#
|
|
88
99
|
# @param tool [String] a key of `TOOLS`
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require "rack"
|
|
2
|
+
|
|
3
|
+
module Hecks
|
|
4
|
+
# What a domain's world file says it is served by: each `served_by("Adapter") { ... }` line
|
|
5
|
+
# names an inbound adapter and the per-environment values it needs. The route is derived,
|
|
6
|
+
# never written: a driving adapter answers at `/webhooks/<adapter name, snake-cased>` unless
|
|
7
|
+
# its `path` says otherwise, so a world holds only what the domain cannot know (secret,
|
|
8
|
+
# path override) and the same domain can be served differently in each environment.
|
|
9
|
+
#
|
|
10
|
+
# A secret is named by the environment variable that holds it, never inline.
|
|
11
|
+
module ServedOptions
|
|
12
|
+
VERB = "served_by".freeze
|
|
13
|
+
|
|
14
|
+
module_function
|
|
15
|
+
|
|
16
|
+
# @param world [Bluebook::World, nil] a domain's judged world
|
|
17
|
+
# @return [Array<Hash>] one entry per `served_by` line: `adapter`, `path` and its settings
|
|
18
|
+
def entries(world)
|
|
19
|
+
return [] unless world
|
|
20
|
+
|
|
21
|
+
world.settings.filter_map do |key, values|
|
|
22
|
+
next unless key.to_s.start_with?("#{VERB}:")
|
|
23
|
+
|
|
24
|
+
adapter = values.fetch(:adapter)
|
|
25
|
+
values.merge(adapter: adapter, path: values.fetch(:path) { "/webhooks/#{snake(adapter)}" })
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# A Rack app mounting every `served_by` adapter the world names at its derived path.
|
|
30
|
+
#
|
|
31
|
+
# @param world [Bluebook::World, nil]
|
|
32
|
+
# @param adapters [Hash{String => Class}] driving adapter classes by the name a world uses;
|
|
33
|
+
# each is built with `secret:` read from the environment variable the line names
|
|
34
|
+
# @param env [#fetch] where secrets are read from (`ENV` in production)
|
|
35
|
+
# @return [Rack::URLMap]
|
|
36
|
+
# @raise [KeyError] when a line names an adapter no class answers for
|
|
37
|
+
# @raise [ArgumentError] when a line names a secret variable the environment does not hold
|
|
38
|
+
def rack_app(world, adapters:, env: ENV)
|
|
39
|
+
routes = entries(world).to_h do |entry|
|
|
40
|
+
klass = adapters.fetch(entry[:adapter])
|
|
41
|
+
[entry[:path], klass.new(secret: secret_for(entry, env))]
|
|
42
|
+
end
|
|
43
|
+
Rack::URLMap.new(routes)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def secret_for(entry, env)
|
|
47
|
+
name = entry.fetch(:secret) { raise ArgumentError, "#{entry[:adapter]} names no secret" }
|
|
48
|
+
env.fetch(name) { raise ArgumentError, "#{entry[:adapter]}: environment variable #{name} is not set" }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def snake(name) = name.to_s.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -33,7 +33,7 @@ module Hecks
|
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
# Tails this bus's own dispatch/query/state audit log — a pull-based
|
|
36
|
-
# substitute for a push subscription, since a stdio
|
|
36
|
+
# substitute for a push subscription, since a stdio server answers one
|
|
37
37
|
# request at a time with no channel to push through.
|
|
38
38
|
#
|
|
39
39
|
# @param runtime [Runtime::Registry] the booted domain to tail
|
|
@@ -34,9 +34,9 @@ module Hecks
|
|
|
34
34
|
|
|
35
35
|
# :nodoc:
|
|
36
36
|
def command_envelope(args, spec)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
Adapters::Driving::CommandRequest.normalize(Adapters::Driving::Json.deep_symbolize(args),
|
|
38
|
+
receiver: spec[:receiver],
|
|
39
|
+
legacy_receiver: spec[:legacy_receiver])
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
# :nodoc:
|
|
@@ -52,7 +52,9 @@ module Hecks
|
|
|
52
52
|
ok(summary: summary,
|
|
53
53
|
id: result.id,
|
|
54
54
|
state: settled_state(runtime, spec, result),
|
|
55
|
-
events: result.events.map
|
|
55
|
+
events: result.events.map do |event|
|
|
56
|
+
{ name: event.name, payload: Adapters::Driving::Json.materialize(event.payload) }
|
|
57
|
+
end)
|
|
56
58
|
end
|
|
57
59
|
|
|
58
60
|
# The record as its repository holds it once every reaction has run, which is the state the
|
|
@@ -65,7 +67,7 @@ module Hecks
|
|
|
65
67
|
def settled_state(runtime, spec, result)
|
|
66
68
|
return if result.state.nil?
|
|
67
69
|
|
|
68
|
-
|
|
70
|
+
Adapters::Driving::Json.materialize(settled_record(runtime, spec, result) || result.state)
|
|
69
71
|
end
|
|
70
72
|
|
|
71
73
|
# :nodoc:
|
|
@@ -141,7 +143,7 @@ module Hecks
|
|
|
141
143
|
|
|
142
144
|
# :nodoc:
|
|
143
145
|
def batch_step(runtime, raw, summary, options)
|
|
144
|
-
step =
|
|
146
|
+
step = Adapters::Driving::Json.deep_symbolize(raw)
|
|
145
147
|
dispatch(runtime: runtime, command: step[:command], args: step[:args] || {}, summary: summary, **options)
|
|
146
148
|
end
|
|
147
149
|
end
|
|
@@ -68,7 +68,7 @@ module Hecks
|
|
|
68
68
|
# @return [Hash] {ok: true, domain:, valid: true} plus :findings when deep;
|
|
69
69
|
# {ok: false, domain:, valid: false, error:} if the boot itself failed
|
|
70
70
|
def validate(domain:, deep: false)
|
|
71
|
-
runtime = Hecks.boot(confine!(domain, "domain"),
|
|
71
|
+
runtime = Hecks.boot(confine!(domain, "domain"), install_driving: false)
|
|
72
72
|
result = { ok: true, domain: domain, valid: true }
|
|
73
73
|
result[:findings] = model_findings(runtime) if deep
|
|
74
74
|
result
|
|
@@ -103,7 +103,7 @@ module Hecks
|
|
|
103
103
|
|
|
104
104
|
# :nodoc:
|
|
105
105
|
def journal_entries(repository)
|
|
106
|
-
repository.entries.map { |entry| { operation: entry.operation, id: entry.id, state:
|
|
106
|
+
repository.entries.map { |entry| { operation: entry.operation, id: entry.id, state: Adapters::Driving::Json.materialize(entry.state) } }
|
|
107
107
|
end
|
|
108
108
|
|
|
109
109
|
# Runs a domain's hand-curated .behaviors examples and reports the results.
|
|
@@ -27,12 +27,14 @@ module Hecks
|
|
|
27
27
|
spec = resolve!(cli_for(request.bluebook), request.name, asking: true)
|
|
28
28
|
rows = with_caller(request.role, request.actor_id) { answer(request, spec) }
|
|
29
29
|
|
|
30
|
-
ok(summary: request.summary, rows: rows.map
|
|
30
|
+
ok(summary: request.summary, rows: rows.map do |row|
|
|
31
|
+
Adapters::Driving::Json.materialize(row)
|
|
32
|
+
end).merge(verb: spec[:command])
|
|
31
33
|
end
|
|
32
34
|
|
|
33
35
|
# :nodoc:
|
|
34
36
|
def answer(request, spec)
|
|
35
|
-
request.runtime.query(spec[:command], **
|
|
37
|
+
request.runtime.query(spec[:command], **Adapters::Driving::Json.deep_symbolize(request.args))
|
|
36
38
|
end
|
|
37
39
|
|
|
38
40
|
# Reads one aggregate's stored records directly, bypassing any declared
|
|
@@ -63,7 +65,7 @@ module Hecks
|
|
|
63
65
|
repository = runtime.registry.repository(bluebook.name, ir)
|
|
64
66
|
return ok(summary: summary, record: single_record(repository, ir, id)) if id
|
|
65
67
|
|
|
66
|
-
records = repository.all.map { |instance|
|
|
68
|
+
records = repository.all.map { |instance| Adapters::Driving::Json.materialize(instance.to_h) }
|
|
67
69
|
ok(summary: summary, count: records.length, records: records)
|
|
68
70
|
end
|
|
69
71
|
|
|
@@ -71,7 +73,7 @@ module Hecks
|
|
|
71
73
|
def single_record(repository, aggregate_ir, identity)
|
|
72
74
|
instance = repository.find(identity) or
|
|
73
75
|
raise Runtime::NotFound, "no #{aggregate_ir.hecks_name} found for id #{identity.inspect}"
|
|
74
|
-
|
|
76
|
+
Adapters::Driving::Json.materialize(instance.to_h)
|
|
75
77
|
end
|
|
76
78
|
end
|
|
77
79
|
end
|