hecks 2.9.0 → 3.0.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/exe/hecks +51 -6
- data/lib/hecks/adapters/driven/heki/journal.rb +1 -1
- data/lib/hecks/adapters/driven/lambda/client.rb +1 -1
- data/lib/hecks/adapters/driven/lambda.rb +1 -1
- data/lib/hecks/adapters/driven/memory.rb +16 -3
- data/lib/hecks/adapters/driven/postgres/reconnect.rb +6 -2
- data/lib/hecks/adapters/driven/postgres/shared_connection.rb +180 -0
- data/lib/hecks/adapters/driven/postgres.rb +4 -2
- data/lib/hecks/adapters/driven/prism.rb +41 -8
- data/lib/hecks/adapters/driven/tenant_provisioner.rb +73 -16
- data/lib/hecks/behaviors/expectations.rb +1 -1
- data/lib/hecks/behaviors.rb +1 -1
- data/lib/hecks/bench/cli.rb +62 -0
- data/lib/hecks/bench/environment.rb +71 -0
- data/lib/hecks/bench/postgres_probe.rb +30 -0
- data/lib/hecks/bench/report.rb +76 -0
- data/lib/hecks/bench/ruby_runner.rb +93 -0
- data/lib/hecks/bench/run.rb +55 -0
- data/lib/hecks/bench/rust_runner.rb +101 -0
- data/lib/hecks/bench/stats.rb +46 -0
- data/lib/hecks/bench/suite.rb +98 -0
- data/lib/hecks/bench/workload.rb +89 -0
- data/lib/hecks/bench.rb +17 -0
- data/lib/hecks/bluebook/assembly/contracts.rb +2 -0
- data/lib/hecks/bluebook/attribute.rb +1 -1
- data/lib/hecks/bluebook/behaviour/aggregate.rb +30 -1
- data/lib/hecks/bluebook/behaviour/domain_port.rb +7 -0
- data/lib/hecks/bluebook/chapter.rb +6 -2
- data/lib/hecks/bluebook/domain_port.rb +36 -5
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +10 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +8 -0
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +2 -1
- data/lib/hecks/bluebook/dsl/domain_port_builder.rb +31 -3
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +122 -3
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +1 -1
- data/lib/hecks/bluebook/dsl/query_builder.rb +27 -1
- data/lib/hecks/bluebook/dsl/rule_reference.rb +1 -1
- data/lib/hecks/bluebook/dsl/world_builder.rb +29 -2
- data/lib/hecks/bluebook/expression/canonical_form.rb +1 -1
- data/lib/hecks/bluebook/expression/resolver.rb +3 -2
- data/lib/hecks/bluebook/hexagon.rb +13 -5
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +1 -0
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +4 -1
- data/lib/hecks/bluebook/meta_validator/verdict_cache.rb +246 -0
- data/lib/hecks/bluebook/meta_validator.rb +9 -4
- data/lib/hecks/bluebook/model_check.rb +23 -0
- data/lib/hecks/bluebook/pattern_subset.rb +38 -0
- data/lib/hecks/bluebook/query.rb +20 -5
- data/lib/hecks/bluebook/smoke_test.rb +1 -1
- data/lib/hecks/canonical_json.rb +30 -0
- data/lib/hecks/chapters.rb +102 -0
- data/lib/hecks/cli/behaviors.rb +61 -0
- data/lib/hecks/cli/canonicalise.rb +25 -0
- data/lib/hecks/cli/check_engine_agreement.rb +32 -0
- data/lib/hecks/cli/check_era.rb +88 -0
- data/lib/hecks/cli/console.rb +66 -0
- data/lib/hecks/cli/deploy_template_diff.rb +40 -0
- data/lib/hecks/cli/doc_coverage.rb +32 -0
- data/lib/hecks/cli/document.rb +2 -2
- data/lib/hecks/cli/expression_projection.rb +41 -0
- data/lib/hecks/cli/follow.rb +88 -0
- data/lib/hecks/cli/history.rb +44 -0
- data/lib/hecks/cli/ir.rb +1 -1
- data/lib/hecks/cli/mcp.rb +3 -3
- data/lib/hecks/cli/model_check.rb +7 -4
- data/lib/hecks/cli/pattern_cases.rb +47 -0
- data/lib/hecks/cli/present.rb +39 -0
- data/lib/hecks/cli/project_cli.rb +224 -32
- data/lib/hecks/cli/project_diagrams.rb +4 -3
- data/lib/hecks/cli/project_glossary.rb +44 -0
- data/lib/hecks/cli/reference.rb +46 -0
- data/lib/hecks/cli/refresh_projections.rb +44 -0
- data/lib/hecks/cli/refresh_rspec_runtime_baseline.rb +150 -0
- data/lib/hecks/cli/release.rb +70 -0
- data/lib/hecks/cli/release_gem.rb +59 -0
- data/lib/hecks/cli/rspec_io_parallel_files.rb +137 -0
- data/lib/hecks/cli/rspec_shard_files.rb +66 -0
- data/lib/hecks/cli/run.rb +3 -3
- data/lib/hecks/cli/seed_semantics_corpus.rb +71 -0
- data/lib/hecks/cli/serve_query_ir_mcp.rb +30 -0
- data/lib/hecks/cli/shape.rb +70 -0
- data/lib/hecks/cli/smoke_http.rb +230 -0
- data/lib/hecks/cli/smoke_test.rb +5 -3
- data/lib/hecks/cli/spec_example.rb +27 -0
- data/lib/hecks/cli/statements.rb +32 -0
- data/lib/hecks/cli/stores.rb +4 -5
- data/lib/hecks/cli/stress_concurrency_specs.rb +177 -0
- data/lib/hecks/cli.rb +201 -52
- data/lib/hecks/codemod.rb +324 -0
- data/lib/hecks/corpus.rb +423 -0
- data/lib/hecks/deploy/bluebook/deploy.bluebook +591 -23
- data/lib/hecks/deploy/bluebook/deploy.hecksagon +41 -4
- data/lib/hecks/deploy/oidc.json +82 -2
- data/lib/hecks/doc/reference.rb +351 -0
- data/lib/hecks/doors/cli_door.rb +196 -0
- data/lib/hecks/doors/cli_runner.rb +297 -0
- data/lib/hecks/{facade → doors}/command_request.rb +1 -1
- data/lib/hecks/{facade → doors}/handle.rb +2 -2
- data/lib/hecks/{facade → doors}/json_door.rb +4 -4
- data/lib/hecks/doors/launcher_options.rb +129 -0
- data/lib/hecks/{cli → doors}/mcp_door.rb +7 -7
- data/lib/hecks/doors/mcp_door_scope.rb +97 -0
- data/lib/hecks/{facade/surface → doors/ruby_door}/aggregate_door.rb +8 -3
- data/lib/hecks/{facade/surface → doors/ruby_door}/chapter.rb +3 -3
- data/lib/hecks/{facade/surface.rb → doors/ruby_door.rb} +36 -5
- data/lib/hecks/doors.rb +61 -0
- data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +1 -1
- data/lib/hecks/embryonaut_bluebook.rb +1 -1
- data/lib/hecks/engine_agreement.rb +156 -0
- data/lib/hecks/facade.rb +24 -37
- data/lib/hecks/forms/app.rb +6 -6
- data/lib/hecks/forms/banking_presentation.rb +50 -0
- data/lib/hecks/forms/field_shape.rb +2 -1
- data/lib/hecks/forms/port_argument.rb +1 -1
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +393 -0
- data/lib/hecks/fuzzing/combination_miner.rb +86 -0
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +214 -0
- data/lib/hecks/fuzzing/coverage_campaign.rb +143 -0
- data/lib/hecks/fuzzing/differential.rb +156 -0
- data/lib/hecks/fuzzing/domain_generator.rb +615 -0
- data/lib/hecks/fuzzing/era_boundary.rb +71 -0
- data/lib/hecks/fuzzing/form_census.rb +136 -0
- data/lib/hecks/fuzzing/generated_domain_check.rb +93 -0
- data/lib/hecks/fuzzing/invalid_value_generator.rb +64 -0
- data/lib/hecks/fuzzing/isolated_boot.rb +301 -0
- data/lib/hecks/fuzzing/nondeterministic.rb +51 -0
- data/lib/hecks/fuzzing/outside_world.rb +45 -0
- data/lib/hecks/fuzzing/persistence_parity.rb +102 -0
- data/lib/hecks/fuzzing/properties/corrections.rb +88 -0
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +314 -0
- data/lib/hecks/fuzzing/properties/guards.rb +190 -0
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +300 -0
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +93 -0
- data/lib/hecks/fuzzing/properties/outbox.rb +89 -0
- data/lib/hecks/fuzzing/properties/querying.rb +175 -0
- data/lib/hecks/fuzzing/properties.rb +162 -0
- data/lib/hecks/fuzzing/qa_settings.rb +123 -0
- data/lib/hecks/fuzzing/replay.rb +505 -0
- data/lib/hecks/fuzzing/rotation_priority.rb +48 -0
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +108 -0
- data/lib/hecks/fuzzing/self_consistency.rb +339 -0
- data/lib/hecks/fuzzing/sequence_generator/adversary.rb +385 -0
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +132 -0
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +95 -0
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +77 -0
- data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +109 -0
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +237 -0
- data/lib/hecks/fuzzing/sequence_generator.rb +189 -0
- data/lib/hecks/fuzzing/shrinker.rb +166 -0
- data/lib/hecks/fuzzing/structural_skips.rb +33 -0
- data/lib/hecks/fuzzing/sweep_depth.rb +43 -0
- data/lib/hecks/fuzzing/target_capabilities.rb +163 -0
- data/lib/hecks/fuzzing/value_generator.rb +216 -0
- data/lib/hecks/fuzzing.rb +23 -0
- data/lib/hecks/grammar/evolve.rb +336 -0
- data/lib/hecks/hecks/adapters/codebase/codemods.rb +45 -0
- data/lib/hecks/hecks/adapters/codebase/conformance.rb +71 -0
- data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +202 -0
- data/lib/hecks/hecks/adapters/codebase/gem_registry.rb +80 -0
- data/lib/hecks/hecks/adapters/codebase/kernel_tables.rb +54 -0
- data/lib/hecks/hecks/adapters/codebase/language.rb +240 -0
- data/lib/hecks/hecks/adapters/codebase/npm_registry.rb +102 -0
- data/lib/hecks/hecks/adapters/codebase/publishing.rb +142 -0
- data/lib/hecks/hecks/adapters/codebase/regeneration.rb +67 -0
- data/lib/hecks/hecks/adapters/codebase/release_facts.rb +90 -0
- data/lib/hecks/hecks/adapters/codebase/ruby_child.rb +83 -0
- data/lib/hecks/hecks/adapters/codebase/secret_vault.rb +36 -0
- data/lib/hecks/hecks/adapters/codebase/source_tree.adapter +7 -0
- data/lib/hecks/hecks/adapters/codebase/source_tree.rb +189 -0
- data/lib/hecks/hecks/adapters/codebase/sqlite_fixture.rb +71 -0
- data/lib/hecks/hecks/adapters/codebase/style.rb +171 -0
- data/lib/hecks/hecks/adapters/codebase/test_runner.rb +55 -0
- data/lib/hecks/hecks/adapters/codebase/test_suite.rb +165 -0
- data/lib/hecks/hecks/adapters/codebase/tree.rb +111 -0
- data/lib/hecks/hecks/adapters/console_capture.rb +79 -0
- data/lib/hecks/hecks/adapters/deploy_toolchain.adapter +7 -0
- data/lib/hecks/hecks/adapters/deploy_toolchain.rb +108 -0
- data/lib/hecks/hecks/adapters/git.adapter +7 -0
- data/lib/hecks/hecks/adapters/git.rb +102 -0
- data/lib/hecks/hecks/adapters/host_http.adapter +7 -0
- data/lib/hecks/hecks/adapters/host_http.rb +65 -0
- data/lib/hecks/hecks/adapters/in_process_boot.adapter +7 -0
- data/lib/hecks/hecks/adapters/in_process_boot.rb +197 -0
- data/lib/hecks/hecks/adapters/in_process_operations.rb +202 -0
- data/lib/hecks/hecks/adapters/journal_store/changes.rb +143 -0
- data/lib/hecks/hecks/adapters/journal_store/compaction.rb +145 -0
- data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +132 -0
- data/lib/hecks/hecks/adapters/journal_store/examination.rb +135 -0
- data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +163 -0
- data/lib/hecks/hecks/adapters/journal_store/readings.rb +187 -0
- data/lib/hecks/hecks/adapters/journal_store.adapter +7 -0
- data/lib/hecks/hecks/adapters/journal_store.rb +64 -0
- data/lib/hecks/hecks/adapters/local_files.adapter +7 -0
- data/lib/hecks/hecks/adapters/local_files.rb +46 -0
- data/lib/hecks/hecks/adapters/pg_admin.adapter +7 -0
- data/lib/hecks/hecks/adapters/pg_admin.rb +245 -0
- data/lib/hecks/hecks/adapters/process_pool.adapter +7 -0
- data/lib/hecks/hecks/adapters/process_pool.rb +119 -0
- data/lib/hecks/hecks/adapters/rust_toolchain.adapter +7 -0
- data/lib/hecks/hecks/adapters/rust_toolchain.rb +179 -0
- data/lib/hecks/hecks/adapters/rust_workspace.rb +150 -0
- data/lib/hecks/hecks/adapters/shell.adapter +7 -0
- data/lib/hecks/hecks/adapters/shell.rb +49 -0
- data/lib/hecks/hecks/adapters/terminal.adapter +7 -0
- data/lib/hecks/hecks/adapters/terminal.rb +74 -0
- data/lib/hecks/hecks/codebase.behaviors +172 -0
- data/lib/hecks/hecks/codebase.bluebook +2453 -0
- data/lib/hecks/hecks/context_map.hecksagon +13 -0
- data/lib/hecks/hecks/custodian.behaviors +179 -0
- data/lib/hecks/hecks/custodian.bluebook +1847 -0
- data/lib/hecks/hecks/deploy.behaviors +74 -0
- data/lib/hecks/hecks/deploy.world +12 -0
- data/lib/hecks/hecks/environments/memory.world +10 -0
- data/lib/hecks/hecks/governance.world +7 -0
- data/lib/hecks/hecks/hecks.behaviors +62 -0
- data/lib/hecks/hecks/hecks.bluebook +124 -0
- data/lib/hecks/hecks/hecks.hecksagon +390 -0
- data/lib/hecks/hecks/hecks.world +42 -0
- data/lib/hecks/kernel_capabilities.rb +194 -0
- data/lib/hecks/language/bluebook/bluebook.bluebook +11 -0
- data/lib/hecks/language/bluebook/query.bluebook +7 -0
- data/lib/hecks/language/bluebook/vocabulary.bluebook +4 -4
- data/lib/hecks/language/hecksagon/domain_port.bluebook +10 -0
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +20 -0
- data/lib/hecks/mcp_stdio_guard.rb +2 -2
- data/lib/hecks/persistence_legacy_fixture/regenerate.rb +161 -0
- data/lib/hecks/persistence_legacy_fixture.rb +113 -0
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +8 -5
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +4 -1
- data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +15 -2
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +32 -15
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +6 -3
- data/lib/hecks/ports/persistence/plugins/era/translation/approval_file.rb +227 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +43 -24
- data/lib/hecks/ports/persistence/plugins/era/translation.rb +1 -0
- data/lib/hecks/ports/persistence/state_codec.rb +24 -5
- data/lib/hecks/projection_files.rb +285 -0
- data/lib/hecks/projections/bootstrap_table.rb +1 -1
- data/lib/hecks/projections/deploy/fargate.rb +5 -5
- data/lib/hecks/projections/deploy/lambda.rb +43 -32
- data/lib/hecks/projections/deploy/preview/preview.sh.erb +1 -1
- data/lib/hecks/projections/deploy/preview/template.rb +1 -1
- data/lib/hecks/projections/deploy/scripts/deploy-service.sh.tmpl +1 -1
- data/lib/hecks/projections/deploy/scripts/expected-era.header +1 -1
- data/lib/hecks/projections/deploy/scripts/hosting.mk.tmpl +3 -3
- data/lib/hecks/projections/deploy/scripts/smoke-after-deploy.sh.tmpl +1 -1
- data/lib/hecks/projections/deploy/shared.rb +1 -1
- data/lib/hecks/projections/diagrams.rb +3 -3
- data/lib/hecks/projections/model/deviations.rb +1 -1
- data/lib/hecks/projections/parser_table.rb +4 -4
- data/lib/hecks/projections/reference.rb +2 -3
- data/lib/hecks/projections/rust_vocabulary.rb +1 -1
- data/lib/hecks/projector/cli_projector.rb +106 -37
- data/lib/hecks/projector.rb +1 -1
- data/lib/hecks/quality_control/adapters/agent.adapter +7 -0
- data/lib/hecks/quality_control/adapters/agent.rb +58 -0
- data/lib/hecks/quality_control/adapters/angle_tools.adapter +7 -0
- data/lib/hecks/quality_control/adapters/angle_tools.rb +15 -0
- data/lib/hecks/quality_control/adapters/clearance_recorder.rb +36 -0
- data/lib/hecks/quality_control/adapters/clearance_tools.adapter +7 -0
- data/lib/hecks/quality_control/adapters/clearance_tools.rb +17 -0
- data/lib/hecks/quality_control/adapters/git_pr.adapter +7 -0
- data/lib/hecks/quality_control/adapters/git_pr.rb +226 -0
- data/lib/hecks/quality_control/adapters/github_checks.adapter +9 -0
- data/lib/hecks/quality_control/adapters/github_checks.rb +83 -0
- data/lib/hecks/quality_control/adapters/github_ci_webhook.rb +56 -0
- data/lib/hecks/quality_control/adapters/github_issues.adapter +7 -0
- data/lib/hecks/quality_control/adapters/github_issues.rb +49 -0
- data/lib/hecks/quality_control/adapters/qa_tool.rb +59 -0
- data/lib/hecks/quality_control/adapters/sweep_tools.adapter +7 -0
- data/lib/hecks/quality_control/adapters/sweep_tools.rb +51 -0
- data/lib/hecks/quality_control/adapters/target_tools.adapter +7 -0
- data/lib/hecks/quality_control/adapters/target_tools.rb +43 -0
- data/lib/hecks/quality_control/cli/child.rb +45 -0
- data/lib/hecks/quality_control/cli/qa_concurrency_racer.rb +45 -0
- data/lib/hecks/quality_control/cli/qa_discover_external_domains.rb +248 -0
- data/lib/hecks/quality_control/cli/qa_domain_novelty.rb +163 -0
- data/lib/hecks/quality_control/cli/qa_generated_domains.rb +450 -0
- data/lib/hecks/quality_control/cli/qa_log_bug.rb +195 -0
- data/lib/hecks/quality_control/cli/qa_mine_combinations.rb +220 -0
- data/lib/hecks/quality_control/cli/qa_open_pr.rb +305 -0
- data/lib/hecks/quality_control/cli/qa_postgres_migrate.rb +154 -0
- data/lib/hecks/quality_control/cli/qa_postgres_role.rb +159 -0
- data/lib/hecks/quality_control/cli/qa_pr_check.rb +232 -0
- data/lib/hecks/quality_control/cli/qa_seed_angles.rb +142 -0
- data/lib/hecks/quality_control/cli/qa_seed_targets.rb +69 -0
- data/lib/hecks/quality_control/cli/qa_sweep/all_mode.rb +280 -0
- data/lib/hecks/quality_control/cli/qa_sweep/checks.rb +329 -0
- data/lib/hecks/quality_control/cli/qa_sweep/dials.rb +92 -0
- data/lib/hecks/quality_control/cli/qa_sweep/finding_report.rb +117 -0
- data/lib/hecks/quality_control/cli/qa_sweep/parsing.rb +175 -0
- data/lib/hecks/quality_control/cli/qa_sweep/release_mode.rb +60 -0
- data/lib/hecks/quality_control/cli/qa_sweep.rb +611 -0
- data/lib/hecks/quality_control/cli/qa_tick.rb +274 -0
- data/lib/hecks/quality_control/quality_control.bluebook +2224 -0
- data/lib/hecks/quality_control/quality_control.hecksagon +13 -0
- data/lib/hecks/quality_control/quality_control.ports.hecksagon +54 -0
- data/lib/hecks/query_ir.rb +346 -0
- data/lib/hecks/query_ir_mcp.rb +198 -0
- data/lib/hecks/release/runner/ci_publisher.rb +2 -2
- data/lib/hecks/release/runner/clean_tree.rb +42 -0
- data/lib/hecks/release/runner/console.rb +6 -0
- data/lib/hecks/release/runner/gem_publisher.rb +14 -7
- data/lib/hecks/release/runner/npm_publisher.rb +6 -36
- data/lib/hecks/release/runner/preflight.rb +26 -2
- data/lib/hecks/release/runner/published.rb +8 -26
- data/lib/hecks/release/runner/tagger.rb +30 -15
- data/lib/hecks/release/runner.rb +57 -6
- data/lib/hecks/router/namespace_installer.rb +3 -3
- data/lib/hecks/runtime/adapter_lookup.rb +124 -0
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +4 -0
- data/lib/hecks/runtime/dependency_planning.rb +20 -2
- data/lib/hecks/runtime/dispatcher.rb +53 -3
- data/lib/hecks/runtime/interpreting.rb +3 -0
- data/lib/hecks/runtime/loader.rb +65 -12
- data/lib/hecks/runtime/outbox.rb +1 -1
- data/lib/hecks/runtime/policy_interpreter.rb +5 -2
- data/lib/hecks/runtime/port_operation_interpreter.rb +2 -10
- data/lib/hecks/runtime/query_interpreter.rb +77 -0
- data/lib/hecks/runtime/reaction_outcome.rb +89 -0
- data/lib/hecks/runtime/refusal_wording.rb +23 -1
- data/lib/hecks/runtime/registry/verification.rb +163 -4
- data/lib/hecks/runtime/registry.rb +57 -3
- data/lib/hecks/runtime/remote_dispatcher.rb +31 -2
- data/lib/hecks/runtime/value/coercion.rb +23 -135
- data/lib/hecks/runtime/value/field_checks.rb +172 -0
- data/lib/hecks/runtime/value.rb +4 -1
- data/lib/hecks/runtime.rb +20 -6
- data/lib/hecks/rust_build/conformance.rb +158 -0
- data/lib/hecks/rust_build/conformance_fuzz.rb +71 -0
- data/lib/hecks/rust_build/coverage.rb +218 -0
- data/lib/hecks/rust_build/native_build.rb +124 -0
- data/lib/hecks/rust_build/project_rust/root_mod.rb +120 -0
- data/lib/hecks/rust_build/project_rust.rb +332 -0
- data/lib/hecks/rust_build/wasm.rb +105 -0
- data/lib/hecks/rust_build/wasm_browser.rb +113 -0
- data/lib/hecks/rust_build.rb +144 -0
- data/lib/hecks/storehouse.rb +16 -16
- data/lib/hecks/tenancy/bluebook/tenancy.bluebook +2 -2
- data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +1 -1
- data/lib/hecks/three_zero/forms.yml +127 -0
- data/lib/hecks/three_zero.rb +12 -0
- data/lib/hecks/tools/argument_gate_matrix.rb +316 -0
- data/lib/hecks/tools/comment_style.rb +1070 -0
- data/lib/hecks/tools/corpus_report.rb +87 -0
- data/lib/hecks/tools/deploy_recipe.rb +255 -0
- data/lib/hecks/tools/deploy_recipe_lint.rb +282 -0
- data/lib/hecks/tools/drop_implicit_append_fields.rb +95 -0
- data/lib/hecks/tools/era_projection_backfill.rb +94 -0
- data/lib/hecks/tools/era_reattest.rb +146 -0
- data/lib/hecks/tools/evolve_run.rb +189 -0
- data/lib/hecks/tools/fuzz_sweep.rb +373 -0
- data/lib/hecks/tools/heki_compaction.rb +100 -0
- data/lib/hecks/tools/hoist_local_givens.rb +246 -0
- data/lib/hecks/tools/journal_compaction.rb +89 -0
- data/lib/hecks/tools/oidc_manifests.rb +70 -0
- data/lib/hecks/tools/query_ir_run.rb +81 -0
- data/lib/hecks/tools/regeneration_run.rb +166 -0
- data/lib/hecks/tools/rust_comment_style.rb +642 -0
- data/lib/hecks/tools/sequence_script.rb +62 -0
- data/lib/hecks/tools/tail_merge.rb +117 -0
- data/lib/hecks/tools/tenant_provisioning.rb +142 -0
- data/lib/hecks/tools/translation_audit.rb +208 -0
- data/lib/hecks/tools/translation_scaffold.rb +131 -0
- data/lib/hecks/tools.rb +86 -0
- data/lib/hecks/version.rb +1 -1
- data/lib/hecks.rb +32 -15
- data/qa/settings.yml +66 -0
- data/rust/.cargo/config.toml +6 -0
- data/rust/.gitignore +2 -0
- data/rust/Cargo.lock +54 -0
- data/rust/Cargo.toml +61 -0
- data/rust/build/.cargo/config.toml +3 -0
- data/rust/build/.gitignore +1 -0
- data/rust/build/Cargo.lock +7 -0
- data/rust/build/Cargo.toml +19 -0
- data/rust/build/src/build_artifact.rs +47 -0
- data/rust/build/src/cargo_sync.rs +248 -0
- data/rust/build/src/json.rs +421 -0
- data/rust/build/src/lineage_pass.rs +285 -0
- data/rust/build/src/main.rs +51 -0
- data/rust/build/src/optional_pass.rs +150 -0
- data/rust/build/src/pipeline.rs +264 -0
- data/rust/build/src/reserved_names.rs +76 -0
- data/rust/build/src/resolve.rs +124 -0
- data/rust/build/src/root.rs +25 -0
- data/rust/build/src/sidecars.rs +73 -0
- data/rust/build/src/subprocess.rs +51 -0
- data/rust/build/src/tmp.rs +31 -0
- data/rust/codegen/.cargo/config.toml +3 -0
- data/rust/codegen/.gitignore +1 -0
- data/rust/codegen/Cargo.lock +7 -0
- data/rust/codegen/Cargo.toml +20 -0
- data/rust/codegen/src/attr.rs +32 -0
- data/rust/codegen/src/bridging.rs +481 -0
- data/rust/codegen/src/commands.rs +1226 -0
- data/rust/codegen/src/constraints.rs +109 -0
- data/rust/codegen/src/dependency_planning.rs +209 -0
- data/rust/codegen/src/domain_generator.rs +1288 -0
- data/rust/codegen/src/exemplar.rs +230 -0
- data/rust/codegen/src/expr_emitter.rs +87 -0
- data/rust/codegen/src/fielded.rs +192 -0
- data/rust/codegen/src/hecks_naming.rs +33 -0
- data/rust/codegen/src/json.rs +335 -0
- data/rust/codegen/src/json_codec.rs +697 -0
- data/rust/codegen/src/literal.rs +207 -0
- data/rust/codegen/src/main.rs +290 -0
- data/rust/codegen/src/manifest.rs +227 -0
- data/rust/codegen/src/mutations.rs +784 -0
- data/rust/codegen/src/naming.rs +286 -0
- data/rust/codegen/src/ports.rs +208 -0
- data/rust/codegen/src/prelude.rs +116 -0
- data/rust/codegen/src/queries.rs +786 -0
- data/rust/codegen/src/reactions.rs +532 -0
- data/rust/codegen/src/read_models.rs +697 -0
- data/rust/codegen/src/reference_specs.rs +40 -0
- data/rust/codegen/src/registry.rs +966 -0
- data/rust/codegen/src/reserved_names.rs +76 -0
- data/rust/codegen/src/shared.rs +93 -0
- data/rust/codegen/src/skip_reason.rs +25 -0
- data/rust/codegen/src/types.rs +362 -0
- data/rust/host/.cargo/config.toml +3 -0
- data/rust/host/.gitignore +1 -0
- data/rust/host/Cargo.lock +4297 -0
- data/rust/host/Cargo.toml +61 -0
- data/rust/host/HECKS_RELEASE +1 -0
- data/rust/host/rds-ca-bundle.pem +2736 -0
- data/rust/host/src/api.rs +1596 -0
- data/rust/host/src/approval.rs +652 -0
- data/rust/host/src/auth.rs +1287 -0
- data/rust/host/src/bin/expr_harness.rs +46 -0
- data/rust/host/src/bin/lineage_harness.rs +119 -0
- data/rust/host/src/bin/mint_harness.rs +135 -0
- data/rust/host/src/checkout.rs +265 -0
- data/rust/host/src/dispatch.rs +1443 -0
- data/rust/host/src/expr_json.rs +1117 -0
- data/rust/host/src/field_hints.rs +52 -0
- data/rust/host/src/ir.rs +733 -0
- data/rust/host/src/journal.rs +874 -0
- data/rust/host/src/lambda_client.rs +378 -0
- data/rust/host/src/log.rs +147 -0
- data/rust/host/src/main.rs +474 -0
- data/rust/host/src/mint.rs +1865 -0
- data/rust/host/src/payments/keystore.rs +330 -0
- data/rust/host/src/payments/tests.rs +1400 -0
- data/rust/host/src/payments.rs +767 -0
- data/rust/host/src/presentation.rs +698 -0
- data/rust/host/src/presentation_write.rs +1431 -0
- data/rust/host/src/query_step.rs +149 -0
- data/rust/host/src/rate_limit.rs +904 -0
- data/rust/host/src/reference_transform.rs +241 -0
- data/rust/host/src/reference_validate.rs +338 -0
- data/rust/host/src/resend.rs +296 -0
- data/rust/host/src/secrets.rs +106 -0
- data/rust/host/src/server.rs +663 -0
- data/rust/host/src/storage_shape.rs +175 -0
- data/rust/host/src/test_pg.rs +40 -0
- data/rust/host/src/ui_schema.rs +1351 -0
- data/rust/host/src/wasm_runner.rs +191 -0
- data/rust/host/src/web/newsletter/cooldown.rs +126 -0
- data/rust/host/src/web/newsletter/tests.rs +104 -0
- data/rust/host/src/web/newsletter.rs +310 -0
- data/rust/host/src/web/newsletter_send.rs +357 -0
- data/rust/host/src/web/registrations.rs +1505 -0
- data/rust/host/src/web.rs +2937 -0
- data/rust/lsp/.gitignore +1 -0
- data/rust/lsp/Cargo.lock +7 -0
- data/rust/lsp/Cargo.toml +16 -0
- data/rust/lsp/README.md +133 -0
- data/rust/lsp/src/diagnostics.rs +165 -0
- data/rust/lsp/src/json.rs +385 -0
- data/rust/lsp/src/main.rs +399 -0
- data/rust/lsp/src/outline.rs +177 -0
- data/rust/lsp/src/rpc.rs +67 -0
- data/rust/parser/.cargo/config.toml +5 -0
- data/rust/parser/.gitignore +1 -0
- data/rust/parser/Cargo.lock +7 -0
- data/rust/parser/Cargo.toml +21 -0
- data/rust/parser/src/build/closed_sets.rs +27 -0
- data/rust/parser/src/build/identity.rs +276 -0
- data/rust/parser/src/build/mod.rs +12 -0
- data/rust/parser/src/build/naming.rs +141 -0
- data/rust/parser/src/build/pattern_subset.rs +161 -0
- data/rust/parser/src/build/query_derive.rs +72 -0
- data/rust/parser/src/build/query_inference.rs +269 -0
- data/rust/parser/src/build/query_options.rs +100 -0
- data/rust/parser/src/build/read_model.rs +94 -0
- data/rust/parser/src/build/references.rs +32 -0
- data/rust/parser/src/canonical.rs +114 -0
- data/rust/parser/src/diag.rs +55 -0
- data/rust/parser/src/emit.rs +953 -0
- data/rust/parser/src/expr/ast_json.rs +147 -0
- data/rust/parser/src/expr/evaluator.rs +81 -0
- data/rust/parser/src/expr/mod.rs +84 -0
- data/rust/parser/src/expr/resolver.rs +497 -0
- data/rust/parser/src/ir.rs +387 -0
- data/rust/parser/src/keywords.rs +585 -0
- data/rust/parser/src/lex.rs +662 -0
- data/rust/parser/src/main.rs +252 -0
- data/rust/parser/src/parse/aggregate.rs +612 -0
- data/rust/parser/src/parse/chapter.rs +517 -0
- data/rust/parser/src/parse/command.rs +637 -0
- data/rust/parser/src/parse/domain_port.rs +127 -0
- data/rust/parser/src/parse/entity.rs +527 -0
- data/rust/parser/src/parse/file.rs +67 -0
- data/rust/parser/src/parse/hecksagon.rs +231 -0
- data/rust/parser/src/parse/lifecycle.rs +162 -0
- data/rust/parser/src/parse/mod.rs +1262 -0
- data/rust/parser/src/parse/policy.rs +87 -0
- data/rust/parser/src/parse/process_manager.rs +305 -0
- data/rust/parser/src/parse/query.rs +100 -0
- data/rust/parser/src/parse/read_model.rs +214 -0
- data/rust/parser/src/parse/value_object.rs +250 -0
- data/rust/parser/src/ruby_value.rs +422 -0
- data/rust/project/bridging.rb +257 -0
- data/rust/project/commands.rb +877 -0
- data/rust/project/constraints.rb +86 -0
- data/rust/project/dependency_planning.rb +178 -0
- data/rust/project/domain_generator.rb +980 -0
- data/rust/project/exemplar.rb +148 -0
- data/rust/project/expr_emitter.rb +72 -0
- data/rust/project/fielded.rb +141 -0
- data/rust/project/json_codec.rb +641 -0
- data/rust/project/mutations.rb +721 -0
- data/rust/project/naming.rb +205 -0
- data/rust/project/ports.rb +65 -0
- data/rust/project/queries.rb +493 -0
- data/rust/project/reactions.rb +317 -0
- data/rust/project/read_models.rb +690 -0
- data/rust/project/reference_specs.rb +27 -0
- data/rust/project/registry.rb +396 -0
- data/rust/project/skip_reason.rb +29 -0
- data/rust/project/types.rb +225 -0
- data/rust/project/write_if_changed.rb +83 -0
- data/rust/project.rb +30 -0
- data/rust/project_rust_pipeline.rb +383 -0
- data/rust/src/exemplar/commands.rs +279 -0
- data/rust/src/exemplar/constraints.rs +18 -0
- data/rust/src/exemplar/fielded.rs +280 -0
- data/rust/src/exemplar/json.rs +277 -0
- data/rust/src/exemplar/mod.rs +17 -0
- data/rust/src/exemplar/mutations.rs +80 -0
- data/rust/src/exemplar/queries.rs +33 -0
- data/rust/src/exemplar/reactions.rs +88 -0
- data/rust/src/exemplar/read_models.rs +48 -0
- data/rust/src/exemplar/registry.rs +166 -0
- data/rust/src/exemplar/types.rs +44 -0
- data/rust/src/kernel/attribute_shapes/composite.rs +88 -0
- data/rust/src/kernel/attribute_shapes/list.rs +18 -0
- data/rust/src/kernel/attribute_shapes/mod.rs +44 -0
- data/rust/src/kernel/attribute_shapes/optional.rs +9 -0
- data/rust/src/kernel/attribute_shapes/scalar.rs +39 -0
- data/rust/src/kernel/cli.rs +585 -0
- data/rust/src/kernel/dispatch.rs +1090 -0
- data/rust/src/kernel/expr.rs +458 -0
- data/rust/src/kernel/expression_operators/arithmetic.rs +128 -0
- data/rust/src/kernel/expression_operators/comparison.rs +48 -0
- data/rust/src/kernel/expression_operators/enumeration.rs +232 -0
- data/rust/src/kernel/expression_operators/logical.rs +13 -0
- data/rust/src/kernel/expression_operators/membership.rs +18 -0
- data/rust/src/kernel/expression_operators/mod.rs +68 -0
- data/rust/src/kernel/expression_operators/pattern_match.rs +73 -0
- data/rust/src/kernel/expression_operators/positional.rs +126 -0
- data/rust/src/kernel/expression_operators/presence.rs +101 -0
- data/rust/src/kernel/expression_operators/sign_test.rs +16 -0
- data/rust/src/kernel/expression_operators/sized.rs +35 -0
- data/rust/src/kernel/expression_operators/text.rs +79 -0
- data/rust/src/kernel/expression_operators/to_string.rs +18 -0
- data/rust/src/kernel/json.rs +779 -0
- data/rust/src/kernel/mod.rs +133 -0
- data/rust/src/kernel/named_query.rs +219 -0
- data/rust/src/kernel/orchestrate.rs +1810 -0
- data/rust/src/kernel/pattern.rs +307 -0
- data/rust/src/kernel/query_comparators.rs +206 -0
- data/rust/src/kernel/query_ordering.rs +103 -0
- data/rust/src/kernel/read_model.rs +914 -0
- data/rust/src/kernel/reference_lookup.rs +149 -0
- data/rust/src/kernel/repository.rs +468 -0
- data/rust/src/kernel/routing.rs +612 -0
- data/rust/src/kernel/vocab/aggregate_dispatch_order.rs +118 -0
- data/rust/src/kernel/vocab/entity_dispatch_order.rs +114 -0
- data/rust/src/kernel/vocab/field_hint.rs +70 -0
- data/rust/src/kernel/vocab/mod.rs +20 -0
- data/rust/src/kernel/vocab/query_comparator.rs +65 -0
- data/rust/src/kernel/vocab/refusal_template.rs +1592 -0
- data/rust/src/lib.rs +8 -0
- data/rust/src/main.rs +16 -0
- data/rust/web/.gitignore +1 -0
- data/rust/web/Cargo.lock +119 -0
- data/rust/web/Cargo.toml +18 -0
- data/rust/web/src/lib.rs +8 -0
- metadata +477 -12
- data/lib/hecks/facade/cli_door.rb +0 -96
- data/lib/hecks/facade/cli_runner.rb +0 -127
- data/lib/hecks/mcp_door_scope.rb +0 -95
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c04beedd84550f06db74d93d28c907eee4a0a913f6dfb619d84a1844faefeb13
|
|
4
|
+
data.tar.gz: 7b3cf71a37bbc83fa80c14eace35831f4b9bceaa789affbda6e2b1158e1ef39e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fdf38f7f5ece37807699026ff6166408f948a827aa59d4cec712ad48a686a90d932ec49ac083853a141654a50bfbc1ade18a0c3538126821ecb187128966c155
|
|
7
|
+
data.tar.gz: 03ccb78bc4b99292abc6e39ae74b35179254583fb41f735f116da2cacec4709971c8eb36c02fdc0e0ebe13b742b58311fe8e01dd1731e2c40efcaa0a430dcbf4
|
data/exe/hecks
CHANGED
|
@@ -1,11 +1,56 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
|
|
3
|
-
#
|
|
4
|
-
#
|
|
3
|
+
# Hecks's command line — GENERATED by hecks project_cli. Do not edit.
|
|
4
|
+
#
|
|
5
|
+
# A launcher, not a CLI: the verbs, their arguments and their refusals are
|
|
6
|
+
# projected from the bluebook beside it every time this runs, so a change
|
|
7
|
+
# to the chapter shows up here without re-minting anything.
|
|
8
|
+
#
|
|
9
|
+
# exe/hecks every verb, and every question
|
|
10
|
+
# exe/hecks <verb> --help what it wants, and how it refuses
|
|
11
|
+
|
|
12
|
+
Encoding.default_external = Encoding::UTF_8
|
|
13
|
+
Encoding.default_internal = Encoding::UTF_8
|
|
5
14
|
|
|
6
|
-
# The gem's own `lib` goes first, as for every `bin/` script, so this also
|
|
7
|
-
# runs straight from a checkout.
|
|
8
15
|
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
9
|
-
require "hecks/cli"
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
# The names the gem has always shipped keep their positional forms.
|
|
18
|
+
LEGACY = %w[run docs narrate ir stores model_check smoke_test project_diagrams project_cli mcp].freeze
|
|
19
|
+
if LEGACY.include?(ARGV.first)
|
|
20
|
+
require "hecks/cli"
|
|
21
|
+
exit Hecks::CLI.start(ARGV) unless Hecks::CLI.launcher_form?(ARGV)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
require "hecks"
|
|
25
|
+
|
|
26
|
+
# Usage is answered from the projected chapter alone: no adapter is bound and no
|
|
27
|
+
# database is opened. Only a line that runs a verb boots the domain.
|
|
28
|
+
domain = File.expand_path("../lib/hecks/hecks", __dir__)
|
|
29
|
+
program = "hecks"
|
|
30
|
+
described = begin
|
|
31
|
+
Hecks.describe(domain)
|
|
32
|
+
rescue StandardError => e
|
|
33
|
+
abort "cannot open Hecks: #{e.message.lines.first.strip}"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
text, status, reason = Hecks::Doors::CliRunner.usage(
|
|
37
|
+
runtime: described, argv: ARGV, program: program
|
|
38
|
+
)
|
|
39
|
+
unless text
|
|
40
|
+
runtime = begin
|
|
41
|
+
Hecks.boot(domain, install_doors: false)
|
|
42
|
+
rescue StandardError => e
|
|
43
|
+
abort "cannot open Hecks: #{e.message.lines.first.strip}"
|
|
44
|
+
end
|
|
45
|
+
text, status, reason = Hecks::Doors::CliRunner.call(
|
|
46
|
+
runtime: runtime, argv: ARGV, program: program
|
|
47
|
+
)
|
|
48
|
+
end
|
|
49
|
+
# A `--wait` run that failed answers its settled record on stdout, so `| jq` reads it
|
|
50
|
+
# either way, and says why on stderr.
|
|
51
|
+
if reason
|
|
52
|
+
puts text
|
|
53
|
+
warn reason
|
|
54
|
+
exit status
|
|
55
|
+
end
|
|
56
|
+
status.zero? ? puts(text) : abort(text)
|
|
@@ -24,7 +24,7 @@ module Hecks
|
|
|
24
24
|
|
|
25
25
|
# Folds the journal into the snapshot and truncates it. Opt-in; never run after a save.
|
|
26
26
|
#
|
|
27
|
-
# This discards the history `entries` returns, which projections and `
|
|
27
|
+
# This discards the history `entries` returns, which projections and `hecks history`
|
|
28
28
|
# read in full, so use it only on an aggregate nothing projects from.
|
|
29
29
|
#
|
|
30
30
|
# The snapshot is written durably before the journal is truncated; a crash between
|
|
@@ -7,7 +7,7 @@ module Hecks
|
|
|
7
7
|
# Runtime::RemoteDispatcher's writes: one Lambda invoke, one JSON round trip.
|
|
8
8
|
#
|
|
9
9
|
# The function name defaults to `"hecks-#{domain.downcase}"`, matching
|
|
10
|
-
# `
|
|
10
|
+
# `hecks deploy project`'s `stack_name` computation. A domain whose stack
|
|
11
11
|
# name doesn't follow that pattern must pass `function` explicitly, via
|
|
12
12
|
# a `.world`'s `persisted_by("Lambda")`/`dispatched_by("Lambda")` block.
|
|
13
13
|
class Client
|
|
@@ -38,7 +38,7 @@ module Hecks
|
|
|
38
38
|
function = setting(settings, :function, nil)
|
|
39
39
|
# `domain` only prefixes the instances lookup; the function to call is named by
|
|
40
40
|
# DOMAIN_NAME (set in a deployed Lambda, where root is always /var/task), else by
|
|
41
|
-
# root's basename, which matches
|
|
41
|
+
# root's basename, which matches hecks deploy project's stack name on a local boot.
|
|
42
42
|
function_domain = ENV["DOMAIN_NAME"] || (root ? File.basename(root) : domain)
|
|
43
43
|
@client = Client.new(domain: function_domain, region: region, function: function)
|
|
44
44
|
@prefix = "#{domain}::#{aggregate.hecks_name}#"
|
|
@@ -34,6 +34,7 @@ module Hecks
|
|
|
34
34
|
@events = []
|
|
35
35
|
@entries = []
|
|
36
36
|
@outbox = []
|
|
37
|
+
@outbox_deliveries = {}
|
|
37
38
|
end
|
|
38
39
|
|
|
39
40
|
# Looks up the current record for one aggregate identity.
|
|
@@ -162,6 +163,7 @@ module Hecks
|
|
|
162
163
|
@events = []
|
|
163
164
|
@entries = []
|
|
164
165
|
@outbox = []
|
|
166
|
+
@outbox_deliveries = {}
|
|
165
167
|
self
|
|
166
168
|
end
|
|
167
169
|
|
|
@@ -185,10 +187,11 @@ module Hecks
|
|
|
185
187
|
# was a duplicate
|
|
186
188
|
def outbox_enqueue(rows)
|
|
187
189
|
rows.filter_map do |row|
|
|
188
|
-
next nil if @
|
|
190
|
+
next nil if @outbox_deliveries.key?(row.delivery_id)
|
|
189
191
|
|
|
190
192
|
row.id = @outbox.size + 1
|
|
191
193
|
@outbox << row
|
|
194
|
+
@outbox_deliveries[row.delivery_id] = true
|
|
192
195
|
row
|
|
193
196
|
end
|
|
194
197
|
end
|
|
@@ -199,7 +202,7 @@ module Hecks
|
|
|
199
202
|
# @return [Boolean] true when the row was pending and is now claimed; false when it is
|
|
200
203
|
# unknown or not pending
|
|
201
204
|
def outbox_claim(id) # rubocop:disable Naming/PredicateMethod
|
|
202
|
-
row =
|
|
205
|
+
row = outbox_row(id)
|
|
203
206
|
return false unless row&.pending?
|
|
204
207
|
|
|
205
208
|
row.status = "claimed"
|
|
@@ -215,7 +218,7 @@ module Hecks
|
|
|
215
218
|
# @param error [String, nil] the failure description, or nil to clear it
|
|
216
219
|
# @return [Boolean] true when the row exists and was updated; false when no row has `id`
|
|
217
220
|
def outbox_settle(id, status:, error: nil) # rubocop:disable Naming/PredicateMethod
|
|
218
|
-
row =
|
|
221
|
+
row = outbox_row(id) or return false
|
|
219
222
|
row.status = status.to_s
|
|
220
223
|
row.error = error
|
|
221
224
|
true
|
|
@@ -233,6 +236,16 @@ module Hecks
|
|
|
233
236
|
|
|
234
237
|
private
|
|
235
238
|
|
|
239
|
+
# Finds a held outbox row by id in constant time.
|
|
240
|
+
#
|
|
241
|
+
# Ids are assigned as the 1-based position at enqueue and rows are never
|
|
242
|
+
# removed, so the id is the row's index plus one.
|
|
243
|
+
def outbox_row(id)
|
|
244
|
+
return nil unless id.is_a?(Integer) && id >= 1
|
|
245
|
+
|
|
246
|
+
@outbox[id - 1]
|
|
247
|
+
end
|
|
248
|
+
|
|
236
249
|
# Skips the codec copy and rehydration round trip while judging the
|
|
237
250
|
# self-hosted grammar (S17, ADR 0026), where re-validating already-valid
|
|
238
251
|
# entity state costs O(N) per save and O(N^2) across an N-row table.
|
|
@@ -38,8 +38,12 @@ module Hecks
|
|
|
38
38
|
# The failing call still raises and is never retried: it may have reached the server.
|
|
39
39
|
# A failed reconnect is swallowed so it does not mask the original error.
|
|
40
40
|
def reconnect!
|
|
41
|
-
@db
|
|
42
|
-
|
|
41
|
+
if @db.respond_to?(:reconnect!)
|
|
42
|
+
@db.reconnect!
|
|
43
|
+
else
|
|
44
|
+
@db = self.class.connect_for(@aggregate.name, @settings)
|
|
45
|
+
end
|
|
46
|
+
rescue PG::Error, Runtime::WiringError
|
|
43
47
|
nil
|
|
44
48
|
end
|
|
45
49
|
end
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
require "monitor"
|
|
2
|
+
|
|
3
|
+
module Hecks
|
|
4
|
+
module Adapters
|
|
5
|
+
# One Postgres connection shared by every `Postgres` or `PostgresEra` adapter of a process
|
|
6
|
+
# that targets the same database and schema, so a domain's connection count does not grow
|
|
7
|
+
# with its aggregates. Each adapter class shares only with its own kind, because each opens
|
|
8
|
+
# its connection its own way.
|
|
9
|
+
#
|
|
10
|
+
# Every call runs under one re-entrant monitor, and a transaction holds it from BEGIN to
|
|
11
|
+
# COMMIT, so a second thread's statements never interleave into another thread's
|
|
12
|
+
# transaction. The owning thread re-enters freely, so a nested `transaction` joins the open
|
|
13
|
+
# one, whichever aggregate's adapter opened it.
|
|
14
|
+
class PostgresSharedConnection
|
|
15
|
+
REGISTRY = {} # rubocop:disable Style/MutableConstant
|
|
16
|
+
REGISTRY_LOCK = Mutex.new
|
|
17
|
+
private_constant :REGISTRY, :REGISTRY_LOCK
|
|
18
|
+
|
|
19
|
+
# Runs in a forked child right after the fork, before any of its code.
|
|
20
|
+
#
|
|
21
|
+
# A child inherits its parent's sockets, and libpq sends a Terminate on the socket when
|
|
22
|
+
# the child's copy of the connection is finalized at exit, which would end the parent's
|
|
23
|
+
# session. The child's copy of each socket fd is pointed at the null device, so that
|
|
24
|
+
# Terminate goes nowhere, and the child forgets the handles without `finish`.
|
|
25
|
+
#
|
|
26
|
+
# @return [void]
|
|
27
|
+
def self.disown_inherited!
|
|
28
|
+
REGISTRY.each_value(&:disown!)
|
|
29
|
+
REGISTRY.clear
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Prepended to `Process` so every `fork`, `Process.fork` and `Kernel#fork` disowns the
|
|
33
|
+
# shared connections in the child.
|
|
34
|
+
module ForkGuard
|
|
35
|
+
# @return [Integer, nil] the child's pid in the parent, nil in the child
|
|
36
|
+
def _fork
|
|
37
|
+
pid = super
|
|
38
|
+
PostgresSharedConnection.disown_inherited! if pid.zero?
|
|
39
|
+
pid
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
Process.singleton_class.prepend(ForkGuard)
|
|
43
|
+
|
|
44
|
+
# Returns the process's shared connection for a database and schema, opening it on first use.
|
|
45
|
+
#
|
|
46
|
+
# The key includes the pid, so a forked child opens its own instead of sharing its
|
|
47
|
+
# parent's socket.
|
|
48
|
+
#
|
|
49
|
+
# @param name [String] the domain or aggregate name, used only in refusal messages
|
|
50
|
+
# @param settings [Hash{Symbol, String => Object}] `database` and optional `schema`
|
|
51
|
+
# @param connector [#connect_for] the adapter class that opens the connection
|
|
52
|
+
# @return [PostgresSharedConnection] the shared handle, connected
|
|
53
|
+
# @raise [Runtime::WiringError] if `database` is missing or the connection is refused
|
|
54
|
+
def self.for(name, settings, connector:)
|
|
55
|
+
key = [Process.pid, connector, setting(settings, :database), setting(settings, :schema)]
|
|
56
|
+
REGISTRY_LOCK.synchronize do
|
|
57
|
+
handle = REGISTRY[key] ||= new(name, settings, connector: connector)
|
|
58
|
+
handle.reconnect! if handle.dead?
|
|
59
|
+
handle
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Reads one setting under its Symbol or String spelling as a string.
|
|
64
|
+
#
|
|
65
|
+
# @param settings [Hash{Symbol, String => Object}] the binding's settings
|
|
66
|
+
# @param key [Symbol] the setting's name
|
|
67
|
+
# @return [String] the value, empty when absent
|
|
68
|
+
def self.setting(settings, key)
|
|
69
|
+
(settings.key?(key) ? settings[key] : settings[key.to_s]).to_s
|
|
70
|
+
end
|
|
71
|
+
private_class_method :setting
|
|
72
|
+
|
|
73
|
+
# Counts the shared connections this process holds open.
|
|
74
|
+
#
|
|
75
|
+
# @return [Integer] how many database and schema pairs have a live shared connection
|
|
76
|
+
def self.open_count = REGISTRY_LOCK.synchronize { REGISTRY.values.count { |handle| !handle.dead? } }
|
|
77
|
+
|
|
78
|
+
# Closes every shared connection and forgets it; the next `for` opens a fresh one.
|
|
79
|
+
#
|
|
80
|
+
# @return [void]
|
|
81
|
+
def self.close_all!
|
|
82
|
+
REGISTRY_LOCK.synchronize do
|
|
83
|
+
REGISTRY.each_value(&:close)
|
|
84
|
+
REGISTRY.clear
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# @param name [String] the domain or aggregate name, used only in refusal messages
|
|
89
|
+
# @param settings [Hash{Symbol, String => Object}] `database` and optional `schema`
|
|
90
|
+
# @param connector [#connect_for] the adapter class that opens the connection
|
|
91
|
+
# @raise [Runtime::WiringError] if `database` is missing or the connection is refused
|
|
92
|
+
def initialize(name, settings, connector:)
|
|
93
|
+
@name = name
|
|
94
|
+
@settings = settings
|
|
95
|
+
@connector = connector
|
|
96
|
+
@monitor = Monitor.new
|
|
97
|
+
@conn = connector.connect_for(name, settings)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Runs one parameterless statement under the connection's monitor.
|
|
101
|
+
#
|
|
102
|
+
# @param sql [String] the statement
|
|
103
|
+
# @return [PG::Result] the statement's result
|
|
104
|
+
def exec(sql, &) = @monitor.synchronize { @conn.exec(sql, &) }
|
|
105
|
+
|
|
106
|
+
# Runs one statement with bind parameters under the connection's monitor.
|
|
107
|
+
#
|
|
108
|
+
# @param sql [String] the statement, with `$1`-style placeholders
|
|
109
|
+
# @param binds [Array<Object>] one value per placeholder
|
|
110
|
+
# @return [PG::Result] the statement's result
|
|
111
|
+
def exec_params(sql, binds = [], *rest, &) = @monitor.synchronize { @conn.exec_params(sql, binds, *rest, &) }
|
|
112
|
+
|
|
113
|
+
# Reports the server-side transaction state; blocks while another thread's transaction
|
|
114
|
+
# holds the connection, so a caller never mistakes it for its own.
|
|
115
|
+
#
|
|
116
|
+
# @return [Integer] a `PG::PQTRANS_*` constant
|
|
117
|
+
def transaction_status = @monitor.synchronize { @conn.transaction_status }
|
|
118
|
+
|
|
119
|
+
# Runs the block in one transaction, joining one the calling thread already holds.
|
|
120
|
+
#
|
|
121
|
+
# @yield the writes to commit together; an exception rolls the outermost one back
|
|
122
|
+
# @return [Object] the block's own value
|
|
123
|
+
def transaction(&block)
|
|
124
|
+
@monitor.synchronize do
|
|
125
|
+
next yield if @conn.transaction_status != PG::PQTRANS_IDLE
|
|
126
|
+
|
|
127
|
+
@conn.transaction(&block)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Reports the server process id serving the connection.
|
|
132
|
+
#
|
|
133
|
+
# @return [Integer] the backend pid
|
|
134
|
+
def backend_pid = @monitor.synchronize { @conn.backend_pid }
|
|
135
|
+
|
|
136
|
+
# Quotes an identifier; needs no connection round trip.
|
|
137
|
+
#
|
|
138
|
+
# @param name [String, Symbol] the identifier
|
|
139
|
+
# @return [String] the double-quoted identifier
|
|
140
|
+
def quote_ident(name) = PG::Connection.quote_ident(name.to_s)
|
|
141
|
+
|
|
142
|
+
# Reports whether the underlying socket is closed or broken.
|
|
143
|
+
#
|
|
144
|
+
# @return [Boolean] true when the connection cannot run statements
|
|
145
|
+
def dead? = @monitor.synchronize { @conn.finished? || @conn.status != PG::CONNECTION_OK }
|
|
146
|
+
|
|
147
|
+
# Replaces the connection when it is dead; a no-op when another caller already did.
|
|
148
|
+
#
|
|
149
|
+
# @return [void]
|
|
150
|
+
# @raise [Runtime::WiringError] if the new connection is refused
|
|
151
|
+
def reconnect!
|
|
152
|
+
@monitor.synchronize do
|
|
153
|
+
next unless dead?
|
|
154
|
+
|
|
155
|
+
@conn.close unless @conn.finished?
|
|
156
|
+
@conn = @connector.connect_for(@name, @settings)
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Detaches this handle's socket from the parent's session in a forked child: the child's
|
|
161
|
+
# fd is repointed at the null device, so nothing the child's copy of the connection writes
|
|
162
|
+
# (statements, Terminate) reaches the parent's server session. Takes no lock, since the
|
|
163
|
+
# child holds none of the parent's monitors.
|
|
164
|
+
#
|
|
165
|
+
# @return [void]
|
|
166
|
+
def disown!
|
|
167
|
+
return if @conn.finished?
|
|
168
|
+
|
|
169
|
+
IO.for_fd(@conn.socket, autoclose: false).reopen(File::NULL, "r+")
|
|
170
|
+
rescue StandardError
|
|
171
|
+
nil
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Closes the underlying connection.
|
|
175
|
+
#
|
|
176
|
+
# @return [void]
|
|
177
|
+
def close = @monitor.synchronize { @conn.close unless @conn.finished? }
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
@@ -11,6 +11,7 @@ require_relative "../../runtime/errors"
|
|
|
11
11
|
require_relative "../../runtime/event"
|
|
12
12
|
require_relative "postgres/outbox"
|
|
13
13
|
require_relative "postgres/reconnect"
|
|
14
|
+
require_relative "postgres/shared_connection"
|
|
14
15
|
require_relative "../../runtime/instance"
|
|
15
16
|
|
|
16
17
|
module Hecks
|
|
@@ -79,7 +80,8 @@ module Hecks
|
|
|
79
80
|
"cannot bind Postgres at #{declared} for #{name}: #{e.message.strip}"
|
|
80
81
|
end
|
|
81
82
|
|
|
82
|
-
#
|
|
83
|
+
# Joins the process's shared connection for the declared database and schema, then
|
|
84
|
+
# creates the aggregate, journal, event, saga and outbox tables if absent.
|
|
83
85
|
#
|
|
84
86
|
# @param aggregate [Bluebook::Aggregate] the aggregate whose table this adapter owns
|
|
85
87
|
# @param settings [Hash{Symbol, String => Object}] world settings for the binding:
|
|
@@ -93,7 +95,7 @@ module Hecks
|
|
|
93
95
|
def initialize(aggregate:, settings: {}, root: nil)
|
|
94
96
|
@aggregate = aggregate
|
|
95
97
|
@settings = settings
|
|
96
|
-
@db =
|
|
98
|
+
@db = PostgresSharedConnection.for(aggregate.name, settings, connector: self.class)
|
|
97
99
|
# Scopes saga rows; falls back to the aggregate's storage name when
|
|
98
100
|
# settings gives no domain (e.g. a directly-instantiated adapter).
|
|
99
101
|
@domain = (
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
require "monitor"
|
|
1
2
|
require "prism"
|
|
2
3
|
require_relative "../../bluebook/expression/canonical_form"
|
|
3
4
|
|
|
@@ -14,6 +15,16 @@ module Hecks
|
|
|
14
15
|
# rubocop:disable-next Style/MutableConstant
|
|
15
16
|
TREES = {}
|
|
16
17
|
|
|
18
|
+
# The first block node starting on each line, per parsed tree (by identity), built by one
|
|
19
|
+
# walk of the tree the first time a block in its file is looked up. Dropped with its tree
|
|
20
|
+
# by #forget/#forget_all.
|
|
21
|
+
BLOCKS_BY_LINE = {}.compare_by_identity
|
|
22
|
+
|
|
23
|
+
# Guards `TREES` and `BLOCKS_BY_LINE` together, so a parse or an index build never
|
|
24
|
+
# interleaves with a `forget` that drops the same tree. Reentrant: `block_node_at`
|
|
25
|
+
# calls `tree_for` under it.
|
|
26
|
+
LOCK = Monitor.new
|
|
27
|
+
|
|
17
28
|
module_function
|
|
18
29
|
|
|
19
30
|
# Recovers a block's body as canonical source text.
|
|
@@ -47,14 +58,25 @@ module Hecks
|
|
|
47
58
|
# @return [Prism::BlockNode, nil] the first block node found starting on `line`, or nil
|
|
48
59
|
# if none does
|
|
49
60
|
def block_node_at(file, line)
|
|
50
|
-
|
|
51
|
-
|
|
61
|
+
LOCK.synchronize do
|
|
62
|
+
tree = tree_for(file)
|
|
63
|
+
BLOCKS_BY_LINE[tree] ||= blocks_by_line(tree)
|
|
64
|
+
BLOCKS_BY_LINE[tree][line]
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Indexes a tree's block nodes by the line they start on, keeping the first in walk order.
|
|
69
|
+
#
|
|
70
|
+
# @param tree [Prism::ProgramNode] a parsed file's root node
|
|
71
|
+
# @return [Hash{Integer => Prism::BlockNode}] block node by 1-based start line
|
|
72
|
+
def blocks_by_line(tree)
|
|
73
|
+
index = {}
|
|
74
|
+
walk(tree) do |node|
|
|
52
75
|
next unless node.is_a?(::Prism::BlockNode)
|
|
53
|
-
next unless node.location.start_line == line
|
|
54
76
|
|
|
55
|
-
|
|
77
|
+
index[node.location.start_line] ||= node
|
|
56
78
|
end
|
|
57
|
-
|
|
79
|
+
index
|
|
58
80
|
end
|
|
59
81
|
|
|
60
82
|
# Parses a file with `prism`, caching the result for the life of the process.
|
|
@@ -65,7 +87,7 @@ module Hecks
|
|
|
65
87
|
# ::Prism.parse_file reads the file at the C-extension level, bypassing
|
|
66
88
|
# Ruby's File/IO layer — invisible to tools that virtualize the filesystem
|
|
67
89
|
# there (e.g. tebako's memfs). Read through File.read first so they intercept it.
|
|
68
|
-
TREES[file] ||= ::Prism.parse(File.read(file)).value
|
|
90
|
+
LOCK.synchronize { TREES[file] ||= ::Prism.parse(File.read(file)).value }
|
|
69
91
|
end
|
|
70
92
|
|
|
71
93
|
# Drops one file from the process-wide parse cache, for a caller (`Hecks::Codemod`)
|
|
@@ -74,12 +96,23 @@ module Hecks
|
|
|
74
96
|
# @param file [String] the file path to drop from the cache
|
|
75
97
|
# @return [Prism::ProgramNode, nil] the cached tree that was removed, or nil if
|
|
76
98
|
# nothing was cached for `file`
|
|
77
|
-
def forget(file)
|
|
99
|
+
def forget(file)
|
|
100
|
+
LOCK.synchronize do
|
|
101
|
+
tree = TREES.delete(file)
|
|
102
|
+
BLOCKS_BY_LINE.delete(tree)
|
|
103
|
+
tree
|
|
104
|
+
end
|
|
105
|
+
end
|
|
78
106
|
|
|
79
107
|
# Drops every cached parse tree.
|
|
80
108
|
#
|
|
81
109
|
# @return [Hash] the now-empty cache
|
|
82
|
-
def forget_all
|
|
110
|
+
def forget_all
|
|
111
|
+
LOCK.synchronize do
|
|
112
|
+
BLOCKS_BY_LINE.clear
|
|
113
|
+
TREES.clear
|
|
114
|
+
end
|
|
115
|
+
end
|
|
83
116
|
|
|
84
117
|
# Visits `node` and every descendant depth-first, calling `visit` on each.
|
|
85
118
|
#
|
|
@@ -5,8 +5,21 @@ require "fileutils"
|
|
|
5
5
|
module Hecks
|
|
6
6
|
module Adapters
|
|
7
7
|
# The imperative half of tenant provisioning, behind `Deploy::Tenant.port
|
|
8
|
-
# "TenantProvisioning"
|
|
8
|
+
# "TenantProvisioning"`, for `Tenant.Provision` and for hecks deploy provision; booting the
|
|
9
|
+
# domain and its capability gate stay in hecks deploy provision.
|
|
9
10
|
class TenantProvisioner
|
|
11
|
+
# Raised when a value is outside its allow-list or the overlay path leaves `environments/`.
|
|
12
|
+
class Refused < ArgumentError; end
|
|
13
|
+
|
|
14
|
+
# Each argument's allow-list. `\A...\z` anchors: `$` would let a newline end the value early.
|
|
15
|
+
IDENTIFIER = /\A[a-z][a-z0-9_]*\z/
|
|
16
|
+
LABEL = /\A[A-Za-z0-9][A-Za-z0-9_ .:-]*\z/
|
|
17
|
+
CONSTANT = /\A[A-Z][A-Za-z0-9]*\z/
|
|
18
|
+
CONNECTION = /\A[^\x00-\x20\x7f]+\z/
|
|
19
|
+
|
|
20
|
+
RULES = { slug: IDENTIFIER, schema: IDENTIFIER, domain: LABEL, realm: LABEL,
|
|
21
|
+
database: CONNECTION, adapter: CONSTANT }.freeze
|
|
22
|
+
|
|
10
23
|
# Accepts the arguments every driven adapter is built with and keeps none of them.
|
|
11
24
|
#
|
|
12
25
|
# @param aggregate [Object, nil] unused
|
|
@@ -14,30 +27,74 @@ module Hecks
|
|
|
14
27
|
# @param root [String, nil] unused
|
|
15
28
|
def initialize(aggregate: nil, settings: {}, root: nil); end
|
|
16
29
|
|
|
17
|
-
# Writes the tenant's environment overlay
|
|
30
|
+
# Writes the tenant's environment overlay under `<directory>/environments/`.
|
|
18
31
|
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
32
|
+
# Each argument arrives bare or wrapped as `{ value: }`; the record's other fields are
|
|
33
|
+
# ignored. Values are allow-listed and written as Ruby string literals.
|
|
21
34
|
#
|
|
22
35
|
# @param slug [String, Hash] names the overlay file
|
|
23
|
-
# @param directory [String, Hash] the domain's own directory on disk
|
|
24
|
-
# @
|
|
25
|
-
|
|
26
|
-
|
|
36
|
+
# @param directory [String, Hash] the domain's own directory on disk (not its declared name)
|
|
37
|
+
# @param adapter [String, Hash, nil] the adapter the overlay binds; PostgresEra when none
|
|
38
|
+
# @return [Hash{Symbol => Object}] `:slug`, `:domain`, `:realm`, `:schema` and `:output`
|
|
39
|
+
# @raise [Refused] when a value is outside its allow-list or the path leaves `environments/`
|
|
40
|
+
def write_overlay(slug:, domain:, realm:, schema:, database:, directory:, adapter: nil, **)
|
|
41
|
+
values = { slug: unwrap(slug), domain: unwrap(domain), realm: unwrap(realm),
|
|
42
|
+
schema: unwrap(schema), database: unwrap(database),
|
|
43
|
+
adapter: adapter_name(adapter) }
|
|
44
|
+
values.each { |name, value| check(name, value) }
|
|
27
45
|
|
|
28
|
-
overlay_path =
|
|
46
|
+
overlay_path = overlay_path_for(unwrap(directory), values[:slug])
|
|
47
|
+
refuse_missing_directory(unwrap(directory))
|
|
29
48
|
FileUtils.mkdir_p(File.dirname(overlay_path))
|
|
30
|
-
File.write(overlay_path,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
49
|
+
File.write(overlay_path, render(values))
|
|
50
|
+
|
|
51
|
+
{ slug: slug, domain: domain, realm: realm, schema: schema,
|
|
52
|
+
output: { value: "wrote #{overlay_path}\n" } }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
# A tenant overlay belongs to a domain that exists: a missing directory is a mistyped path,
|
|
58
|
+
# not a place to create.
|
|
59
|
+
def refuse_missing_directory(directory)
|
|
60
|
+
return if File.directory?(directory.to_s)
|
|
61
|
+
|
|
62
|
+
raise Refused, "directory #{directory.to_s.inspect} is not an existing domain directory"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def render(values)
|
|
66
|
+
<<~WORLD
|
|
67
|
+
Hecks.world #{values[:domain].inspect} do
|
|
68
|
+
realm #{values[:realm].inspect}
|
|
69
|
+
persisted_by(#{values[:adapter].inspect}) do
|
|
70
|
+
database #{values[:database].inspect}
|
|
71
|
+
schema #{values[:schema].inspect}
|
|
36
72
|
end
|
|
37
73
|
end
|
|
38
74
|
WORLD
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def unwrap(argument) = argument.is_a?(Hash) ? argument[:value] : argument
|
|
78
|
+
|
|
79
|
+
def check(name, value)
|
|
80
|
+
return if value.is_a?(String) && RULES.fetch(name).match?(value)
|
|
81
|
+
|
|
82
|
+
raise Refused, "#{name} #{value.inspect} is not an accepted #{name}"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def overlay_path_for(directory, slug)
|
|
86
|
+
raise Refused, "directory is required" unless directory.is_a?(String) && !directory.empty?
|
|
87
|
+
|
|
88
|
+
environments = File.join(File.expand_path(directory), "environments")
|
|
89
|
+
path = File.expand_path("#{slug}.world", environments)
|
|
90
|
+
return path if path.start_with?("#{environments}#{File::SEPARATOR}")
|
|
91
|
+
|
|
92
|
+
raise Refused, "overlay path #{path} is outside #{environments}"
|
|
93
|
+
end
|
|
39
94
|
|
|
40
|
-
|
|
95
|
+
def adapter_name(adapter)
|
|
96
|
+
name = unwrap(adapter)
|
|
97
|
+
name.nil? || name.to_s.empty? ? "PostgresEra" : name
|
|
41
98
|
end
|
|
42
99
|
end
|
|
43
100
|
end
|
|
@@ -81,7 +81,7 @@ module Hecks
|
|
|
81
81
|
# Memory-only-guarded runtime
|
|
82
82
|
# @raise [Malformed] if any aggregate is bound to a non-Memory adapter
|
|
83
83
|
def boot_and_guard(files)
|
|
84
|
-
runtime = Hecks::Runtime::Loader.boot_files(files,
|
|
84
|
+
runtime = Hecks::Runtime::Loader.boot_files(files, install_doors: false)
|
|
85
85
|
guard_memory_only!(runtime)
|
|
86
86
|
runtime
|
|
87
87
|
end
|
data/lib/hecks/behaviors.rb
CHANGED
|
@@ -2,7 +2,7 @@ require_relative "behaviors/dsl"
|
|
|
2
2
|
require_relative "behaviors/expectations"
|
|
3
3
|
require_relative "behaviors/runner"
|
|
4
4
|
|
|
5
|
-
# The `.behaviors` toolkit driven by `
|
|
5
|
+
# The `.behaviors` toolkit driven by `hecks run_behaviors` and `hecks/behaviors/rspec`.
|
|
6
6
|
# Opt-in: not required by lib/hecks.rb, like `Fuzzing`.
|
|
7
7
|
# lib/hecks/fuzzing.rb, the shape this file mirrors) is opt-in too.
|
|
8
8
|
module Hecks
|