hecks 3.10.0 → 3.12.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 +158 -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 +70 -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/newcomer.rb +50 -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/read_models.rb +1 -1
- 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 +4 -15
- data/lib/hecks/bluebook/assembly/scalars.rb +39 -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 +24 -1
- data/lib/hecks/bluebook/meta_validator/reconstruction/heads.rb +2 -1
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +6 -3
- 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 +2 -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 +34 -4
- 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 +33 -7
- 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 +133 -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 +13 -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.behaviors +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.behaviors +19 -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 +63 -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/projection_files/expression_tables.rb +7 -2
- data/lib/hecks/projections/deploy/box/compose.rb +6 -4
- data/lib/hecks/projections/deploy/box/edge.rb +62 -0
- data/lib/hecks/projections/deploy/box/logging.rb +99 -0
- data/lib/hecks/projections/deploy/box/roll_scripts.rb +16 -8
- data/lib/hecks/projections/deploy/box/settings/cdn.rb +40 -0
- data/lib/hecks/projections/deploy/box/settings/logs.rb +40 -0
- data/lib/hecks/projections/deploy/box/settings/patterns.rb +11 -0
- data/lib/hecks/projections/deploy/box/settings/types.rb +16 -1
- data/lib/hecks/projections/deploy/box/settings.rb +6 -2
- data/lib/hecks/projections/deploy/box/stack_yaml.rb +5 -2
- data/lib/hecks/projections/deploy/box/templates/Makefile.tmpl +16 -0
- data/lib/hecks/projections/deploy/box/templates/box.yaml.tmpl +8 -4
- data/lib/hecks/projections/deploy/box/templates/deploy-box.sh.tmpl +32 -0
- data/lib/hecks/projections/deploy/box/templates/deploy-service.sh.tmpl +1 -1
- data/lib/hecks/projections/deploy/box/templates/edge.mk.tmpl +17 -0
- data/lib/hecks/projections/deploy/box/templates/edge.yaml.tmpl +65 -0
- data/lib/hecks/projections/deploy/box/templates/log-group.yaml.tmpl +12 -0
- data/lib/hecks/projections/deploy/box/templates/log-policy.yaml.tmpl +7 -0
- data/lib/hecks/projections/deploy/box/templates/render-compose-taskdef.sh.tmpl +5 -4
- data/lib/hecks/projections/deploy/box/templates/render-compose.sh.tmpl +5 -4
- data/lib/hecks/projections/deploy/box.rb +15 -3
- 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/projections/site/site_root/workflow.rb +5 -0
- data/lib/hecks/projector/cli_audience.rb +22 -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/cli_projector/usage.rb +15 -4
- 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/host.rb +11 -4
- data/lib/hecks/rust_build/prebuilt_binary.rb +101 -0
- 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/ci_gate_decision.rb +35 -0
- data/lib/hecks/tools/ci_gates.rb +20 -1
- 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/files.rb +8 -0
- data/lib/hecks/tools/lanes/prebuilt_workflow.rb +81 -0
- data/lib/hecks/tools/lanes/rows.rb +6 -0
- data/lib/hecks/tools/lanes.rb +1 -0
- data/lib/hecks/tools/oidc_manifests.rb +4 -5
- data/lib/hecks/tools/regeneration_run.rb +11 -4
- data/lib/hecks/tools/release_only.rb +111 -0
- 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 +19 -5
- 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/9ee54e2f0d4d6d3fe046827779b221e02de665fba911a048ae5dd8b8fbfb7d90.marshal +0 -0
- data/prebuilt/d74a00e996222c1d8b676d5959092effc46b4dc59e0555f3bf9554ac58e3094a.marshal +0 -0
- data/prebuilt/verdicts-df19f35868d3284a70f55e42dcef87ef4e65e6a678e5135f72e1f6cff4c1357b.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/extension.rs +13 -1
- data/rust/host/src/lib.rs +1 -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/platform_signin/attack_tests.rs +1100 -0
- data/rust/host/src/platform_signin/config.rs +512 -0
- data/rust/host/src/platform_signin/cookie.rs +237 -0
- data/rust/host/src/platform_signin/extension.rs +190 -0
- data/rust/host/src/platform_signin/fetcher.rs +322 -0
- data/rust/host/src/platform_signin/handler.rs +251 -0
- data/rust/host/src/platform_signin/handler_tests.rs +554 -0
- data/rust/host/src/platform_signin/jti.rs +196 -0
- data/rust/host/src/platform_signin/jwks.rs +542 -0
- data/rust/host/src/platform_signin/jws.rs +249 -0
- data/rust/host/src/platform_signin/known_answer_tests.rs +237 -0
- data/rust/host/src/platform_signin/mapping_tests.rs +254 -0
- data/rust/host/src/platform_signin/mod.rs +75 -0
- data/rust/host/src/platform_signin/mode_tests.rs +382 -0
- data/rust/host/src/platform_signin/pages.rs +204 -0
- data/rust/host/src/platform_signin/query.rs +233 -0
- data/rust/host/src/platform_signin/session.rs +151 -0
- data/rust/host/src/platform_signin/settings.rs +385 -0
- data/rust/host/src/platform_signin/strict_json.rs +351 -0
- data/rust/host/src/platform_signin/test_support.rs +235 -0
- data/rust/host/src/platform_signin/ttl_tests.rs +94 -0
- data/rust/host/src/platform_signin/verify.rs +604 -0
- data/rust/host/src/platform_signin/wiring_support.rs +319 -0
- 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 +53 -9
- 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 +34 -17
- 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 +178 -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
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "open3"
|
|
4
|
+
require_relative "../../indifferent_key"
|
|
4
5
|
|
|
5
6
|
module Hecks
|
|
6
7
|
module Adapters
|
|
7
8
|
# The `IssueTracker` port's adapter: files a `QualityControl::Ticket` as a GitHub issue.
|
|
8
9
|
# Raises when `gh` refuses, which the runtime records as the ticket's refusal.
|
|
9
10
|
class GithubIssues
|
|
11
|
+
# Raised when `gh` cannot file the issue.
|
|
12
|
+
class Error < RuntimeError; end
|
|
13
|
+
|
|
10
14
|
# @param aggregate [Object, nil] unused
|
|
11
15
|
# @param settings [Hash] unused
|
|
12
16
|
# @param root [String, nil] unused
|
|
@@ -18,7 +22,7 @@ module Hecks
|
|
|
18
22
|
# value objects (`{value: ...}`) or bare strings, and `pull_request` names a proposed fix
|
|
19
23
|
# @return [Hash{Symbol => Hash}] `number:` and `url:` of the issue, in the shape the
|
|
20
24
|
# ticket's `Filed` command takes
|
|
21
|
-
# @raise [
|
|
25
|
+
# @raise [Error] when `gh` exits non-zero or prints no issue URL
|
|
22
26
|
def file(**held)
|
|
23
27
|
out = create_issue(plain(held[:repository]), plain(held[:title]).to_s, issue_body(held))
|
|
24
28
|
url, number = issue_url_and_number(out)
|
|
@@ -37,7 +41,7 @@ module Hecks
|
|
|
37
41
|
def issue_url_and_number(out)
|
|
38
42
|
url = out.strip.lines.last.to_s.strip
|
|
39
43
|
number = url[%r{/issues/(\d+)\z}, 1]
|
|
40
|
-
raise "gh issue create printed no issue URL: #{out.strip.inspect}" unless number
|
|
44
|
+
raise Error, "gh issue create printed no issue URL: #{out.strip.inspect}" unless number
|
|
41
45
|
|
|
42
46
|
[url, number]
|
|
43
47
|
end
|
|
@@ -45,7 +49,7 @@ module Hecks
|
|
|
45
49
|
def create_issue(repository, title, body)
|
|
46
50
|
out, err, status = Open3.capture3("gh", "issue", "create", "--repo", repository,
|
|
47
51
|
"--title", title, "--body", body)
|
|
48
|
-
raise "gh issue create failed — #{err.strip.empty? ? out.strip : err.strip}" unless status.success?
|
|
52
|
+
raise Error, "gh issue create failed — #{err.strip.empty? ? out.strip : err.strip}" unless status.success?
|
|
49
53
|
|
|
50
54
|
out
|
|
51
55
|
end
|
|
@@ -54,7 +58,7 @@ module Hecks
|
|
|
54
58
|
def plain(field)
|
|
55
59
|
return field unless field.is_a?(Hash)
|
|
56
60
|
|
|
57
|
-
|
|
61
|
+
IndifferentKey.read(field, :value)
|
|
58
62
|
end
|
|
59
63
|
end
|
|
60
64
|
end
|
|
@@ -11,8 +11,8 @@ require_relative "qa_open_pr/recording"
|
|
|
11
11
|
module Hecks
|
|
12
12
|
module QualityControlCli
|
|
13
13
|
# The command behind `hecks quality_control patch.open`: opens a PR and records it in the
|
|
14
|
-
# QualityControl ledger in one step. It is the only
|
|
15
|
-
# `QualityControl::Improvement.Open`.
|
|
14
|
+
# QualityControl ledger in one step. It is the only entry point into
|
|
15
|
+
# `QualityControl::Patch.Open` and `QualityControl::Improvement.Open`.
|
|
16
16
|
#
|
|
17
17
|
# It refuses (exit 1, nothing opened or recorded) unless the ledger's own `Open` command would
|
|
18
18
|
# take the record and the `GitPr` adapter agrees. The command's `given`s are the rules, asked
|
|
@@ -10,7 +10,7 @@ module Hecks
|
|
|
10
10
|
private
|
|
11
11
|
|
|
12
12
|
# Re-runs only the comparison that surprised; `seat` matters only for `self_consistency`,
|
|
13
|
-
# which reads the Rust binary's rehydration
|
|
13
|
+
# which reads the Rust binary's rehydration entry point under a differential seat.
|
|
14
14
|
def candidate_divergences(check_mode, seat, steps)
|
|
15
15
|
case check_mode
|
|
16
16
|
when :differential
|
|
@@ -37,7 +37,7 @@ module Hecks
|
|
|
37
37
|
|
|
38
38
|
def print_finding_instructions
|
|
39
39
|
puts "No Bug was logged (that needs a real failing-test demonstration, which"
|
|
40
|
-
puts "needs judgment this script does not have — hecks quality_control log is the
|
|
40
|
+
puts "needs judgment this script does not have — hecks quality_control log is the entry point)"
|
|
41
41
|
puts "and the sweep was not concluded. The ledger's own SuspendOnSurprise"
|
|
42
42
|
puts "policy took the target out of the rotation; it stays out until a PERSON"
|
|
43
43
|
puts "runs: hecks quality_control ask run target=#{@target_reference} " \
|
|
@@ -130,7 +130,7 @@ module Hecks
|
|
|
130
130
|
@trace_last = now
|
|
131
131
|
end
|
|
132
132
|
|
|
133
|
-
# Default `
|
|
133
|
+
# Default `install_driving` so `QualityControl::Target` and friends are top-level constants.
|
|
134
134
|
def boot_ledger
|
|
135
135
|
Hecks.boot(@domain_dir)
|
|
136
136
|
rescue StandardError => e
|
|
@@ -164,7 +164,7 @@ Hecks.bluebook "QualityControl" do
|
|
|
164
164
|
role "QA engineer"
|
|
165
165
|
goal "Hand a chapter back to the rotation, stamped with when, what this pass was worth, and how the clean streak moves"
|
|
166
166
|
|
|
167
|
-
# `now` is the argument and `last_swept` the field, so the
|
|
167
|
+
# `now` is the argument and `last_swept` the field, so the entry point can fill the clock.
|
|
168
168
|
#
|
|
169
169
|
# `next_streak` is the caller's to compute (`clean_streak + 1` if every check held and none
|
|
170
170
|
# was ever surprised, else 0): `Target` cannot read `Sweep` state and no policy payload can
|
|
@@ -530,6 +530,7 @@ Hecks.bluebook "QualityControl" do
|
|
|
530
530
|
end
|
|
531
531
|
|
|
532
532
|
lifecycle :status, default: "sweeping" do
|
|
533
|
+
mark :failure, "abandoned"
|
|
533
534
|
transition "Check" => "sweeping", from: "sweeping"
|
|
534
535
|
transition "Waive" => "sweeping", from: "sweeping"
|
|
535
536
|
transition "Conclude" => "concluded", from: "sweeping"
|
|
@@ -778,7 +779,7 @@ Hecks.bluebook "QualityControl" do
|
|
|
778
779
|
invariant("a bug sequence is positive") { value.positive? }
|
|
779
780
|
end
|
|
780
781
|
|
|
781
|
-
# Prefixed on purpose: `
|
|
782
|
+
# Prefixed on purpose: `Adapters::Driving::Ruby.install` puts every aggregate name on Object, so a
|
|
782
783
|
# value object sharing a word with any aggregate resolves to that class once the other domain
|
|
783
784
|
# boots.
|
|
784
785
|
value_object "BugTitle" do
|
|
@@ -1456,6 +1457,7 @@ Hecks.bluebook "QualityControl" do
|
|
|
1456
1457
|
# filing. `Submit` is non-creating, so `TicketSubmitted` carries `{ id: ... }`, which a
|
|
1457
1458
|
# reference slot takes.
|
|
1458
1459
|
lifecycle :status, default: "raised" do
|
|
1460
|
+
mark :failure, "refused", "abandoned"
|
|
1459
1461
|
transition "Submit" => "submitting", from: ["raised", "refused"]
|
|
1460
1462
|
transition "Filed" => "filed", from: "submitting"
|
|
1461
1463
|
transition "Refused" => "refused", from: "submitting"
|
|
@@ -1866,6 +1868,7 @@ Hecks.bluebook "QualityControl" do
|
|
|
1866
1868
|
# proof-only PR can be closed while still "opened" (`retire_if_settled?` hit
|
|
1867
1869
|
# `LifecycleRefused`).
|
|
1868
1870
|
lifecycle :status, default: "opened" do
|
|
1871
|
+
mark :failure, "needs_fix"
|
|
1869
1872
|
transition "Land" => "landed", from: ["opened", "needs_fix"]
|
|
1870
1873
|
transition "Regress" => "needs_fix", from: "landed"
|
|
1871
1874
|
transition "Merge" => "merged", from: ["opened", "landed", "needs_fix"]
|
|
@@ -1983,6 +1986,7 @@ Hecks.bluebook "QualityControl" do
|
|
|
1983
1986
|
end
|
|
1984
1987
|
|
|
1985
1988
|
lifecycle :status, default: "running" do
|
|
1989
|
+
mark :failure, "red"
|
|
1986
1990
|
transition "Passed" => "green", from: "running"
|
|
1987
1991
|
transition "Failed" => "red", from: "running"
|
|
1988
1992
|
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "hecks/vocabulary"
|
|
4
|
+
|
|
5
|
+
module Hecks
|
|
6
|
+
module Release
|
|
7
|
+
# Whether the commit that set the version carries the owner's approval of the release.
|
|
8
|
+
#
|
|
9
|
+
# Releases are the owner's decision. A bump on `main` reaches `stable` by itself, so the bump
|
|
10
|
+
# commit must say, in its message, that a release is wanted: a trailer line named by the
|
|
11
|
+
# `release_trailer` of the `Lane` row a release is cut from, `Release-Approved-By: <name>`. The
|
|
12
|
+
# decision is read from git history alone, so it can be made again on any later run. It reads
|
|
13
|
+
# only the Vocabulary table, so `release.yml` can run it with the runner's own Ruby.
|
|
14
|
+
module Approval
|
|
15
|
+
module_function
|
|
16
|
+
|
|
17
|
+
# @return [String] the trailer key, read from the `Lane` row that feeds a tag
|
|
18
|
+
# @raise [KeyError] when that row names no trailer
|
|
19
|
+
def trailer
|
|
20
|
+
row = Hecks::Vocabulary.rows("Lane").find { |lane| !lane["feeds"].to_s.empty? }
|
|
21
|
+
key = row && row["release_trailer"].to_s
|
|
22
|
+
raise KeyError, "the Lane row a release is cut from names no release_trailer" if key.nil? || key.empty?
|
|
23
|
+
|
|
24
|
+
key
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# @param message [String] a commit message
|
|
28
|
+
# @return [String, nil] who approved, from the first trailer line with a name, or nil
|
|
29
|
+
def approver(message)
|
|
30
|
+
line = message.to_s.lines.map(&:strip).find { |text| text.match?(/\A#{Regexp.escape(trailer)}:\s*\S/) }
|
|
31
|
+
line&.sub(/\A[^:]*:\s*/, "")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @param message [String] the message of the commit that set the version
|
|
35
|
+
# @param tag_exists [Boolean] whether the release's tag already stands on origin: a release
|
|
36
|
+
# that was begun was approved when it began, so finishing it asks again for nothing
|
|
37
|
+
# @param explicit [String, nil] a name the owner passed to a by-hand run
|
|
38
|
+
# @return [Array(Boolean, String)] whether the release may go ahead, and the words to print
|
|
39
|
+
def verdict(message:, tag_exists: false, explicit: nil)
|
|
40
|
+
return [true, "approved by #{explicit.strip} (by-hand run)"] unless explicit.to_s.strip.empty?
|
|
41
|
+
return [true, "the tag already stands; finishing a release that was begun"] if tag_exists
|
|
42
|
+
|
|
43
|
+
who = approver(message)
|
|
44
|
+
return [true, "approved by #{who} (#{trailer} trailer)"] if who
|
|
45
|
+
|
|
46
|
+
[false, "the commit that set the version has no '#{trailer}: <name>' line in its message, so it " \
|
|
47
|
+
"is not a release the owner asked for. Nothing was tagged or pushed. To release it, " \
|
|
48
|
+
"re-run by hand with the approval: gh workflow run release.yml -f tag=vX.Y.Z -f approved_by=<name>"]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Reads the decision's inputs from the environment `release.yml` gives it.
|
|
52
|
+
#
|
|
53
|
+
# @param env [#[]] `COMMIT_MESSAGE`, `TAG_EXISTS` (true/false), `APPROVED_BY`
|
|
54
|
+
# @param out [#puts] where the words go
|
|
55
|
+
# @return [Integer] the exit status: 0 to go ahead, 1 to refuse
|
|
56
|
+
def check(env: ENV, out: $stdout)
|
|
57
|
+
ok, words = verdict(message: env["COMMIT_MESSAGE"], tag_exists: env["TAG_EXISTS"] == "true",
|
|
58
|
+
explicit: env["APPROVED_BY"])
|
|
59
|
+
out.puts(ok ? "release approval: #{words}" : "::error::#{words}")
|
|
60
|
+
ok ? 0 : 1
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
require_relative "../
|
|
1
|
+
require_relative "../adapters/driving/handle"
|
|
2
2
|
|
|
3
3
|
module Hecks
|
|
4
4
|
class Router
|
|
5
5
|
class NamespaceInstaller
|
|
6
6
|
# One aggregate's repository and event log, read through its dispatcher.
|
|
7
|
-
|
|
7
|
+
AggregateReader = Struct.new(:dispatcher, :domain, :aggregate) do
|
|
8
8
|
# @param entry [Router::Entry] a router entry
|
|
9
|
-
# @return [
|
|
9
|
+
# @return [AggregateReader, nil] the reader for the entry's aggregate; nil for a
|
|
10
|
+
# query/command-only entry
|
|
10
11
|
# whose owner isn't a real aggregate root
|
|
11
12
|
def self.for(entry)
|
|
12
13
|
domain = entry.fqn.domain
|
|
@@ -29,7 +30,7 @@ module Hecks
|
|
|
29
30
|
def all = repository.all.map { |instance| handle(instance) }
|
|
30
31
|
|
|
31
32
|
def handle(instance)
|
|
32
|
-
|
|
33
|
+
Adapters::Driving::Handle.new(dispatcher: dispatcher, domain: domain, aggregate: aggregate, instance: instance)
|
|
33
34
|
end
|
|
34
35
|
end
|
|
35
36
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require_relative "../fqn"
|
|
2
2
|
require_relative "options_proxy"
|
|
3
|
-
require_relative "
|
|
3
|
+
require_relative "aggregate_reader"
|
|
4
4
|
|
|
5
5
|
module Hecks
|
|
6
6
|
class Router
|
|
@@ -12,11 +12,11 @@ module Hecks
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
# Installs every current-version route as a namespace constant/method, plus
|
|
15
|
-
# the aggregate CRUD
|
|
15
|
+
# the aggregate CRUD module and short `Aggregate.verb` shortcuts.
|
|
16
16
|
def install!
|
|
17
17
|
current_entries.each { |entry| install_namespace_entry(entry) }
|
|
18
18
|
install_shortcuts!
|
|
19
|
-
|
|
19
|
+
install_aggregate_modules!
|
|
20
20
|
self
|
|
21
21
|
end
|
|
22
22
|
|
|
@@ -48,26 +48,26 @@ module Hecks
|
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
# `.find`/`.all`/`.count`/`.events`/`.repository`, matching `Hecks.boot`'s
|
|
51
|
-
#
|
|
52
|
-
def
|
|
51
|
+
# module; grouped by (realm, domain, aggregate) since the five don't vary by verb.
|
|
52
|
+
def install_aggregate_modules!
|
|
53
53
|
current_entries.reject { |entry| entry.fqn.aggregate.nil? }
|
|
54
54
|
.group_by { |entry| [entry.fqn.realm, entry.fqn.domain, entry.fqn.aggregate] }
|
|
55
|
-
.each_value { |entries|
|
|
55
|
+
.each_value { |entries| install_aggregate_module(entries.first) }
|
|
56
56
|
end
|
|
57
57
|
|
|
58
|
-
def
|
|
59
|
-
|
|
60
|
-
return unless
|
|
58
|
+
def install_aggregate_module(entry)
|
|
59
|
+
reader = AggregateReader.for(entry)
|
|
60
|
+
return unless reader
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
define_module_methods(namespace_for(entry.fqn.realm, entry.fqn.domain, entry.fqn.aggregate), reader)
|
|
63
63
|
end
|
|
64
64
|
|
|
65
|
-
def
|
|
66
|
-
target.define_singleton_method(:repository) {
|
|
67
|
-
target.define_singleton_method(:count) {
|
|
68
|
-
target.define_singleton_method(:events) {
|
|
69
|
-
target.define_singleton_method(:find) { |id|
|
|
70
|
-
target.define_singleton_method(:all) {
|
|
65
|
+
def define_module_methods(target, reader)
|
|
66
|
+
target.define_singleton_method(:repository) { reader.repository }
|
|
67
|
+
target.define_singleton_method(:count) { reader.repository.count }
|
|
68
|
+
target.define_singleton_method(:events) { reader.events }
|
|
69
|
+
target.define_singleton_method(:find) { |id| reader.find(id) }
|
|
70
|
+
target.define_singleton_method(:all) { reader.all }
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
def install_shortcuts!
|
data/lib/hecks/router.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
module Hecks
|
|
2
|
-
# The public, project-wide dispatch
|
|
2
|
+
# The public, project-wide dispatch entry point. It owns address resolution only;
|
|
3
3
|
# each discovered Bluebook keeps its own runtime and persistence bindings.
|
|
4
4
|
class Router
|
|
5
5
|
class UnknownAddress < StandardError; end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Hecks
|
|
2
|
+
module Runtime
|
|
3
|
+
# The one place the runtime answers a default when a read raises, so a deliberate guard is
|
|
4
|
+
# named at its call site and `Hecks/SwallowedRescue` can refuse every other silent swallow.
|
|
5
|
+
#
|
|
6
|
+
# BestEffort.call(false) { adapter_class.tenant_capable? } # => false when the lookup raises
|
|
7
|
+
module BestEffort
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
# Runs the block and answers its value, or `default` when it raises a StandardError.
|
|
11
|
+
#
|
|
12
|
+
# @param default [Object] what to answer when the block raises
|
|
13
|
+
# @yield the read that may raise
|
|
14
|
+
# @return [Object] the block's value, or `default`
|
|
15
|
+
def call(default)
|
|
16
|
+
yield
|
|
17
|
+
rescue StandardError
|
|
18
|
+
default
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -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)
|