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
|
@@ -16,6 +16,11 @@ module Hecks
|
|
|
16
16
|
[/\A(.+)\.set\?\z/, Assignment, { negated: false }], [/\A(.+)\.unset\?\z/, Assignment, { negated: true }]
|
|
17
17
|
].freeze
|
|
18
18
|
|
|
19
|
+
# The strip family, each matched as `<receiver>.<call>`, naming which ends it trims.
|
|
20
|
+
STRIP_SUFFIXES = [
|
|
21
|
+
[/\A(.+)\.strip\z/, :both], [/\A(.+)\.lstrip\z/, :left], [/\A(.+)\.rstrip\z/, :right]
|
|
22
|
+
].freeze
|
|
23
|
+
|
|
19
24
|
# The suffix calls that carry one quoted argument, as `<receiver>.<call>("<argument>")`.
|
|
20
25
|
TEXT_SUFFIXES = [
|
|
21
26
|
[/\A(.+)\.split\("([^"]*)"\)\z/, Split, :separator],
|
|
@@ -23,10 +28,15 @@ module Hecks
|
|
|
23
28
|
[/\A(.+)\.end_with\?\("([^"]*)"\)\z/, EndsWith, :substring]
|
|
24
29
|
].freeze
|
|
25
30
|
|
|
31
|
+
# The node each infix operator builds, by precedence level.
|
|
32
|
+
ADDITIVE = { "+" => Addition, "-" => Subtraction }.freeze
|
|
33
|
+
MULTIPLICATIVE = { "*" => Multiplication, "/" => Division }.freeze
|
|
34
|
+
|
|
26
35
|
# Every step `parse` tries, in precedence order (`.length` first, sign tests before the
|
|
27
36
|
# rest); each answers a node, or `nil` when the expression is not its form.
|
|
28
|
-
PARSE_STEPS = [:parse_length, :parse_literal, :parse_array, :
|
|
29
|
-
:
|
|
37
|
+
PARSE_STEPS = [:parse_length, :parse_literal, :parse_array, :parse_additive, :parse_multiplicative,
|
|
38
|
+
:parse_group, :parse_sign_test,
|
|
39
|
+
:parse_receiver_suffix, :parse_strip, :parse_modulo, :parse_matches_regex, :parse_text_suffix,
|
|
30
40
|
:parse_block_opener].freeze
|
|
31
41
|
|
|
32
42
|
# @param expr [String] the leaf expression text
|
|
@@ -62,9 +72,24 @@ module Hecks
|
|
|
62
72
|
ArrayLiteral.new(elements: elements.map { |element| parse(element) }) if elements
|
|
63
73
|
end
|
|
64
74
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
75
|
+
# The additive level: the last top-level `+` or binary `-`, so `a - b + c` is `(a - b) + c`.
|
|
76
|
+
def parse_additive(expr)
|
|
77
|
+
parse_binary(expr, ADDITIVE)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# The multiplicative level, binding tighter than the additive one.
|
|
81
|
+
def parse_multiplicative(expr)
|
|
82
|
+
parse_binary(expr, MULTIPLICATIVE)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# A parenthesised group reads as what it wraps.
|
|
86
|
+
def parse_group(expr)
|
|
87
|
+
parse(expr[1..-2]) if grouped?(expr)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def parse_binary(expr, table)
|
|
91
|
+
operator, left, right = split_last_binary(expr, table.keys)
|
|
92
|
+
table.fetch(operator).new(left: parse(left), right: parse(right)) if operator
|
|
68
93
|
end
|
|
69
94
|
|
|
70
95
|
def parse_sign_test(expr)
|
|
@@ -80,6 +105,14 @@ module Hecks
|
|
|
80
105
|
nil
|
|
81
106
|
end
|
|
82
107
|
|
|
108
|
+
def parse_strip(expr)
|
|
109
|
+
STRIP_SUFFIXES.each do |pattern, side|
|
|
110
|
+
match = expr.match(pattern)
|
|
111
|
+
return Strip.new(receiver: parse(match[1]), side: side) if match
|
|
112
|
+
end
|
|
113
|
+
nil
|
|
114
|
+
end
|
|
115
|
+
|
|
83
116
|
def parse_modulo(expr)
|
|
84
117
|
modulo = match_call(expr, ".modulo(")
|
|
85
118
|
Modulo.new(receiver: parse(modulo[0]), divisor: parse(modulo[1])) if modulo
|
|
@@ -66,17 +66,34 @@ module Hecks
|
|
|
66
66
|
elements.map(&:strip)
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
-
#
|
|
70
|
-
#
|
|
71
|
-
|
|
69
|
+
# The text before and after the last top-level binary operator in `operators`, so a chain
|
|
70
|
+
# splits left-associatively. A `-` is binary only after an operand (`a - b`, not `a - -b`
|
|
71
|
+
# or a leading `-5`).
|
|
72
|
+
#
|
|
73
|
+
# @param operators [Array<String>] the single-character operators to split on
|
|
74
|
+
# @return [Array<String>, nil] the operator and the texts either side, or `nil`
|
|
75
|
+
def split_last_binary(expr, operators)
|
|
72
76
|
depth = 0
|
|
77
|
+
found = nil
|
|
73
78
|
scan_text(expr) do |char, index, plain|
|
|
74
79
|
next unless plain
|
|
75
80
|
|
|
76
81
|
depth += DEPTH_DELTA.fetch(char, 0)
|
|
77
|
-
|
|
82
|
+
found = index if depth.zero? && operators.include?(char) && binary_position?(expr, index, char)
|
|
78
83
|
end
|
|
79
|
-
|
|
84
|
+
found && [expr[found], expr[0...found].strip, expr[(found + 1)..].strip]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Whether the operator at `index` has an operand on its left; only `-` can also be a sign.
|
|
88
|
+
def binary_position?(expr, index, char)
|
|
89
|
+
return true unless char == "-"
|
|
90
|
+
|
|
91
|
+
expr[0...index].rstrip.match?(/[[:alnum:]_)\]"']\z/)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Whether `expr` is one parenthesised group: its first `(` closes at its last character.
|
|
95
|
+
def grouped?(expr)
|
|
96
|
+
expr.start_with?("(") && matching_paren(expr, 1) == expr.length - 1
|
|
80
97
|
end
|
|
81
98
|
|
|
82
99
|
# Whether `expr` is wrapped in a matching pair of quotes.
|
|
@@ -76,6 +76,16 @@ module Hecks
|
|
|
76
76
|
value.split(separator)
|
|
77
77
|
end
|
|
78
78
|
|
|
79
|
+
def strip_value(value, side)
|
|
80
|
+
raise EvaluationError, "strip expects a string, got #{describe(value)}" unless value.is_a?(String)
|
|
81
|
+
|
|
82
|
+
case side
|
|
83
|
+
when :left then value.lstrip
|
|
84
|
+
when :right then value.rstrip
|
|
85
|
+
else value.strip
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
79
89
|
def last_of(value)
|
|
80
90
|
return value.last if value.respond_to?(:last)
|
|
81
91
|
|
|
@@ -27,6 +27,11 @@ module Hecks
|
|
|
27
27
|
# A plain class: `Struct.new(keyword_init: true)` with no members raises on Ruby 3.2.
|
|
28
28
|
NilLiteral = Class.new
|
|
29
29
|
Addition = Struct.new(:left, :right, keyword_init: true)
|
|
30
|
+
Subtraction = Struct.new(:left, :right, keyword_init: true)
|
|
31
|
+
Multiplication = Struct.new(:left, :right, keyword_init: true)
|
|
32
|
+
# Integer operands divide with floor semantics (toward negative infinity); a zero divisor
|
|
33
|
+
# is an evaluation fault, never a crash or an infinity.
|
|
34
|
+
Division = Struct.new(:left, :right, keyword_init: true)
|
|
30
35
|
SignTest = Struct.new(:operator, :test, :receiver, keyword_init: true)
|
|
31
36
|
Empty = Struct.new(:receiver, keyword_init: true)
|
|
32
37
|
ToS = Struct.new(:receiver, keyword_init: true)
|
|
@@ -43,6 +48,11 @@ module Hecks
|
|
|
43
48
|
|
|
44
49
|
Split = Struct.new(:receiver, :separator, keyword_init: true)
|
|
45
50
|
|
|
51
|
+
# `.strip`/`.lstrip`/`.rstrip`: `side` is `:both`, `:left` or `:right`. Strips Ruby's own
|
|
52
|
+
# whitespace set (null, tab, line feed, vertical tab, form feed, carriage return, space),
|
|
53
|
+
# never Unicode spaces; a receiver that is not a String is an evaluation fault.
|
|
54
|
+
Strip = Struct.new(:receiver, :side, keyword_init: true)
|
|
55
|
+
|
|
46
56
|
Last = Struct.new(:receiver, keyword_init: true)
|
|
47
57
|
|
|
48
58
|
First = Struct.new(:receiver, keyword_init: true)
|
|
@@ -72,12 +82,21 @@ module Hecks
|
|
|
72
82
|
when IntegerLiteral, FloatLiteral, StringLiteral, BoolLiteral then node.value
|
|
73
83
|
when ArrayLiteral then node.elements.map { |element| interpret(element, state, attrs) }
|
|
74
84
|
when NilLiteral then nil
|
|
75
|
-
when Addition
|
|
85
|
+
when Addition, Subtraction, Multiplication, Division then interpret_binary(node, state, attrs)
|
|
76
86
|
when Lookup then lookup(node.path, state, attrs)
|
|
77
87
|
else interpret_on_receiver(node, state, attrs)
|
|
78
88
|
end
|
|
79
89
|
end
|
|
80
90
|
|
|
91
|
+
# Each arithmetic node and the operation that applies it to its two resolved operands.
|
|
92
|
+
BINARY_OPERATIONS = { Addition => :add, Subtraction => :subtract, Multiplication => :multiply,
|
|
93
|
+
Division => :divide }.freeze
|
|
94
|
+
|
|
95
|
+
def interpret_binary(node, state, attrs)
|
|
96
|
+
operation = BINARY_OPERATIONS.find { |klass, _| node.is_a?(klass) }.last
|
|
97
|
+
public_send(operation, interpret(node.left, state, attrs), interpret(node.right, state, attrs))
|
|
98
|
+
end
|
|
99
|
+
|
|
81
100
|
# Resolves the node's receiver, then applies the operation `RECEIVER_OPERATIONS` names.
|
|
82
101
|
def interpret_on_receiver(node, state, attrs)
|
|
83
102
|
_, operation = RECEIVER_OPERATIONS.find { |klass, _| node.is_a?(klass) }
|
|
@@ -10,10 +10,17 @@ module Hecks
|
|
|
10
10
|
def effect? = signal == :effect
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
# One `.adapter`: the port it implements, the settings a world may give it, and the secrets.
|
|
14
|
+
# `defaults` maps a field's name to the value used when the world gives none; a string may hold
|
|
15
|
+
# a `{name}` or `{storage_name}` placeholder, filled from the aggregate the adapter is built
|
|
16
|
+
# for.
|
|
17
|
+
Adapter = Struct.new(:name, :port, :fields, :secrets, :defaults, keyword_init: true) do
|
|
14
18
|
def declares?(field) = all_fields.include?(field.to_sym)
|
|
15
19
|
|
|
16
20
|
def all_fields = (fields || []) + (secrets || [])
|
|
21
|
+
|
|
22
|
+
# @return [Hash{Symbol => Object}] the declared defaults, empty when none
|
|
23
|
+
def declared_defaults = defaults || {}
|
|
17
24
|
end
|
|
18
25
|
|
|
19
26
|
Bind = Struct.new(:aggregate, :verb, :adapter, :role, keyword_init: true) do
|
|
@@ -49,15 +56,19 @@ module Hecks
|
|
|
49
56
|
binds: many(:binds),
|
|
50
57
|
subscriptions: -> { subscriptions.map(&:to_s) },
|
|
51
58
|
attachments: -> { attachments.map(&:to_h) },
|
|
59
|
+
driving: -> { driving.map(&:to_s) },
|
|
52
60
|
bounded: :bounded?,
|
|
53
61
|
translates: -> { translates.map(&:to_s) }
|
|
54
62
|
)
|
|
55
63
|
|
|
56
|
-
attr_reader :domain, :binds, :subscriptions, :attachments, :translates
|
|
64
|
+
attr_reader :domain, :binds, :subscriptions, :attachments, :translates, :driving
|
|
65
|
+
|
|
66
|
+
# The driving adapters `driven_by` can name.
|
|
67
|
+
DRIVING_ADAPTERS = %w[Ruby Cli Json Mcp].freeze
|
|
57
68
|
|
|
58
69
|
# Every optional keyword and what it holds when the declaration omits it.
|
|
59
70
|
FIELD_DEFAULTS = {
|
|
60
|
-
binds: [], subscriptions: [], attachments: [], bounded: false, translates: []
|
|
71
|
+
binds: [], subscriptions: [], attachments: [], bounded: false, translates: [], driving: []
|
|
61
72
|
}.freeze
|
|
62
73
|
|
|
63
74
|
# @param domain [String, Symbol] the domain this hecksagon wires
|
|
@@ -69,11 +80,13 @@ module Hecks
|
|
|
69
80
|
# @param bounded [Boolean] whether this chapter is an explicit bounded context
|
|
70
81
|
# (consumer-owned; `attaches` marks attached chapters bounded on the registry instead)
|
|
71
82
|
# @param translates [Array<String>] names of `translates` ACL blocks declared here
|
|
83
|
+
# @param driving [Array<String>] the driving adapters `driven_by` admits; empty admits all
|
|
72
84
|
def initialize(domain:, **given)
|
|
73
85
|
KeywordFields.assign(self, KeywordFields.fill(given, FIELD_DEFAULTS))
|
|
74
86
|
@domain = domain.to_s
|
|
75
87
|
@bounded = @bounded ? true : false
|
|
76
88
|
@translates = Array(@translates).map(&:to_s)
|
|
89
|
+
@driving = Array(@driving).map(&:to_s)
|
|
77
90
|
end
|
|
78
91
|
|
|
79
92
|
# Says whether this hecksagon marked its own chapter `bounded`.
|
|
@@ -93,6 +106,13 @@ module Hecks
|
|
|
93
106
|
# @return [Boolean] whether that chapter is attached here
|
|
94
107
|
def attaches?(chapter) = member_chapters.include?(chapter.to_s)
|
|
95
108
|
|
|
109
|
+
# Says whether a driving adapter may reach this hecksagon's domain: every adapter may when
|
|
110
|
+
# none is declared, and only the declared ones may once any is.
|
|
111
|
+
#
|
|
112
|
+
# @param adapter [String, Symbol] a driving adapter's name, such as `"Mcp"`
|
|
113
|
+
# @return [Boolean] whether `driven_by` admits that adapter
|
|
114
|
+
def driven_by?(adapter) = driving.empty? || driving.include?(adapter.to_s)
|
|
115
|
+
|
|
96
116
|
# The vendored packages this hecksagon attaches.
|
|
97
117
|
#
|
|
98
118
|
# @return [Array<String>] their directory names, in the order they were attached
|
|
@@ -32,19 +32,38 @@ module Hecks
|
|
|
32
32
|
field: -> { field.to_s },
|
|
33
33
|
default: :default,
|
|
34
34
|
# `expand` is private; a Proc runs in the construct's own context, so it can reach it.
|
|
35
|
-
transitions: -> { transitions.flat_map { |command, t| expand(command, t) } }
|
|
35
|
+
transitions: -> { transitions.flat_map { |command, t| expand(command, t) } },
|
|
36
|
+
# Dropped from `to_h` when empty (see below), so an unmarked lifecycle's IR is unchanged.
|
|
37
|
+
marks: :marks
|
|
36
38
|
)
|
|
37
39
|
|
|
38
|
-
attr_reader :field, :default, :transitions
|
|
40
|
+
attr_reader :field, :default, :transitions, :marks
|
|
39
41
|
|
|
40
42
|
# @param field [Symbol, String] the attribute this state machine lives on
|
|
41
43
|
# @param default [String, Symbol] the state a new record starts in
|
|
42
44
|
# @param transitions [Array<Array(String, Bluebook::StateTransition)>] each declared
|
|
43
45
|
# `command name, StateTransition` pair, in declaration order
|
|
44
|
-
|
|
46
|
+
# @param marks [Hash{String, Symbol => Array<String, Symbol>}] each named meaning and the
|
|
47
|
+
# states that carry it, such as `holds_seat => ["pending", "succeeded"]`
|
|
48
|
+
def initialize(field:, default:, transitions: [], marks: {})
|
|
45
49
|
@field = field.to_sym
|
|
46
50
|
@default = default.to_s
|
|
47
51
|
@transitions = transitions
|
|
52
|
+
@marks = marks.to_h { |name, states| [name.to_s, Array(states).map(&:to_s)] }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# The states a named meaning marks.
|
|
56
|
+
#
|
|
57
|
+
# @param name [String, Symbol] the mark, such as `:holds_seat`
|
|
58
|
+
# @return [Array<String>, nil] the states in declared order, or nil when no such mark
|
|
59
|
+
def marked(name) = marks[name.to_s]
|
|
60
|
+
|
|
61
|
+
# `marks` is left out when the lifecycle declares none, so IR written before the word
|
|
62
|
+
# existed stays byte-identical.
|
|
63
|
+
def to_h
|
|
64
|
+
row = super
|
|
65
|
+
row.delete(:marks) if marks.empty?
|
|
66
|
+
row
|
|
48
67
|
end
|
|
49
68
|
end
|
|
50
69
|
end
|
|
@@ -3,6 +3,9 @@ module Hecks
|
|
|
3
3
|
module MetaValidator
|
|
4
4
|
# Offers a built .adapter to the self-hosted adapter language (adapter.bluebook).
|
|
5
5
|
class AdapterJudge
|
|
6
|
+
# Marks a field with no declared default; `nil` and `false` are defaults too.
|
|
7
|
+
NONE = Object.new.freeze
|
|
8
|
+
|
|
6
9
|
attr_reader :refusals
|
|
7
10
|
|
|
8
11
|
# @param adapter [Bluebook::Adapter] the built adapter to judge
|
|
@@ -34,10 +37,19 @@ module Hecks
|
|
|
34
37
|
|
|
35
38
|
def judge!
|
|
36
39
|
send_to("Adapter::Adapter.Declare", @adapter.name, name: v(@adapter.name), port: v(@adapter.port))
|
|
37
|
-
|
|
40
|
+
add_fields
|
|
38
41
|
add_all("AddSecret", @adapter.secrets)
|
|
39
42
|
end
|
|
40
43
|
|
|
44
|
+
# Offers one `AddField` per field, each with its declared default when it has one.
|
|
45
|
+
def add_fields
|
|
46
|
+
Array(@adapter.fields).each do |field|
|
|
47
|
+
default = @adapter.declared_defaults.fetch(field.to_sym, NONE)
|
|
48
|
+
send_to("Adapter::Adapter.AddField", @adapter.name, name: @adapter.name, value: v(field),
|
|
49
|
+
default: default.equal?(NONE) ? nil : v(default.inspect))
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
41
53
|
# Offers one `verb` per value, each addressed to the adapter by name.
|
|
42
54
|
def add_all(verb, values)
|
|
43
55
|
Array(values).each do |value|
|
|
@@ -4,6 +4,9 @@ module Hecks
|
|
|
4
4
|
# The mode switches of judging: bootstrapping, deferring, disabled, shadow-parsing and the
|
|
5
5
|
# forced fixpoint. `MetaValidator` extends this, so each reads and writes its own state.
|
|
6
6
|
module Modes
|
|
7
|
+
# Raised when a mode is asked for a builder that was never opened.
|
|
8
|
+
class Error < RuntimeError; end
|
|
9
|
+
|
|
7
10
|
# Whether the language's own grammar is still loading raw, unjudged.
|
|
8
11
|
# Judging it while it loads would recurse, so the bootstrap sets this
|
|
9
12
|
# and the fixpoint clears it once every grammar file is merged.
|
|
@@ -66,7 +69,7 @@ module Hecks
|
|
|
66
69
|
# Bare chapter-level givens must resolve before anything below
|
|
67
70
|
# reads a `Given`'s fields. The `raise` block never runs — this
|
|
68
71
|
# chapter's builder is always already open by the time `chapter` exists.
|
|
69
|
-
builder = registry.bluebook_builder(name) { raise "internal: no open builder for #{name}" }
|
|
72
|
+
builder = registry.bluebook_builder(name) { raise Error, "internal: no open builder for #{name}" }
|
|
70
73
|
builder.resolve_pending_chapter_givens!
|
|
71
74
|
# Same, one level down: entity-scoped pending givens.
|
|
72
75
|
builder.resolve_pending_chapter_entity_givens!
|
|
@@ -57,11 +57,25 @@ module Hecks
|
|
|
57
57
|
end
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
+
# A mark names several states, so it expands into one row per state, in declared order.
|
|
61
|
+
def mark_rows(node)
|
|
62
|
+
lifecycle = node.respond_to?(:lifecycle) ? node.lifecycle : nil
|
|
63
|
+
return [] unless lifecycle
|
|
64
|
+
|
|
65
|
+
lifecycle.marks.flat_map { |name, states| states.map { |state| { name: name, state: state } } }
|
|
66
|
+
end
|
|
67
|
+
|
|
60
68
|
# An open map has no value object to hold it, so each entry is its own row.
|
|
61
69
|
def pair_rows(map)
|
|
62
70
|
Array(map&.to_h).map { |key, value| { key: key, value: value } }
|
|
63
71
|
end
|
|
64
72
|
|
|
73
|
+
# A member's cells, each spelled so a quoted `"true"` stays a String and a bare `true` a
|
|
74
|
+
# boolean.
|
|
75
|
+
def member_pair_rows(map)
|
|
76
|
+
Array(map&.to_h).map { |key, value| { key: key, value: Assembly::Scalars.mark(value) } }
|
|
77
|
+
end
|
|
78
|
+
|
|
65
79
|
# Flattens options via `extra_options_to_h` — a new option needs no
|
|
66
80
|
# change here. `filters: true` reads wheres/order_by/limit live off
|
|
67
81
|
# the node, not `to_h`, so wire-format changes there don't affect it.
|
|
@@ -116,7 +130,16 @@ module Hecks
|
|
|
116
130
|
|
|
117
131
|
[{ target: mutation.target, op: mutation.op, field: mutation.target,
|
|
118
132
|
kind: classified[:kind],
|
|
119
|
-
source:
|
|
133
|
+
source: scalar_source_text(classified) }]
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# The one text a scalar mutation's source is stored as: an argument or state name, an
|
|
137
|
+
# expression's text, or an encoded literal.
|
|
138
|
+
def scalar_source_text(classified)
|
|
139
|
+
return classified[:name] if classified.key?(:name)
|
|
140
|
+
return classified[:text] if classified.key?(:text)
|
|
141
|
+
|
|
142
|
+
encode_literal(classified[:value])
|
|
120
143
|
end
|
|
121
144
|
|
|
122
145
|
# The columns of one canonical-form table entry, as the language declares them.
|
|
@@ -79,7 +79,8 @@ module Hecks
|
|
|
79
79
|
{
|
|
80
80
|
field: field,
|
|
81
81
|
default: text(row[:state_start]),
|
|
82
|
-
transitions: Array(row[:transitions]).map { |move| transition(move) }
|
|
82
|
+
transitions: Array(row[:transitions]).map { |move| transition(move) },
|
|
83
|
+
marks: Array(row[:marks]).map { |held| mark(held) }
|
|
83
84
|
}
|
|
84
85
|
end
|
|
85
86
|
end
|
|
@@ -41,11 +41,14 @@ module Hecks
|
|
|
41
41
|
# dispatched state, one member at a time, not behind a `DeclaredIn` query.
|
|
42
42
|
def members_row(row) = members_of(row)
|
|
43
43
|
|
|
44
|
-
# The key is stringified, never the value: a pair's value
|
|
45
|
-
#
|
|
44
|
+
# The key is stringified, never the value: a pair's value is read back from its text by
|
|
45
|
+
# `Assembly::Scalars`, so a quoted cell returns a String and `true`, `false` and numbers
|
|
46
|
+
# return as the builder holds them.
|
|
46
47
|
def members_of(value_object_row)
|
|
47
48
|
Array(value_object_row[:members]).map do |member|
|
|
48
|
-
Array(member[:pairs]).map
|
|
49
|
+
Array(member[:pairs]).map do |pair|
|
|
50
|
+
[text(pair[:key]).to_s, Assembly::Scalars.unmark(text(pair[:value]))]
|
|
51
|
+
end
|
|
49
52
|
end
|
|
50
53
|
end
|
|
51
54
|
|
|
@@ -86,6 +86,10 @@ module Hecks
|
|
|
86
86
|
}
|
|
87
87
|
end
|
|
88
88
|
|
|
89
|
+
def mark(row)
|
|
90
|
+
{ name: text(row[:name]), state: text(row[:state]) }
|
|
91
|
+
end
|
|
92
|
+
|
|
89
93
|
def head(row)
|
|
90
94
|
{
|
|
91
95
|
aggregate: text(row[:aggregate]),
|
|
@@ -140,6 +144,7 @@ module Hecks
|
|
|
140
144
|
value = text(binding[:source])
|
|
141
145
|
|
|
142
146
|
return { kind: kind, name: value } if %w[argument state].include?(kind)
|
|
147
|
+
return { kind: kind, text: value } if kind == "expression"
|
|
143
148
|
|
|
144
149
|
{ kind: "literal", value: decode_literal(value) }
|
|
145
150
|
end
|
|
@@ -34,7 +34,7 @@ module Hecks
|
|
|
34
34
|
# project, serve or deploy from a chapter, and nothing the judge runs
|
|
35
35
|
# calls into them. An edit there leaves every verdict as it was, so
|
|
36
36
|
# their files stay out of the key. Paths are relative to `lib/hecks`.
|
|
37
|
-
CONSUMER_TREES = %r{\A/hecks/(?:bench|cli|codemod|deploy|doc|
|
|
37
|
+
CONSUMER_TREES = %r{\A/hecks/(?:bench|cli|codemod|deploy|doc|adapters/driving|fuzzing|projections|
|
|
38
38
|
quality_control|release)(?:/|\.rb\z)}x
|
|
39
39
|
|
|
40
40
|
# Files older than this that do not match the current code digest are
|
|
@@ -15,7 +15,7 @@ module Hecks
|
|
|
15
15
|
GRAMMAR_FILES = Dir.glob(File.join(GRAMMAR_DIR, "*.bluebook")).freeze
|
|
16
16
|
WORLD_GRAMMAR = Dir.glob(File.expand_path("../language/world/*.bluebook", __dir__)).freeze
|
|
17
17
|
HECKSAGON_GRAMMAR = Dir.glob(File.expand_path("../language/hecksagon/*.bluebook", __dir__)).freeze
|
|
18
|
-
# Backs PortJudge, the same
|
|
18
|
+
# Backs PortJudge, the same entry point shape as WorldJudge.
|
|
19
19
|
PORT_GRAMMAR = File.expand_path("../language/port.bluebook", __dir__).freeze
|
|
20
20
|
# Backs AdapterJudge, one file over.
|
|
21
21
|
ADAPTER_GRAMMAR = File.expand_path("../language/adapter.bluebook", __dir__).freeze
|
|
@@ -41,42 +41,42 @@ module Hecks
|
|
|
41
41
|
# verdict Hash for a chapter
|
|
42
42
|
def self.verdicts = @verdicts ||= VerdictCache.seed
|
|
43
43
|
|
|
44
|
-
# Judges `world` through the meta-domain's own `WorldJudge`
|
|
44
|
+
# Judges `world` through the meta-domain's own `WorldJudge` entry point.
|
|
45
45
|
#
|
|
46
46
|
# @param world [Bluebook::World] the world to judge
|
|
47
47
|
# @return [Bluebook::World] `world` unchanged, if well formed or
|
|
48
48
|
# while disabled/bootstrapping/shadow-parsing
|
|
49
49
|
# @raise [DSL::Malformed] if `WorldJudge` finds `world` malformed
|
|
50
50
|
def self.call_world(world)
|
|
51
|
-
|
|
51
|
+
judge_artifact(world, WorldJudge, "#{world.domain}'s world") do
|
|
52
52
|
JSON.generate([world.domain, world.realm, world.latest, world.settings])
|
|
53
53
|
end
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
-
# Judges `port` through the meta-domain's own `PortJudge`
|
|
56
|
+
# Judges `port` through the meta-domain's own `PortJudge` entry point.
|
|
57
57
|
#
|
|
58
58
|
# @param port [Bluebook::Port] the port to judge
|
|
59
59
|
# @return [Bluebook::Port] `port` unchanged, if well formed or while
|
|
60
60
|
# disabled/bootstrapping/shadow-parsing
|
|
61
61
|
# @raise [DSL::Malformed] if `PortJudge` finds `port` malformed
|
|
62
62
|
def self.call_port(port)
|
|
63
|
-
|
|
63
|
+
judge_artifact(port, PortJudge, "#{port.name}'s port") { JSON.generate([port.name, port.verb, port.signal]) }
|
|
64
64
|
end
|
|
65
65
|
|
|
66
|
-
# Judges `adapter` through the meta-domain's own `AdapterJudge`
|
|
66
|
+
# Judges `adapter` through the meta-domain's own `AdapterJudge` entry point.
|
|
67
67
|
#
|
|
68
68
|
# @param adapter [Bluebook::Adapter] the adapter to judge
|
|
69
69
|
# @return [Bluebook::Adapter] `adapter` unchanged, if well formed or
|
|
70
70
|
# while disabled/bootstrapping/shadow-parsing
|
|
71
71
|
# @raise [DSL::Malformed] if `AdapterJudge` finds `adapter` malformed
|
|
72
72
|
def self.call_adapter(adapter)
|
|
73
|
-
|
|
74
|
-
JSON.generate([adapter.name, adapter.port, adapter.fields, adapter.secrets])
|
|
73
|
+
judge_artifact(adapter, AdapterJudge, "#{adapter.name}'s adapter") do
|
|
74
|
+
JSON.generate([adapter.name, adapter.port, adapter.fields, adapter.secrets, adapter.declared_defaults])
|
|
75
75
|
end
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
# Judges `translation` through the meta-domain's own `TranslationJudge`
|
|
79
|
-
#
|
|
79
|
+
# entry point, walking every nested aggregate's own rule table in one pass.
|
|
80
80
|
#
|
|
81
81
|
# `Translation` has no `.to_h`; `.inspect` embeds an object-id, so
|
|
82
82
|
# structurally-identical translations never cache-hit here (a lost
|
|
@@ -88,10 +88,10 @@ module Hecks
|
|
|
88
88
|
# @raise [DSL::Malformed] if `TranslationJudge` finds `translation`
|
|
89
89
|
# malformed
|
|
90
90
|
def self.call_translation(translation)
|
|
91
|
-
|
|
91
|
+
judge_artifact(translation, TranslationJudge, "#{translation.domain}'s translation") { translation.inspect }
|
|
92
92
|
end
|
|
93
93
|
|
|
94
|
-
# The one
|
|
94
|
+
# The one entry point every artifact but a chapter goes through: skip while judging is off,
|
|
95
95
|
# else judge once per distinct `key_text` and refuse a malformed artifact.
|
|
96
96
|
#
|
|
97
97
|
# @param subject [Object] the artifact to judge
|
|
@@ -100,7 +100,7 @@ module Hecks
|
|
|
100
100
|
# @yieldreturn [String] the text whose SHA-256 digest keys the verdict
|
|
101
101
|
# @return [Object] `subject` unchanged, if well formed or while judging is off
|
|
102
102
|
# @raise [DSL::Malformed] if `judge` finds `subject` malformed
|
|
103
|
-
def self.
|
|
103
|
+
def self.judge_artifact(subject, judge, label)
|
|
104
104
|
return subject if disabled? || bootstrapping? || shadow_parsing?
|
|
105
105
|
|
|
106
106
|
key = Digest::SHA256.hexdigest(yield)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
require_relative "../ask_resolution"
|
|
2
|
+
|
|
3
|
+
module Hecks
|
|
4
|
+
module Bluebook
|
|
5
|
+
module ModelCheck
|
|
6
|
+
# The checks over `ask`: one that resolves to no declared port operation, a port trigger
|
|
7
|
+
# that should be an ask, and a declared ask no policy reaches.
|
|
8
|
+
module AskChecks
|
|
9
|
+
# @param bluebook [Bluebook::Chapter] the chapter the policy is declared in
|
|
10
|
+
# @param policy [Bluebook::Policy] the policy to check
|
|
11
|
+
# @return [Finding, nil] an error for an `ask` that names no declared ask (or an
|
|
12
|
+
# ambiguous one), a warning for a `trigger` that names a port operation, else `nil`
|
|
13
|
+
def ask_finding(bluebook, policy)
|
|
14
|
+
return port_trigger_finding(bluebook, policy) unless policy.asks?
|
|
15
|
+
|
|
16
|
+
outcome = AskResolution.call(bluebook, policy)
|
|
17
|
+
return if outcome.resolved?
|
|
18
|
+
|
|
19
|
+
Finding.new(kind: :unresolved_ask, severity: :error, subject: policy.name, message: outcome.detail)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# A port operation no policy reaches, by `ask` or by a trigger that names it.
|
|
23
|
+
#
|
|
24
|
+
# @param bluebook [Bluebook::Chapter] the chapter whose aggregates declare the ports
|
|
25
|
+
# @return [Array<Finding>] one warning per outbound operation nothing asks
|
|
26
|
+
def unused_ask_findings(bluebook)
|
|
27
|
+
reached = reached_port_verbs(bluebook)
|
|
28
|
+
bluebook.aggregates.flat_map do |aggregate|
|
|
29
|
+
outbound_operations(aggregate).filter_map do |port, operation|
|
|
30
|
+
verb = "#{aggregate.hecks_name}.#{port.name}.#{operation.hecks_name}"
|
|
31
|
+
next if reached.include?(Naming.split_verb("#{bluebook.name}::#{verb}"))
|
|
32
|
+
|
|
33
|
+
Finding.new(kind: :unused_ask, severity: :warning, subject: verb,
|
|
34
|
+
message: "the hecksagon declares this ask but no policy asks it")
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def port_trigger_finding(bluebook, policy)
|
|
42
|
+
return unless port_operation_verb?(bluebook, policy.trigger_command)
|
|
43
|
+
|
|
44
|
+
Finding.new(kind: :port_trigger, severity: :warning, subject: policy.name,
|
|
45
|
+
message: "trigger #{policy.trigger_command.inspect} names a port operation — " \
|
|
46
|
+
"write `ask :#{Naming.snake(policy.trigger_command.to_s.split(".").last)}` and " \
|
|
47
|
+
"let the hecksagon map the port")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def port_operation_verb?(bluebook, verb)
|
|
51
|
+
qualified = Naming.split_verb("#{bluebook.name}::#{verb}")
|
|
52
|
+
!qualified.nil? && port_verbs_of(bluebook).any? { |held| Naming.split_verb(held) == qualified }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def reached_port_verbs(bluebook)
|
|
56
|
+
from_policies = bluebook.policies.map { |policy| policy.trigger_command.to_s }
|
|
57
|
+
from_sagas = bluebook.process_managers.flat_map do |manager|
|
|
58
|
+
manager.handlers.flat_map { |handler| handler.dispatches.map(&:command_name) }
|
|
59
|
+
end
|
|
60
|
+
(from_policies + from_sagas).to_set { |verb| Naming.split_verb("#{bluebook.name}::#{verb}") }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def outbound_operations(aggregate)
|
|
64
|
+
aggregate.ports.flat_map do |port|
|
|
65
|
+
port.operations.select(&:outbound?).map { |operation| [port, operation] }
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -11,7 +11,8 @@ module Hecks
|
|
|
11
11
|
|
|
12
12
|
[
|
|
13
13
|
deaf_policy_finding(policy, emitted_events(bluebook), global_emitted_events),
|
|
14
|
-
unknown_trigger_finding(bluebook, policy)
|
|
14
|
+
policy.asks? ? nil : unknown_trigger_finding(bluebook, policy),
|
|
15
|
+
ask_finding(bluebook, policy)
|
|
15
16
|
].compact
|
|
16
17
|
end
|
|
17
18
|
|