hecks 3.10.0 → 3.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/examples/pizzas/bluebook/pizzas.bluebook +29 -0
- data/examples/pizzas/bluebook/pizzas.hecksagon +7 -0
- data/exe/hecks +4 -4
- data/lib/hecks/adapters/driven/d1.rb +2 -10
- data/lib/hecks/adapters/driven/heki.adapter +1 -1
- data/lib/hecks/adapters/driven/heki.rb +2 -12
- data/lib/hecks/adapters/driven/lambda.adapter +1 -1
- data/lib/hecks/adapters/driven/lambda.rb +3 -18
- data/lib/hecks/adapters/driven/postgres.rb +4 -11
- data/lib/hecks/adapters/driven/sqlite.adapter +1 -1
- data/lib/hecks/adapters/driven/sqlite.rb +2 -10
- data/lib/hecks/adapters/driving/admission.rb +46 -0
- data/lib/hecks/adapters/driving/cli/nesting.rb +36 -0
- data/lib/hecks/adapters/driving/cli/shorthand.rb +88 -0
- data/lib/hecks/adapters/driving/cli.rb +127 -0
- data/lib/hecks/adapters/driving/cli_runner/answers.rb +160 -0
- data/lib/hecks/adapters/driving/cli_runner/resolution.rb +155 -0
- data/lib/hecks/adapters/driving/cli_runner/settling.rb +120 -0
- data/lib/hecks/adapters/driving/cli_runner/streaming.rb +93 -0
- data/lib/hecks/adapters/driving/cli_runner/suggestions.rb +47 -0
- data/lib/hecks/adapters/driving/cli_runner.rb +69 -0
- data/lib/hecks/adapters/driving/command_request.rb +121 -0
- data/lib/hecks/adapters/driving/handle.rb +214 -0
- data/lib/hecks/adapters/driving/json.rb +136 -0
- data/lib/hecks/adapters/driving/launcher_options.rb +267 -0
- data/lib/hecks/adapters/driving/mcp/properties.rb +49 -0
- data/lib/hecks/adapters/driving/mcp/tool_calls.rb +116 -0
- data/lib/hecks/adapters/driving/mcp/tool_definitions/auditing.rb +53 -0
- data/lib/hecks/adapters/driving/mcp/tool_definitions/calling.rb +71 -0
- data/lib/hecks/adapters/driving/mcp/tool_definitions/reading.rb +99 -0
- data/lib/hecks/adapters/driving/mcp/tool_definitions.rb +18 -0
- data/lib/hecks/adapters/driving/mcp.rb +159 -0
- data/lib/hecks/adapters/driving/mcp_guide_cache.rb +78 -0
- data/lib/hecks/adapters/driving/mcp_scope/argument_policy.rb +97 -0
- data/lib/hecks/adapters/driving/mcp_scope/env_problems.rb +69 -0
- data/lib/hecks/adapters/driving/mcp_scope/presenter.rb +83 -0
- data/lib/hecks/adapters/driving/mcp_scope.rb +213 -0
- data/lib/hecks/adapters/driving/ruby/aggregate_module.rb +171 -0
- data/lib/hecks/adapters/driving/ruby/chapter.rb +91 -0
- data/lib/hecks/adapters/driving/ruby.rb +83 -0
- data/lib/hecks/adapters/driving/usage_cache.rb +144 -0
- data/lib/hecks/{doors.rb → adapters/driving.rb} +10 -6
- data/lib/hecks/behaviors/expectations/boot.rb +1 -1
- data/lib/hecks/bench/ruby_runner.rb +1 -1
- data/lib/hecks/bluebook/ask_resolution.rb +130 -0
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +8 -2
- data/lib/hecks/bluebook/assembly/contracts/rules.rb +4 -2
- data/lib/hecks/bluebook/assembly/contracts/structure.rb +3 -1
- data/lib/hecks/bluebook/assembly/marks.rb +1 -0
- data/lib/hecks/bluebook/attribute.rb +1 -1
- data/lib/hecks/bluebook/behaviour/command.rb +13 -8
- data/lib/hecks/bluebook/behaviour/policy.rb +30 -0
- data/lib/hecks/bluebook/capabilities/attribute_values.rb +72 -0
- data/lib/hecks/bluebook/capabilities.rb +91 -9
- data/lib/hecks/bluebook/domain_port.rb +16 -4
- data/lib/hecks/bluebook/dsl/adapter_builder.rb +18 -6
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +13 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/computed_sources.rb +98 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/fan_out_rows.rb +42 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/projected_fields.rb +14 -2
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/provisions.rb +69 -3
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/with_projections.rb +17 -10
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +5 -0
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +2 -0
- data/lib/hecks/bluebook/dsl/command_builder/mutations.rb +8 -1
- data/lib/hecks/bluebook/dsl/command_builder/operands.rb +121 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +2 -0
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +10 -1
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +45 -2
- data/lib/hecks/bluebook/dsl/policy_builder.rb +47 -10
- data/lib/hecks/bluebook/dsl/rule_reference.rb +7 -4
- data/lib/hecks/bluebook/dsl/world_builder.rb +1 -1
- data/lib/hecks/bluebook/expression/ast_json/emitters.rb +6 -0
- data/lib/hecks/bluebook/expression/ast_json.rb +9 -6
- data/lib/hecks/bluebook/expression/ast_reader.rb +14 -9
- data/lib/hecks/bluebook/expression/projection.json +36 -0
- data/lib/hecks/bluebook/expression/resolver/operations.rb +31 -0
- data/lib/hecks/bluebook/expression/resolver/parsing.rb +38 -5
- data/lib/hecks/bluebook/expression/resolver/scanning.rb +22 -5
- data/lib/hecks/bluebook/expression/resolver/values.rb +10 -0
- data/lib/hecks/bluebook/expression/resolver.rb +20 -1
- data/lib/hecks/bluebook/hecksagon.rb +23 -3
- data/lib/hecks/bluebook/lifecycle.rb +22 -3
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +13 -1
- data/lib/hecks/bluebook/meta_validator/modes.rb +4 -1
- data/lib/hecks/bluebook/meta_validator/readings.rb +18 -1
- data/lib/hecks/bluebook/meta_validator/reconstruction/heads.rb +2 -1
- data/lib/hecks/bluebook/meta_validator/shapes.rb +5 -0
- data/lib/hecks/bluebook/meta_validator/verdict_cache.rb +1 -1
- data/lib/hecks/bluebook/meta_validator.rb +12 -12
- data/lib/hecks/bluebook/model_check/ask_checks.rb +71 -0
- data/lib/hecks/bluebook/model_check/policy_checks.rb +2 -1
- data/lib/hecks/bluebook/model_check/reference_checks.rb +70 -0
- data/lib/hecks/bluebook/model_check.rb +8 -2
- data/lib/hecks/bluebook/policy.rb +4 -2
- data/lib/hecks/bluebook/smoke_test.rb +1 -1
- data/lib/hecks/bluebook/synthesizer.rb +2 -0
- data/lib/hecks/bluebook.rb +1 -0
- data/lib/hecks/cli/command_table.rb +1 -1
- data/lib/hecks/cli/console.rb +2 -1
- data/lib/hecks/cli/document.rb +1 -1
- data/lib/hecks/cli/launcher_words.rb +4 -4
- data/lib/hecks/cli/mcp.rb +4 -4
- data/lib/hecks/cli/project_cli/launcher_source.rb +2 -2
- data/lib/hecks/cli/project_cli/templates.rb +5 -5
- data/lib/hecks/cli/project_cli.rb +9 -6
- data/lib/hecks/cli/run.rb +2 -2
- data/lib/hecks/cli/smoke_http/checks.rb +4 -1
- data/lib/hecks/cli/smoke_http/transport.rb +3 -3
- data/lib/hecks/cli/smoke_http.rb +3 -0
- data/lib/hecks/codemod.rb +5 -2
- data/lib/hecks/corpus/routes.rb +7 -0
- data/lib/hecks/corpus/rust.rb +3 -2
- data/lib/hecks/deploy/bluebook/deploy.bluebook +18 -2
- data/lib/hecks/doc/reference/rendering.rb +6 -3
- data/lib/hecks/forms/app/commands.rb +8 -7
- data/lib/hecks/forms/app/queries.rb +2 -1
- data/lib/hecks/forms/app.rb +1 -1
- data/lib/hecks/forms/record_renderer.rb +1 -1
- data/lib/hecks/framework/bluebook/privacy.bluebook +11 -0
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +4 -1
- data/lib/hecks/fuzzing/failure_triage.rb +2 -1
- data/lib/hecks/fuzzing/mutation/run.rb +11 -4
- data/lib/hecks/fuzzing/properties/catalog.rb +6 -4
- data/lib/hecks/fuzzing/properties/guaranteed_by_construction.rb +18 -11
- data/lib/hecks/fuzzing/properties/guards.rb +1 -1
- data/lib/hecks/fuzzing/self_consistency/saga_redelivery.rb +1 -1
- data/lib/hecks/fuzzing/self_consistency.rb +6 -2
- data/lib/hecks/fuzzing/shrinker.rb +3 -1
- data/lib/hecks/fuzzing/value_generator.rb +19 -5
- data/lib/hecks/gate/stages.yml +4 -10
- data/lib/hecks/grammar/evolve.rb +1 -1
- data/lib/hecks/grammar/expression_operators.json +372 -0
- data/lib/hecks/grammar/operators.rb +3 -1
- data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +10 -10
- data/lib/hecks/hecks/adapters/codebase/inspection/rubycritic.rb +35 -0
- data/lib/hecks/hecks/adapters/codebase/inspection.rb +104 -0
- data/lib/hecks/hecks/adapters/codebase/publishing.rb +2 -1
- data/lib/hecks/hecks/adapters/codebase/release_facts.rb +12 -2
- data/lib/hecks/hecks/adapters/codebase/source_tree.rb +2 -1
- data/lib/hecks/hecks/adapters/codebase/test_runner.rb +1 -1
- data/lib/hecks/hecks/adapters/cost_explorer.rb +8 -5
- data/lib/hecks/hecks/adapters/deploy_toolchain/statuses.rb +2 -1
- data/lib/hecks/hecks/adapters/finding_github.rb +13 -6
- data/lib/hecks/hecks/adapters/first_admin.rb +2 -2
- data/lib/hecks/hecks/adapters/github_rulesets.rb +6 -3
- data/lib/hecks/hecks/adapters/in_process_boot.rb +1 -1
- data/lib/hecks/hecks/adapters/journal_store/compaction.rb +1 -1
- data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +10 -20
- data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +28 -5
- data/lib/hecks/hecks/adapters/local_files.rb +2 -2
- data/lib/hecks/hecks/adapters/rehearsal/audit_report.rb +107 -0
- data/lib/hecks/hecks/adapters/rehearsal/census.rb +71 -0
- data/lib/hecks/hecks/adapters/rehearsal/declaration.rb +133 -0
- data/lib/hecks/hecks/adapters/rehearsal/environment.rb +83 -0
- data/lib/hecks/hecks/adapters/rehearsal/inquiry.rb +142 -0
- data/lib/hecks/hecks/adapters/rehearsal/memory_store.rb +96 -0
- data/lib/hecks/hecks/adapters/rehearsal/postgres_census.rb +100 -0
- data/lib/hecks/hecks/adapters/rehearsal/postgres_reading.rb +69 -0
- data/lib/hecks/hecks/adapters/rehearsal/postgres_store.rb +129 -0
- data/lib/hecks/hecks/adapters/rehearsal/rows.rb +41 -0
- data/lib/hecks/hecks/adapters/rehearsal/rust_audit.rb +83 -0
- data/lib/hecks/hecks/adapters/rehearsal/subject.rb +104 -0
- data/lib/hecks/hecks/adapters/rehearsal.rb +54 -0
- data/lib/hecks/hecks/adapters/rehearsal_store.adapter +7 -0
- data/lib/hecks/hecks/adapters/rehearsal_store.rb +81 -0
- data/lib/hecks/hecks/adapters/terminal.rb +13 -11
- data/lib/hecks/hecks/codebase.behaviors +13 -1
- data/lib/hecks/hecks/codebase.bluebook +239 -5
- data/lib/hecks/hecks/custodian.behaviors +24 -6
- data/lib/hecks/hecks/custodian.bluebook +6 -1227
- data/lib/hecks/hecks/deploy.behaviors +1 -1
- data/lib/hecks/hecks/deploy.world +1 -3
- data/lib/hecks/hecks/hecks.behaviors +1 -1
- data/lib/hecks/hecks/hecks.hecksagon +53 -18
- data/lib/hecks/hecks/hecks.world +10 -10
- data/lib/hecks/hecks/rehearsal.bluebook +477 -0
- data/lib/hecks/hecks/site.behaviors +1 -1
- data/lib/hecks/hecks/site.world +0 -1
- data/lib/hecks/hecks/tooling.bluebook +1238 -0
- data/lib/hecks/indifferent_key.rb +20 -0
- data/lib/hecks/language/adapter.bluebook +13 -3
- data/lib/hecks/language/bluebook/aggregate.bluebook +23 -0
- data/lib/hecks/language/bluebook/bluebook.bluebook +15 -0
- data/lib/hecks/language/bluebook/entity.bluebook +18 -0
- data/lib/hecks/language/bluebook/policy.bluebook +9 -1
- data/lib/hecks/language/bluebook/query.bluebook +1 -1
- data/lib/hecks/language/bluebook/vocabulary.bluebook +11 -4
- data/lib/hecks/language/hecksagon/domain_port.bluebook +1 -1
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +22 -0
- data/lib/hecks/language/oidc.json +10 -0
- data/lib/hecks/language/port.bluebook +4 -4
- data/lib/hecks/literal.rb +12 -3
- data/lib/hecks/ports/key_vault.rb +7 -2
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +21 -10
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/boot.rb +4 -2
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +2 -1
- data/lib/hecks/ports/persistence/repository_factory.rb +6 -3
- data/lib/hecks/projections/deploy/box/templates/deploy-box.sh.tmpl +29 -0
- data/lib/hecks/projections/deploy/box/templates/deploy-service.sh.tmpl +1 -1
- data/lib/hecks/projections/deploy/preview/preview.sh.erb +1 -1
- data/lib/hecks/projections/deploy/shared.rb +5 -2
- data/lib/hecks/projections/model/deviations.rb +2 -2
- data/lib/hecks/projections/model.rb +2 -2
- data/lib/hecks/projections/oidc.rb +13 -1
- data/lib/hecks/projections/shape.rb +5 -2
- data/lib/hecks/projections/site/cms_editor/attributes.rb +26 -6
- data/lib/hecks/projections/site/cms_editor/blocks.rb +157 -0
- data/lib/hecks/projections/site/cms_editor/checks.rb +14 -1
- data/lib/hecks/projections/site/cms_editor/clearing.rb +70 -0
- data/lib/hecks/projections/site/cms_editor/color.rb +124 -0
- data/lib/hecks/projections/site/cms_editor/composition.rb +42 -0
- data/lib/hecks/projections/site/cms_editor/destructive.rb +61 -0
- data/lib/hecks/projections/site/cms_editor/drafts.rb +102 -0
- data/lib/hecks/projections/site/cms_editor/hints.rb +74 -0
- data/lib/hecks/projections/site/cms_editor/icons.rb +86 -0
- data/lib/hecks/projections/site/cms_editor/key_kinds.rb +31 -0
- data/lib/hecks/projections/site/cms_editor/limits.rb +72 -0
- data/lib/hecks/projections/site/cms_editor/media.rb +1 -1
- data/lib/hecks/projections/site/cms_editor/moment.rb +34 -0
- data/lib/hecks/projections/site/cms_editor/palette.rb +115 -0
- data/lib/hecks/projections/site/cms_editor/pickers.rb +85 -0
- data/lib/hecks/projections/site/cms_editor/preview.rb +91 -0
- data/lib/hecks/projections/site/cms_editor/relations.rb +92 -0
- data/lib/hecks/projections/site/cms_editor/scale_checks.rb +66 -0
- data/lib/hecks/projections/site/cms_editor/scheduling.rb +150 -0
- data/lib/hecks/projections/site/cms_editor/schema.rb +96 -19
- data/lib/hecks/projections/site/cms_editor/setting.rb +52 -9
- data/lib/hecks/projections/site/cms_editor/targets.rb +86 -0
- data/lib/hecks/projections/site/cms_editor/templates/package.json.tmpl +18 -1
- data/lib/hecks/projections/site/cms_editor/templates/src/app.ts.tmpl +251 -57
- data/lib/hecks/projections/site/cms_editor/templates/src/assets.ts.tmpl +98 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/auth/membership.ts.tmpl +32 -24
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/app.css.tmpl +412 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/autosave.js.tmpl +144 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/blocks.js.tmpl +500 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/body_doc.js.tmpl +175 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/body_editor.js.tmpl +418 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/epoch.js.tmpl +61 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/forms.js.tmpl +210 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/lists.js.tmpl +40 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/main.js.tmpl +26 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/media_picker.js.tmpl +232 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/moments.js.tmpl +73 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/pickers.js.tmpl +152 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/preview.js.tmpl +98 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/shell.js.tmpl +140 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/toast.js.tmpl +66 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/choices.ts.tmpl +99 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/commands.ts.tmpl +78 -24
- data/lib/hecks/projections/site/cms_editor/templates/src/config.ts.tmpl +6 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/flash.ts.tmpl +52 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/host.ts.tmpl +19 -2
- data/lib/hecks/projections/site/cms_editor/templates/src/media/handler.ts.tmpl +31 -8
- data/lib/hecks/projections/site/cms_editor/templates/src/names.ts.tmpl +36 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/schema.ts.tmpl +131 -2
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/availability.ts.tmpl +15 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/block_list.js.tmpl +213 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/blocks.ts.tmpl +275 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/body_model.js.tmpl +8 -5
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/detail.ts.tmpl +88 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/dialogs.ts.tmpl +43 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/fields.ts.tmpl +229 -34
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/html.ts.tmpl +40 -81
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/icons.ts.tmpl +15 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/input.ts.tmpl +29 -12
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/links.ts.tmpl +100 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/moments.ts.tmpl +44 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/outline.ts.tmpl +53 -17
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/pages.ts.tmpl +178 -88
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/paging.ts.tmpl +82 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/pickers.ts.tmpl +110 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/preview.ts.tmpl +87 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/related.ts.tmpl +97 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/schedule.ts.tmpl +160 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/shell.ts.tmpl +211 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/table.ts.tmpl +151 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/theme.js.tmpl +16 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/values.ts.tmpl +69 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/words.ts.tmpl +97 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/world.ts.tmpl +35 -0
- data/lib/hecks/projections/site/cms_editor/templates/tsconfig.json.tmpl +2 -1
- data/lib/hecks/projections/site/cms_editor/theme.rb +29 -0
- data/lib/hecks/projections/site/cms_editor/theme_checks.rb +57 -0
- data/lib/hecks/projections/site/cms_editor.rb +49 -23
- data/lib/hecks/projections/site/role_probe.rb +2 -0
- data/lib/hecks/projector/cli_audience.rb +2 -1
- data/lib/hecks/projector/cli_projector/listing.rb +1 -1
- data/lib/hecks/projector/cli_projector/option_specs.rb +1 -1
- data/lib/hecks/projector/docs_projector/closing.rb +1 -1
- data/lib/hecks/projector/docs_projector.rb +1 -1
- data/lib/hecks/projector/exporter/bindings.rb +40 -10
- data/lib/hecks/projector/exporter/capability_values.rb +55 -0
- data/lib/hecks/projector/narrate_projector/reactions.rb +1 -1
- data/lib/hecks/projector/target.rb +11 -0
- data/lib/hecks/projector.rb +32 -5
- data/lib/hecks/quality_control/adapters/github_checks.rb +12 -8
- data/lib/hecks/quality_control/adapters/github_issues.rb +8 -4
- data/lib/hecks/quality_control/cli/qa_open_pr.rb +2 -2
- data/lib/hecks/quality_control/cli/qa_sweep/checks/shrinking.rb +1 -1
- data/lib/hecks/quality_control/cli/qa_sweep/finding_report.rb +1 -1
- data/lib/hecks/quality_control/cli/qa_sweep.rb +1 -1
- data/lib/hecks/quality_control/quality_control.bluebook +6 -2
- data/lib/hecks/release/approval.rb +64 -0
- data/lib/hecks/router/{door.rb → aggregate_reader.rb} +5 -4
- data/lib/hecks/router/namespace_installer.rb +16 -16
- data/lib/hecks/router.rb +1 -1
- data/lib/hecks/runtime/best_effort.rb +22 -0
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +12 -2
- data/lib/hecks/runtime/command_interpreter.rb +3 -2
- data/lib/hecks/runtime/command_rules/emission.rb +1 -1
- data/lib/hecks/runtime/dispatcher.rb +4 -4
- data/lib/hecks/runtime/entity_element/location.rb +1 -1
- data/lib/hecks/runtime/event.rb +5 -0
- data/lib/hecks/runtime/identity.rb +7 -6
- data/lib/hecks/runtime/interpreting.rb +2 -1
- data/lib/hecks/runtime/invocation_builder.rb +1 -1
- data/lib/hecks/runtime/loader/boot_steps.rb +8 -5
- data/lib/hecks/runtime/loader.rb +10 -10
- data/lib/hecks/runtime/policy_interpreter/arguments.rb +7 -4
- data/lib/hecks/runtime/policy_interpreter/fan_out.rb +3 -3
- data/lib/hecks/runtime/policy_interpreter.rb +6 -6
- data/lib/hecks/runtime/port_operation_interpreter.rb +1 -1
- data/lib/hecks/runtime/reaction_invocation.rb +1 -1
- data/lib/hecks/runtime/rebuild_sweep.rb +11 -1
- data/lib/hecks/runtime/registry/ask_verification.rb +35 -0
- data/lib/hecks/runtime/registry/hecksagon_rules.rb +10 -0
- data/lib/hecks/runtime/registry/merging.rb +1 -1
- data/lib/hecks/runtime/registry/providers.rb +16 -0
- data/lib/hecks/runtime/registry/read_repository.rb +6 -4
- data/lib/hecks/runtime/registry/verification.rb +4 -1
- data/lib/hecks/runtime/registry/world_defaults.rb +29 -0
- data/lib/hecks/runtime/registry.rb +1 -1
- data/lib/hecks/runtime/saga_interpreter/compensation.rb +1 -1
- data/lib/hecks/runtime/saga_interpreter/delivery.rb +4 -4
- data/lib/hecks/runtime/saga_interpreter/transitions.rb +1 -1
- data/lib/hecks/runtime/saga_interpreter.rb +3 -3
- data/lib/hecks/runtime/tenant_check.rb +5 -4
- data/lib/hecks/runtime/value/coercion.rb +2 -2
- data/lib/hecks/runtime/value/validation.rb +16 -4
- data/lib/hecks/runtime.rb +9 -9
- data/lib/hecks/rust_build/project_rust/target_ir.rb +1 -1
- data/lib/hecks/rust_build/wasm.rb +1 -1
- data/lib/hecks/rust_build/wasm_browser.rb +1 -1
- data/lib/hecks/rust_build.rb +11 -0
- data/lib/hecks/served_options.rb +53 -0
- data/lib/hecks/site/bluebook/site.bluebook +1 -0
- data/lib/hecks/storehouse/audit.rb +1 -1
- data/lib/hecks/storehouse/dispatching.rb +8 -6
- data/lib/hecks/storehouse/introspection.rb +2 -2
- data/lib/hecks/storehouse/querying.rb +6 -4
- data/lib/hecks/storehouse.rb +4 -4
- data/lib/hecks/tools/comment_style/source_file.rb +4 -1
- data/lib/hecks/tools/deploy_recipe_lint/fixtures.rb +4 -1
- data/lib/hecks/tools/lanes/rows.rb +6 -0
- data/lib/hecks/tools/oidc_manifests.rb +4 -5
- data/lib/hecks/tools/regeneration_run.rb +11 -4
- data/lib/hecks/tools/site_routes/editor_files.rb +12 -5
- data/lib/hecks/tools/tenant_provisioning.rb +2 -2
- data/lib/hecks/tools/tools_doc.rb +4 -4
- data/lib/hecks/version.rb +1 -1
- data/lib/hecks/vocabulary.rb +4 -4
- data/lib/hecks.rb +15 -15
- data/lib/rubocop/cop/hecks/env_dump.rb +69 -0
- data/lib/rubocop/cop/hecks/monotonic_duration.rb +53 -0
- data/lib/rubocop/cop/hecks/no_wall_clock_in_runtime.rb +34 -0
- data/lib/rubocop/cop/hecks/raw_shell_interpolation.rb +79 -0
- data/lib/rubocop/cop/hecks/sleep_in_spec.rb +34 -0
- data/lib/rubocop/cop/hecks/swallowed_rescue.rb +37 -0
- data/lib/rubocop/cop/hecks/symbol_string_key_mix.rb +50 -0
- data/lib/rubocop/cop/hecks/untyped_raise.rb +37 -0
- data/prebuilt/05c358d38d661a3774f813d49c66f5b68939af94432d66257a56f49ee2598994.marshal +0 -0
- data/prebuilt/26c40c61f09b09b11651c64668eda3ceb180f83cf2a3802d3033d2fd99ac841b.marshal +0 -0
- data/prebuilt/verdicts-230ac18c25abfd3d92ede032bee2661a4c2cd2773ab0cf0e2ae52546ba2f7af9.json +1 -0
- data/rust/.gitignore +6 -0
- data/rust/Cargo.toml +6 -0
- data/rust/build/src/binding_pass.rs +103 -0
- data/rust/build/src/cargo_sync.rs +6 -0
- data/rust/build/src/lineage_pass.rs +3 -3
- data/rust/build/src/main.rs +17 -5
- data/rust/build/src/pipeline.rs +48 -5
- data/rust/build/src/seams_pass.rs +123 -0
- data/rust/build/src/translation_pass.rs +167 -0
- data/rust/codegen/src/asks.rs +103 -0
- data/rust/codegen/src/commands.rs +13 -8
- data/rust/codegen/src/constraints.rs +25 -0
- data/rust/codegen/src/domain_generator.rs +2 -0
- data/rust/codegen/src/expr_emitter.rs +13 -0
- data/rust/codegen/src/json_codec.rs +54 -15
- data/rust/codegen/src/main.rs +1 -0
- data/rust/codegen/src/mutations.rs +128 -3
- data/rust/codegen/src/queries.rs +11 -2
- data/rust/codegen/src/reactions.rs +1 -1
- data/rust/codegen/src/types.rs +166 -8
- data/rust/host/HECKS_RELEASE +1 -1
- data/rust/host/src/api.rs +4 -4
- data/rust/host/src/bin/validate_harness.rs +43 -0
- data/rust/host/src/boundary_fuzz/expr_json.rs +2 -2
- data/rust/host/src/boundary_fuzz/ir.rs +1 -0
- data/rust/host/src/boundary_fuzz/server.rs +1 -1
- data/rust/host/src/checkout.rs +35 -19
- data/rust/host/src/commerce_ir.rs +408 -2
- data/rust/host/src/expr_json.rs +118 -0
- data/rust/host/src/mint.rs +1 -1
- data/rust/host/src/payments/tests.rs +27 -1
- data/rust/host/src/payments.rs +12 -4
- data/rust/host/src/query_step.rs +22 -4
- data/rust/host/src/reference_validate.rs +653 -108
- data/rust/host/src/resend.rs +2 -0
- data/rust/host/src/server.rs +19 -6
- data/rust/host/src/ui_schema.rs +132 -5
- data/rust/host/src/web/newsletter.rs +7 -8
- data/rust/host/src/web/newsletter_send.rs +38 -13
- data/rust/host/src/web/registrations.rs +229 -26
- data/rust/host/src/web.rs +3 -3
- data/rust/parser/src/emit.rs +38 -6
- data/rust/parser/src/expr/ast_json.rs +7 -1
- data/rust/parser/src/expr/resolver.rs +171 -6
- data/rust/parser/src/ir.rs +7 -0
- data/rust/parser/src/keywords.rs +24 -0
- data/rust/parser/src/main.rs +3 -0
- data/rust/parser/src/parse/aggregate.rs +2 -1
- data/rust/parser/src/parse/chapter.rs +2 -2
- data/rust/parser/src/parse/command.rs +2 -0
- data/rust/parser/src/parse/hecksagon.rs +5 -2
- data/rust/parser/src/parse/lifecycle.rs +81 -0
- data/rust/parser/src/parse/mod.rs +15 -1
- data/rust/parser/src/parse/policy.rs +13 -2
- data/rust/parser/src/parse/value_object.rs +13 -8
- data/rust/parser/src/ruby_value.rs +1 -1
- data/rust/src/exemplar/commands.rs +4 -4
- data/rust/src/exemplar/constraints.rs +1 -1
- data/rust/src/exemplar/json.rs +43 -1
- data/rust/src/kernel/cli.rs +7 -5
- data/rust/src/kernel/dispatch.rs +2 -2
- data/rust/src/kernel/dispatch_guard_tests.rs +1 -1
- data/rust/src/kernel/expr.rs +66 -3
- data/rust/src/kernel/expression_operators/arithmetic.rs +130 -5
- data/rust/src/kernel/expression_operators/text.rs +26 -2
- data/rust/src/kernel/json.rs +15 -0
- data/rust/src/kernel/mod.rs +1 -1
- data/rust/src/kernel/orchestrate.rs +54 -5
- data/rust/src/kernel/orchestrate_guard_tests.rs +67 -0
- data/rust/src/kernel/pattern.rs +60 -0
- data/rust/src/kernel/reference_lookup.rs +90 -7
- metadata +140 -38
- data/lib/hecks/doors/cli_door/nesting.rb +0 -34
- data/lib/hecks/doors/cli_door/shorthand.rb +0 -85
- data/lib/hecks/doors/cli_door.rb +0 -124
- data/lib/hecks/doors/cli_runner/answers.rb +0 -138
- data/lib/hecks/doors/cli_runner/resolution.rb +0 -146
- data/lib/hecks/doors/cli_runner/settling.rb +0 -115
- data/lib/hecks/doors/cli_runner/streaming.rb +0 -90
- data/lib/hecks/doors/cli_runner/suggestions.rb +0 -43
- data/lib/hecks/doors/cli_runner.rb +0 -66
- data/lib/hecks/doors/command_request.rb +0 -119
- data/lib/hecks/doors/handle.rb +0 -208
- data/lib/hecks/doors/json_door.rb +0 -132
- data/lib/hecks/doors/launcher_options.rb +0 -247
- data/lib/hecks/doors/mcp_door/properties.rb +0 -47
- data/lib/hecks/doors/mcp_door/tool_calls.rb +0 -113
- data/lib/hecks/doors/mcp_door/tool_definitions/auditing.rb +0 -51
- data/lib/hecks/doors/mcp_door/tool_definitions/calling.rb +0 -69
- data/lib/hecks/doors/mcp_door/tool_definitions/reading.rb +0 -97
- data/lib/hecks/doors/mcp_door/tool_definitions.rb +0 -15
- data/lib/hecks/doors/mcp_door.rb +0 -156
- data/lib/hecks/doors/mcp_door_scope/argument_policy.rb +0 -92
- data/lib/hecks/doors/mcp_door_scope/env_problems.rb +0 -55
- data/lib/hecks/doors/mcp_door_scope/presenter.rb +0 -78
- data/lib/hecks/doors/mcp_door_scope.rb +0 -201
- data/lib/hecks/doors/mcp_guide_cache.rb +0 -75
- data/lib/hecks/doors/ruby_door/aggregate_door.rb +0 -162
- data/lib/hecks/doors/ruby_door/chapter.rb +0 -89
- data/lib/hecks/doors/ruby_door.rb +0 -80
- data/lib/hecks/doors/usage_cache.rb +0 -139
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/body_widget.js.tmpl +0 -282
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/media_picker.js.tmpl +0 -109
- data/prebuilt/c28d6d9db14eea3e17161e9d9c262efee30b256cf97693a7cfd552bce24b2f7f.marshal +0 -0
- data/prebuilt/cb375cba61ca0dbe8ddb9739c306510fe05e5f4b7a9b6955caff8224c63ea0e0.marshal +0 -0
- data/prebuilt/verdicts-d6d584ad43b5f3cebf88aafbbdbf024c38574acf18e06adffbc555f7786b1c2f.json +0 -1
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
require_relative "../../bluebook/dsl/hecksagon_builder"
|
|
2
|
-
require_relative "../../bluebook/dsl/world_builder"
|
|
3
|
-
require_relative "../../bluebook/dsl/domain_port_builder"
|
|
4
|
-
require_relative "../../bluebook/dsl/const_shim"
|
|
5
|
-
require_relative "../../bluebook/dsl/binding_proxy"
|
|
6
|
-
require_relative "../../bluebook/hecksagon"
|
|
7
|
-
require_relative "../handle"
|
|
8
|
-
require_relative "../../naming"
|
|
9
|
-
|
|
10
|
-
module Hecks
|
|
11
|
-
module Doors
|
|
12
|
-
module RubyDoor
|
|
13
|
-
# One aggregate's door: creating verbs and queries as module methods, CRUD
|
|
14
|
-
# delegation, and the `.hecksagon` binding/port hooks it lands on.
|
|
15
|
-
module AggregateDoor
|
|
16
|
-
# Builds one aggregate's door module: creating-command methods, query methods,
|
|
17
|
-
# find/all/count/events, project/docs/narrate, and the port/binding hooks.
|
|
18
|
-
#
|
|
19
|
-
# Kept as one method: `:port`/`:method_missing`/`:const_missing` below
|
|
20
|
-
# cross-reference each other and would lose that thread if split up.
|
|
21
|
-
# rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
22
|
-
def aggregate_module(dispatcher, domain, aggregate)
|
|
23
|
-
fqn = "#{domain}::#{aggregate.hecks_name}"
|
|
24
|
-
door = Module.new
|
|
25
|
-
|
|
26
|
-
aggregate.attributes.each do |attribute|
|
|
27
|
-
next unless RESERVED.include?(attribute.name.to_sym)
|
|
28
|
-
|
|
29
|
-
warn "[hecks] #{aggregate.hecks_name}##{attribute.name} shadows a built-in — no reader defined"
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# `!` marks a creating command (Ruby's mutate-and-may-refuse convention).
|
|
33
|
-
# Without it, a query sharing the same business name (e.g. Account's
|
|
34
|
-
# "Open") would collide with the creating command's own bare name.
|
|
35
|
-
aggregate.commands.select(&:creates?).each do |command|
|
|
36
|
-
door.define_singleton_method("#{Naming.snake(command.hecks_name)}!") do |**args|
|
|
37
|
-
Handle.new(dispatcher: dispatcher, domain: domain, aggregate: aggregate,
|
|
38
|
-
instance: dispatcher.dispatch("#{fqn}.#{command.hecks_name}", with: args).instance)
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# A query is a bare module method (no `!`): it just reads and returns
|
|
43
|
-
# the same raw row array `dispatcher.query` itself answers.
|
|
44
|
-
aggregate.queries.each do |query|
|
|
45
|
-
door.define_singleton_method(Naming.snake(query.hecks_name)) do |**args|
|
|
46
|
-
dispatcher.query("#{fqn}.#{query.hecks_name}", **args)
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
door.define_singleton_method(:fqn) { fqn }
|
|
51
|
-
door.define_singleton_method(:ir) { aggregate }
|
|
52
|
-
|
|
53
|
-
# Every construct emits its own IR, so an aggregate is a legitimate
|
|
54
|
-
# `project` target too. A chapter-scoped target refuses here via
|
|
55
|
-
# `Projector.admits!` rather than answering a confidently empty result.
|
|
56
|
-
door.define_singleton_method(:project) do |target, out: nil, **options|
|
|
57
|
-
key = Projector.key_for(target)
|
|
58
|
-
artifact = Projector.call(key, bluebook: aggregate, options: options)
|
|
59
|
-
return artifact unless out
|
|
60
|
-
|
|
61
|
-
Projector.write(artifact, out, as: Projector.emits_for(key))
|
|
62
|
-
end
|
|
63
|
-
door.define_singleton_method(:repository) { dispatcher.registry.repository(domain, aggregate) }
|
|
64
|
-
door.define_singleton_method(:commands) do
|
|
65
|
-
aggregate.commands.map { |c| "#{Naming.snake(c.hecks_name)}!" }.sort
|
|
66
|
-
end
|
|
67
|
-
door.define_singleton_method(:queries) { aggregate.queries.map { |q| Naming.snake(q.hecks_name) }.sort }
|
|
68
|
-
# This chapter's own `:docs` projection, narrowed to this aggregate.
|
|
69
|
-
door.define_singleton_method(:docs) do |**options|
|
|
70
|
-
Projector.call(:docs, bluebook: dispatcher.registry.bluebook(domain),
|
|
71
|
-
options: options.merge(aggregate: aggregate.hecks_name))
|
|
72
|
-
end
|
|
73
|
-
# Same narrowing as `:docs`, aimed at `:narrate`.
|
|
74
|
-
door.define_singleton_method(:narrate) do |**options|
|
|
75
|
-
Projector.call(:narrate, bluebook: dispatcher.registry.bluebook(domain),
|
|
76
|
-
options: options.merge(aggregate: aggregate.hecks_name))
|
|
77
|
-
end
|
|
78
|
-
door.define_singleton_method(:count) { dispatcher.registry.repository(domain, aggregate).count }
|
|
79
|
-
door.define_singleton_method(:events) { dispatcher.events.select { |event| event.aggregate == fqn } }
|
|
80
|
-
|
|
81
|
-
door.define_singleton_method(:find) do |id|
|
|
82
|
-
found = dispatcher.registry.repository(domain, aggregate).find(id)
|
|
83
|
-
found && Handle.new(dispatcher: dispatcher, domain: domain, aggregate: aggregate, instance: found)
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
door.define_singleton_method(:all) do |**opts|
|
|
87
|
-
dispatcher.registry.repository(domain, aggregate).all(**opts).map do |instance|
|
|
88
|
-
Handle.new(dispatcher: dispatcher, domain: domain, aggregate: aggregate, instance: instance)
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
# Re-resolves via `Hecks.current_registry` rather than the closed-over
|
|
93
|
-
# `aggregate`: this door can be stale from an earlier boot, and its own
|
|
94
|
-
# `aggregate` would silently port a discarded one instead of the live one.
|
|
95
|
-
door.define_singleton_method(:port) do |name, &block|
|
|
96
|
-
current = Hecks.current_registry&.bluebook(domain)&.aggregate(aggregate.hecks_name) or
|
|
97
|
-
raise Bluebook::DSL::Malformed, "#{fqn}.port(#{name.inspect}) called outside a boot"
|
|
98
|
-
|
|
99
|
-
built = Bluebook::DSL::ConstShim.with(->(const) { const }) do
|
|
100
|
-
Bluebook::DSL::DomainPortBuilder.build(name, owner: current.hecks_name, &block)
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
# A `verb`-shaped port is a plain `Port`, the same struct `Hecks.port` registers —
|
|
104
|
-
# it belongs to no aggregate IR the way an operations-shaped `DomainPort` does, so
|
|
105
|
-
# it takes the registry's `add_port` directly. Mirrors `DSL::BindingProxy#port`,
|
|
106
|
-
# which handles the identical shape on a domain's first in-process boot (before
|
|
107
|
-
# this facade constant exists); this method is what a repeat boot reaches instead.
|
|
108
|
-
if built.is_a?(Bluebook::Port)
|
|
109
|
-
Hecks.current_registry.add_port(built)
|
|
110
|
-
return self
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
built.operations.each do |operation|
|
|
114
|
-
operation.attributes.select(&:reference?).each { |attribute| attribute.type.declared_in = current }
|
|
115
|
-
end
|
|
116
|
-
current.add_port(built)
|
|
117
|
-
self
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
door.define_singleton_method(:method_missing) do |verb, *args, **kwargs, &block|
|
|
121
|
-
# A bare call starts a Privacy marking chain (see
|
|
122
|
-
# `BindingProxy#method_missing`), reached here when the door is already
|
|
123
|
-
# installed (a second in-process boot) rather than at parse time.
|
|
124
|
-
return Bluebook::DSL::AttributePath.new(fqn, [verb.to_s]) if args.empty? && kwargs.empty? && !block
|
|
125
|
-
|
|
126
|
-
collector = Bluebook::DSL::HecksagonBuilder.collector
|
|
127
|
-
world = Bluebook::DSL::WorldBuilder.current
|
|
128
|
-
# Inside a `.world` block the same qualified spelling records a world setting.
|
|
129
|
-
return world.record_binding(verb, args, kwargs, block) if world && !collector
|
|
130
|
-
return super(verb, *args, **kwargs, &block) unless collector
|
|
131
|
-
|
|
132
|
-
collector << Bluebook::Bind.new(
|
|
133
|
-
aggregate: fqn,
|
|
134
|
-
verb: verb.to_s,
|
|
135
|
-
adapter: args.first.to_s,
|
|
136
|
-
role: kwargs[:role]&.to_s
|
|
137
|
-
)
|
|
138
|
-
block&.call
|
|
139
|
-
self
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
door.define_singleton_method(:respond_to_missing?) do |name, include_private = false|
|
|
143
|
-
!Bluebook::DSL::HecksagonBuilder.collector.nil? || !Bluebook::DSL::WorldBuilder.current.nil? ||
|
|
144
|
-
super(name, include_private)
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
# Uses `aggregate.hecks_name`, not the qualified `fqn`: qualifying it here
|
|
148
|
-
# would make `Account::Debit`'s meaning depend on whether a stale door
|
|
149
|
-
# from an earlier boot happens to be sitting on this process.
|
|
150
|
-
door.define_singleton_method(:const_missing) do |name|
|
|
151
|
-
resolver = Bluebook::DSL::ConstShim.resolver
|
|
152
|
-
return resolver.call("#{aggregate.hecks_name}::#{name}") if resolver
|
|
153
|
-
|
|
154
|
-
super(name)
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
door
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
end
|
|
161
|
-
end
|
|
162
|
-
end
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
require_relative "../../bluebook/dsl/binding_proxy"
|
|
2
|
-
require_relative "../../bluebook/dsl/const_shim"
|
|
3
|
-
require_relative "../../bluebook/dsl/hecksagon_builder"
|
|
4
|
-
|
|
5
|
-
module Hecks
|
|
6
|
-
module Doors
|
|
7
|
-
module RubyDoor
|
|
8
|
-
# One chapter's module: vision and aggregate list on the singleton, one
|
|
9
|
-
# aggregate door per declared head, and a `const_missing` hook for undeclared names.
|
|
10
|
-
module Chapter
|
|
11
|
-
# Builds the anonymous module that stands for one booted chapter: `vision`,
|
|
12
|
-
# `aggregates`, `docs`, `narrate` and `project` as singleton methods, plus one
|
|
13
|
-
# nested constant per aggregate holding that aggregate's door.
|
|
14
|
-
#
|
|
15
|
-
# @param dispatcher [Runtime::Dispatcher, Runtime::RemoteDispatcher] the booted
|
|
16
|
-
# dispatcher each aggregate door closes over
|
|
17
|
-
# @param bluebook [Bluebook::Chapter] the chapter to project into a module
|
|
18
|
-
# @return [Module] a fresh, unnamed module; `RubyDoor.install` gives it its
|
|
19
|
-
# top-level name
|
|
20
|
-
# @raise [NameError] if an aggregate's name is not a valid constant name
|
|
21
|
-
def chapter_module(dispatcher, bluebook)
|
|
22
|
-
chapter = Module.new
|
|
23
|
-
define_readers(chapter, bluebook)
|
|
24
|
-
define_projections(chapter, bluebook)
|
|
25
|
-
|
|
26
|
-
bluebook.aggregates.each do |aggregate|
|
|
27
|
-
chapter.const_set(aggregate.hecks_name, aggregate_module(dispatcher, bluebook.name, aggregate))
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
define_const_missing(chapter, bluebook)
|
|
31
|
-
chapter
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
private
|
|
35
|
-
|
|
36
|
-
# The chapter's vision and its aggregate names.
|
|
37
|
-
def define_readers(chapter, bluebook)
|
|
38
|
-
chapter.define_singleton_method(:vision) { bluebook.vision }
|
|
39
|
-
chapter.define_singleton_method(:aggregates) { bluebook.aggregates.map(&:name).sort }
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# The chapter's documents and projections, each projected from its IR on every call so
|
|
43
|
-
# none can go stale.
|
|
44
|
-
def define_projections(chapter, bluebook)
|
|
45
|
-
chapter.define_singleton_method(:docs) do |**options|
|
|
46
|
-
Projector.call(:docs, bluebook: bluebook, options: options)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# The chapter read back in english, via `Projector::NarrateProjector`.
|
|
50
|
-
chapter.define_singleton_method(:narrate) do |**options|
|
|
51
|
-
Projector.call(:narrate, bluebook: bluebook, options: options)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
define_project(chapter, bluebook)
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
# Projects the chapter's IR through a target; `out:` writes the artifact and
|
|
58
|
-
# the remaining options go to the projector (`audience:` for OIDC).
|
|
59
|
-
#
|
|
60
|
-
# Pizzas.project(Projections::OIDC)
|
|
61
|
-
# Pizzas.project(Projections::Shape, out: "shape.json")
|
|
62
|
-
def define_project(chapter, bluebook)
|
|
63
|
-
chapter.define_singleton_method(:project) do |target, out: nil, **options|
|
|
64
|
-
key = Projector.key_for(target)
|
|
65
|
-
artifact = Projector.call(key, bluebook: bluebook, options: options)
|
|
66
|
-
return artifact unless out
|
|
67
|
-
|
|
68
|
-
Projector.write(artifact, out, as: Projector.emits_for(key))
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
# Inside a hecksagon a name is a declaration: with a collector open it becomes
|
|
73
|
-
# a `BindingProxy`. Otherwise a scoped reference from a bluebook mid-declaration
|
|
74
|
-
# goes to the `ConstShim` resolver, so it resolves whether or not a facade exists.
|
|
75
|
-
def define_const_missing(chapter, bluebook)
|
|
76
|
-
chapter.define_singleton_method(:const_missing) do |name|
|
|
77
|
-
collector = Bluebook::DSL::HecksagonBuilder.collector
|
|
78
|
-
return Bluebook::DSL::BindingProxy.new("#{bluebook.name}::#{name}", collector) if collector
|
|
79
|
-
|
|
80
|
-
resolver = Bluebook::DSL::ConstShim.resolver
|
|
81
|
-
return resolver.call("#{bluebook.name}::#{name}") if resolver
|
|
82
|
-
|
|
83
|
-
super(name)
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
end
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
require_relative "../chapters"
|
|
2
|
-
require_relative "ruby_door/chapter"
|
|
3
|
-
require_relative "ruby_door/aggregate_door"
|
|
4
|
-
|
|
5
|
-
module Hecks
|
|
6
|
-
module Doors
|
|
7
|
-
# The door without classes: anonymous per-boot modules whose singleton methods
|
|
8
|
-
# dispatch by FQN, installed by `Loader.bind_runtime` and replaced whole on the next boot.
|
|
9
|
-
#
|
|
10
|
-
# `persisted_by("Heki")` in a `.hecksagon` file lands on the module's `method_missing`,
|
|
11
|
-
# which records a `Bind` into the open `HecksagonBuilder.collector`.
|
|
12
|
-
module RubyDoor
|
|
13
|
-
# Names that would shadow the machinery a Handle runs on; a field with one gets no reader.
|
|
14
|
-
RESERVED = %i[id state events reload inspect to_h hash class].freeze
|
|
15
|
-
|
|
16
|
-
extend Chapter
|
|
17
|
-
extend AggregateDoor
|
|
18
|
-
|
|
19
|
-
module_function
|
|
20
|
-
|
|
21
|
-
# Installs one top-level module per booted chapter, and one per aggregate, each
|
|
22
|
-
# closing over `dispatcher`, so `Pizzas::Pizza` and the bare `Pizza` both open the
|
|
23
|
-
# door of the boot that ran last.
|
|
24
|
-
#
|
|
25
|
-
# A gem chapter a hecksagon `attaches` installs nothing (`Query`, `Port` stay free).
|
|
26
|
-
# An aggregate sharing its chapter's name gets no second constant. A name that user
|
|
27
|
-
# code or the stdlib already owns is left alone with a warning (see `Namespace.install`).
|
|
28
|
-
#
|
|
29
|
-
# @param dispatcher [Runtime::Dispatcher, Runtime::RemoteDispatcher] the booted
|
|
30
|
-
# dispatcher every installed door dispatches and queries through
|
|
31
|
-
# @return [Runtime::Dispatcher, Runtime::RemoteDispatcher] the same `dispatcher`
|
|
32
|
-
# @raise [NameError] if a chapter or aggregate name is not a valid constant name
|
|
33
|
-
def install(dispatcher)
|
|
34
|
-
dispatcher.registry.bluebooks.each_value do |bluebook|
|
|
35
|
-
install_chapter(dispatcher, bluebook) unless attached_chapter?(dispatcher.registry, bluebook)
|
|
36
|
-
end
|
|
37
|
-
dispatcher
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
# Installs one chapter's module, and the top-level shortcut of each of its aggregates.
|
|
41
|
-
def install_chapter(dispatcher, bluebook)
|
|
42
|
-
chapter = chapter_module(dispatcher, bluebook)
|
|
43
|
-
Namespace.install(*placement(bluebook), chapter)
|
|
44
|
-
# A namespaced chapter keeps its aggregates inside its namespace: top-level
|
|
45
|
-
# shortcuts would bring back the collisions the namespace exists to avoid.
|
|
46
|
-
return if bluebook.namespace
|
|
47
|
-
|
|
48
|
-
bluebook.aggregates.each do |aggregate|
|
|
49
|
-
next if aggregate.hecks_name == bluebook.name
|
|
50
|
-
|
|
51
|
-
Namespace.install(Object, aggregate.hecks_name, chapter.const_get(aggregate.hecks_name, false))
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# Whether `bluebook` is a gem chapter that a hecksagon attached rather than a domain's own.
|
|
56
|
-
#
|
|
57
|
-
# @param registry [Runtime::Registry] the booted registry
|
|
58
|
-
# @param bluebook [Bluebook::Chapter] the chapter under test
|
|
59
|
-
# @return [Boolean]
|
|
60
|
-
def attached_chapter?(registry, bluebook)
|
|
61
|
-
registry.bounded?(bluebook.name) && Hecks::Chapters.index.key?(bluebook.name)
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
# Where a chapter's module installs: `Object::<name>`, or the constant path its
|
|
65
|
-
# `namespace` names, creating any missing parent modules along the way.
|
|
66
|
-
#
|
|
67
|
-
# @param bluebook [Bluebook::Chapter] the chapter being installed
|
|
68
|
-
# @return [Array(Module, String)] the parent module and the constant name within it
|
|
69
|
-
def placement(bluebook)
|
|
70
|
-
return [Object, bluebook.name] unless bluebook.namespace
|
|
71
|
-
|
|
72
|
-
*parents, leaf = bluebook.namespace.split("::")
|
|
73
|
-
parent = parents.reduce(Object) do |outer, name|
|
|
74
|
-
outer.const_defined?(name, false) ? outer.const_get(name, false) : outer.const_set(name, Module.new)
|
|
75
|
-
end
|
|
76
|
-
[parent, leaf]
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
end
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
require "digest"
|
|
2
|
-
require "fileutils"
|
|
3
|
-
require "json"
|
|
4
|
-
|
|
5
|
-
module Hecks
|
|
6
|
-
module Doors
|
|
7
|
-
# Remembers the help a launcher prints, so a repeat `hecks` need not read the domain again.
|
|
8
|
-
#
|
|
9
|
-
# The help is a pure function of the domain's declarations and of the gem that projects them,
|
|
10
|
-
# and reading those is most of what a launcher costs. The answer is kept in a file named for a
|
|
11
|
-
# digest of everything it depends on (the domain's declaration files, the gem's judging code and
|
|
12
|
-
# doors, the hecks and Ruby versions, the environment overlay, the command line and the
|
|
13
|
-
# program name),
|
|
14
|
-
# so any edit to one of them is simply a different entry: nothing is ever stale, only unused.
|
|
15
|
-
# Only an answer that ended well is kept, and any trouble with the cache itself is ignored
|
|
16
|
-
# and the help is worked out as if it did not exist.
|
|
17
|
-
#
|
|
18
|
-
# `HECKS_NO_USAGE_CACHE=1` turns it off; `HECKS_CACHE_DIR` moves it.
|
|
19
|
-
module UsageCache
|
|
20
|
-
# The variable that turns the cache off when set to anything but empty or `0`.
|
|
21
|
-
DISABLE_VARIABLE = "HECKS_NO_USAGE_CACHE".freeze
|
|
22
|
-
# The variable that names the directory the cache lives in.
|
|
23
|
-
DIRECTORY_VARIABLE = "HECKS_CACHE_DIR".freeze
|
|
24
|
-
# The declaration files whose contents shape a help text.
|
|
25
|
-
DECLARATIONS = "*.{bluebook,world,hecksagon,rb}".freeze
|
|
26
|
-
# How long an unused entry stays before the next write sweeps it away.
|
|
27
|
-
KEEP_SECONDS = 14 * 24 * 60 * 60
|
|
28
|
-
|
|
29
|
-
module_function
|
|
30
|
-
|
|
31
|
-
# Answers the cached help for this command line, or works it out with the block and
|
|
32
|
-
# remembers it.
|
|
33
|
-
#
|
|
34
|
-
# @param runtime [#directory] what `Hecks.describe` answered; anything else bypasses the cache
|
|
35
|
-
# @param argv [Array<String>] the command line
|
|
36
|
-
# @param program [String] how the caller was invoked
|
|
37
|
-
# @param audience [String] who the help is for, since the same line reads differently to each
|
|
38
|
-
# @yield works the answer out, loading the domain
|
|
39
|
-
# @yieldreturn [Array(String, Integer), nil] the text and status; nil if it runs a command
|
|
40
|
-
# @return [Array(String, Integer), nil] the block's answer, or the remembered one
|
|
41
|
-
def fetch(runtime, argv, program, audience: "")
|
|
42
|
-
directory = runtime.respond_to?(:directory) ? runtime.directory : nil
|
|
43
|
-
return yield unless directory && enabled?
|
|
44
|
-
|
|
45
|
-
file = entry_path(directory, argv, program, audience)
|
|
46
|
-
remembered = file && recall(file)
|
|
47
|
-
return remembered if remembered
|
|
48
|
-
|
|
49
|
-
answer = yield
|
|
50
|
-
remember(file, answer) if worth_keeping?(file, answer)
|
|
51
|
-
answer
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
# Whether an answer that ended well can be written to the entry's file.
|
|
55
|
-
def worth_keeping?(file, answer)
|
|
56
|
-
file && answer&.last&.zero?
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
# @return [Boolean] whether the cache is on
|
|
60
|
-
def enabled?
|
|
61
|
-
off = ENV[DISABLE_VARIABLE].to_s
|
|
62
|
-
off.empty? || off == "0"
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
# @return [String] the directory entries live in
|
|
66
|
-
def directory
|
|
67
|
-
ENV[DIRECTORY_VARIABLE] || File.join(ENV["XDG_CACHE_HOME"] || File.join(Dir.home, ".cache"), "hecks")
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
# The file that holds the answer for this command line, named by what it depends on.
|
|
71
|
-
#
|
|
72
|
-
# @return [String, nil] nil when the digest cannot be taken
|
|
73
|
-
def entry_path(domain, argv, program, audience = "")
|
|
74
|
-
digest = Digest::SHA256.new
|
|
75
|
-
key_parts(program, audience, argv).each { |part| digest << part.to_s << "\0" }
|
|
76
|
-
fingerprint_code(domain, digest)
|
|
77
|
-
File.join(directory, "usage-#{digest.hexdigest}.json")
|
|
78
|
-
rescue SystemCallError
|
|
79
|
-
nil
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
# @return [Array<String>] what the answer depends on besides the files: the gem and Ruby
|
|
83
|
-
# series, the environment overlay, the program and audience and the command line
|
|
84
|
-
def key_parts(program, audience, argv)
|
|
85
|
-
[Hecks::VERSION, Hecks::Bluebook::MetaValidator::VerdictCache.ruby_series,
|
|
86
|
-
ENV["HECKS_ENVIRONMENT"].to_s, program, audience, argv.join("\0")]
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
# Feeds the digest every declaration file under `root`: its path below `root` and its bytes,
|
|
90
|
-
# so a touch or a checkout elsewhere keeps the entry and an edit does not.
|
|
91
|
-
def fingerprint(root, digest)
|
|
92
|
-
Dir.glob(File.join(root, "**", DECLARATIONS)).each do |file|
|
|
93
|
-
digest << file.delete_prefix(root) << "\0" << File.binread(file) << "\0"
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
# Feeds the digest what shapes a help text: the domain's declarations, the judging trees of
|
|
98
|
-
# the gem (the same set the verdict cache keys on) and the doors that render the text. An
|
|
99
|
-
# edit to the gem's projections, deploy or release code cannot change a help line.
|
|
100
|
-
def fingerprint_code(domain, digest)
|
|
101
|
-
fingerprint(domain, digest)
|
|
102
|
-
digest << Hecks::Bluebook::MetaValidator::VerdictCache.code_digest << "\0"
|
|
103
|
-
fingerprint(__dir__, digest)
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
# Reads the remembered answer and marks the entry as used, so a sweep keeps what is read.
|
|
107
|
-
#
|
|
108
|
-
# @return [Array(String, Integer), nil] the remembered answer, or nil when none can be trusted
|
|
109
|
-
def recall(file)
|
|
110
|
-
record = JSON.parse(File.read(file))
|
|
111
|
-
File.utime(nil, nil, file)
|
|
112
|
-
[record.fetch("text"), record.fetch("status")]
|
|
113
|
-
rescue SystemCallError, JSON::ParserError, KeyError
|
|
114
|
-
nil
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
# Writes the answer beside its name and sweeps entries nobody has read for a while.
|
|
118
|
-
def remember(file, answer)
|
|
119
|
-
FileUtils.mkdir_p(File.dirname(file))
|
|
120
|
-
scratch = "#{file}.#{Process.pid}"
|
|
121
|
-
File.write(scratch, JSON.generate("text" => answer.first, "status" => answer.last))
|
|
122
|
-
File.rename(scratch, file)
|
|
123
|
-
sweep(File.dirname(file))
|
|
124
|
-
rescue SystemCallError
|
|
125
|
-
nil
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
# Removes the entries older than `KEEP_SECONDS`.
|
|
129
|
-
def sweep(dir)
|
|
130
|
-
cutoff = Time.now - KEEP_SECONDS
|
|
131
|
-
Dir.glob(File.join(dir, "usage-*.json")).each do |entry|
|
|
132
|
-
File.delete(entry) if File.mtime(entry) < cutoff
|
|
133
|
-
end
|
|
134
|
-
rescue SystemCallError
|
|
135
|
-
nil
|
|
136
|
-
end
|
|
137
|
-
end
|
|
138
|
-
end
|
|
139
|
-
end
|