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
|
@@ -3,7 +3,7 @@ require_relative "../bluebook/model_check"
|
|
|
3
3
|
|
|
4
4
|
module Hecks
|
|
5
5
|
module CLI
|
|
6
|
-
# The command behind `
|
|
6
|
+
# The command behind `hecks model_check`: static analysis
|
|
7
7
|
# over the IR, printed per domain, exiting non-zero when any error-severity
|
|
8
8
|
# finding is left — unreachable lifecycle states, dead transitions, unreached
|
|
9
9
|
# saga states, dispatches to a nonexistent command, handlers for an event
|
|
@@ -24,7 +24,8 @@ module Hecks
|
|
|
24
24
|
|
|
25
25
|
# Runs the model check `argv` describes and exits with its verdict.
|
|
26
26
|
#
|
|
27
|
-
# @param argv [Array<String>] `--strict`, `--profile NAME` and domain paths
|
|
27
|
+
# @param argv [Array<String>] `--strict`, `--profile NAME`, `--wait` and domain paths;
|
|
28
|
+
# `--wait` is accepted for the launcher's sake, as the verdict is always the exit status
|
|
28
29
|
# @param program [String] the name the usage message calls this command by
|
|
29
30
|
# @param root [String, nil] the repository root, for the corpus sweep and the
|
|
30
31
|
# Rust-target check; nil when there is no checkout
|
|
@@ -34,6 +35,7 @@ module Hecks
|
|
|
34
35
|
def call(argv, program:, root: nil)
|
|
35
36
|
argv = argv.dup
|
|
36
37
|
strict = !argv.delete("--strict").nil?
|
|
38
|
+
argv.delete("--wait")
|
|
37
39
|
profile = take_profile(argv)
|
|
38
40
|
unless profile.nil? || Bluebook::ModelCheck::PROFILES.include?(profile)
|
|
39
41
|
warn "unknown profile #{profile.inspect} (known: #{Bluebook::ModelCheck::PROFILES.join(', ')})"
|
|
@@ -105,11 +107,12 @@ module Hecks
|
|
|
105
107
|
|
|
106
108
|
# A port attaches to its aggregate from the hecksagon, not the bluebook, so a
|
|
107
109
|
# deaf-policy check that skipped it would miss a policy reacting to an event
|
|
108
|
-
# nothing emits. Recording a bind builds IR only; no adapter resolves here.
|
|
110
|
+
# nothing emits. Recording a bind builds IR only; no adapter resolves here. A chapter
|
|
111
|
+
# that ships its ports beside its bluebook (`<name>.ports.hecksagon`) is read with them.
|
|
109
112
|
hecksagons = if File.directory?(source)
|
|
110
113
|
Dir.glob(File.join(source, "*.hecksagon"))
|
|
111
114
|
else
|
|
112
|
-
[source.sub(/\.bluebook\z/,
|
|
115
|
+
[".hecksagon", ".ports.hecksagon"].map { |suffix| source.sub(/\.bluebook\z/, suffix) }
|
|
113
116
|
end
|
|
114
117
|
hecksagons.each { |hecksagon| Kernel.load(hecksagon) if File.exist?(hecksagon) }
|
|
115
118
|
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module Hecks
|
|
6
|
+
module CLI
|
|
7
|
+
# The command behind `hecks record_pattern_cases`: records the expected match results for
|
|
8
|
+
# `pattern:` cases, which `spec/pattern_subset_spec.rb` reads from
|
|
9
|
+
# `spec/corpus/fixtures/patterns.json`.
|
|
10
|
+
#
|
|
11
|
+
# The inputs cover embedded and trailing newlines and non-ASCII digits and word characters.
|
|
12
|
+
module PatternCases
|
|
13
|
+
# Each pattern with the inputs it is matched against.
|
|
14
|
+
CASES = [
|
|
15
|
+
["^[A-Z]{3}-[0-9]{4}$", ["ABC-1234", "abc-1234", "xx\nABC-1234\nyy", "ABC-1234\n", "ABC-١٢٣٤"]],
|
|
16
|
+
["^[0-9]{5}(-[0-9]{4})?$", ["12345", "12345-6789", "1234", "12345\nx", "١٢٣٤٥"]],
|
|
17
|
+
['^[^@ ]+@[^@ ]+\.[^@ ]+$', ["a@b.co", "a b@c.co", "no-at-sign", "a@b.co\nevil", "\na@b.co", "café@x.co"]],
|
|
18
|
+
["^(red|green|blue)$", ["red", "purple", "red\ngreen", "RED", "x\nred"]],
|
|
19
|
+
["^[A-Za-z0-9_]+$", ["abc_1", "a b", "café", "abc\ndef"]],
|
|
20
|
+
['^[ \t]*$', ["", " ", " ", "a", "\n", "\t"]],
|
|
21
|
+
["^[a-f0-9]{8}(-[a-f0-9]{4}){3}-[a-f0-9]{12}$", ["12345678-1234-1234-1234-123456789abc", "nope"]],
|
|
22
|
+
['^\+?[0-9 ()-]{7,20}$', ["+44 20 1234", "abc", "+44 20 1234\nx"]],
|
|
23
|
+
['\Aonly\z', ["only", "only\n", "x\nonly"]],
|
|
24
|
+
["^a.c$", ["abc", "a\nc", "a\tc", "aéc"]]
|
|
25
|
+
].freeze
|
|
26
|
+
|
|
27
|
+
module_function
|
|
28
|
+
|
|
29
|
+
# @return [Array<Hash{String => Object}>] one row per pattern and input, with its match result
|
|
30
|
+
def rows
|
|
31
|
+
CASES.flat_map do |pattern, inputs|
|
|
32
|
+
regexp = Regexp.new(pattern)
|
|
33
|
+
inputs.map { |input| { "pattern" => pattern, "input" => input, "matches" => regexp.match?(input) } }
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Prints the rows as pretty JSON.
|
|
38
|
+
#
|
|
39
|
+
# @param out [IO] where the JSON goes
|
|
40
|
+
# @return [Integer] the exit status, always 0
|
|
41
|
+
def call(out: $stdout)
|
|
42
|
+
out.puts JSON.pretty_generate(rows)
|
|
43
|
+
0
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../forms"
|
|
4
|
+
require_relative "../forms/banking_presentation"
|
|
5
|
+
|
|
6
|
+
module Hecks
|
|
7
|
+
module CLI
|
|
8
|
+
# The command behind `hecks present` and `hecks present`: serves the banking example's rendered
|
|
9
|
+
# forms and views, backed by the in-memory adapter
|
|
10
|
+
# (docs/command-form-and-query-form-bluebook.md).
|
|
11
|
+
#
|
|
12
|
+
# Then, for example, `http://localhost:4567/` lists every exposed chapter,
|
|
13
|
+
# `/Banking/Customer.html` every Customer plus Register, `/Banking/Account/Overdrawn.html` a
|
|
14
|
+
# query view, and `/Banking/Account/Debit` answers the command's shape as JSON.
|
|
15
|
+
module Present
|
|
16
|
+
ROOT = File.expand_path("../../..", __dir__)
|
|
17
|
+
|
|
18
|
+
module_function
|
|
19
|
+
|
|
20
|
+
# Starts a development server and blocks until it stops.
|
|
21
|
+
#
|
|
22
|
+
# @param argv [Array<String>] `[-p port]`
|
|
23
|
+
# @param program [String] the name the refusal calls this command by
|
|
24
|
+
# @param root [String] the checkout whose examples are served
|
|
25
|
+
# @return [void]
|
|
26
|
+
# @raise [SystemExit] when the port argument is refused
|
|
27
|
+
def call(argv, program: "hecks present", root: ROOT)
|
|
28
|
+
require "rackup"
|
|
29
|
+
port, error = Hecks::Forms::PortArgument.parse(argv)
|
|
30
|
+
abort "#{program}: #{error}" if error
|
|
31
|
+
|
|
32
|
+
app = Hecks::Forms::BankingPresentation.app(root: root)
|
|
33
|
+
puts "command_form.bluebook/query_form.bluebook — Banking, in memory — http://localhost:#{port}/"
|
|
34
|
+
puts "development server: no authentication, no CSRF protection, no caller identity — do not expose beyond localhost"
|
|
35
|
+
Rackup::Server.start(app: app, Port: port, server: "webrick")
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -3,35 +3,133 @@ require_relative "../../hecks"
|
|
|
3
3
|
|
|
4
4
|
module Hecks
|
|
5
5
|
module CLI
|
|
6
|
-
# The command behind `
|
|
6
|
+
# The command behind `hecks project_cli` and `hecks project_cli`: writes a
|
|
7
7
|
# command-line launcher beside each domain, named after its bluebook, so
|
|
8
8
|
# `Hecks.bluebook "QualityControl"` in `qa/` becomes `qa/quality_control`.
|
|
9
9
|
#
|
|
10
10
|
# Each launcher is a dozen lines pinning one directory and handing over to
|
|
11
|
-
# `
|
|
11
|
+
# `Doors::CliRunner`; the surface itself is projected at the moment it runs,
|
|
12
12
|
# so editing a chapter changes behaviour without regenerating anything.
|
|
13
|
+
#
|
|
14
|
+
# A chapter whose world's `launcher` setting names an `executable` gets its launcher
|
|
15
|
+
# there instead: the Hecks chapter's is the gem's `exe/hecks`.
|
|
13
16
|
module ProjectCli
|
|
14
17
|
# Build output and other trees under a root that hold no domain a caller means.
|
|
15
18
|
IGNORED = %r{\A(rust|deploy|tmp|coverage)/}
|
|
16
19
|
|
|
20
|
+
# What a chapter name, a domain path and a launcher verb may be made of.
|
|
21
|
+
NAME = /\A[A-Za-z][A-Za-z0-9_ ]*\z/
|
|
22
|
+
PATH = %r{\A[\w./-]+\z}
|
|
23
|
+
VERB = /\A[A-Za-z_][A-Za-z0-9_]*\z/
|
|
24
|
+
|
|
25
|
+
# Set first in an opted-in launcher, before anything reads a file.
|
|
26
|
+
ENCODING = "Encoding.default_external = Encoding::UTF_8\nEncoding.default_internal = Encoding::UTF_8\n\n".freeze
|
|
27
|
+
|
|
28
|
+
# How every launcher ends.
|
|
29
|
+
PLAIN_ENDING = "status.zero? ? puts(text) : abort(text)".freeze
|
|
30
|
+
|
|
31
|
+
# How an opted-in launcher ends: a failed `--wait` run still prints its settled record.
|
|
32
|
+
OPTED_ENDING = <<~LAUNCHER_TAIL.chomp.freeze
|
|
33
|
+
# A `--wait` run that failed answers its settled record on stdout, so `| jq` reads it
|
|
34
|
+
# either way, and says why on stderr.
|
|
35
|
+
if reason
|
|
36
|
+
puts text
|
|
37
|
+
warn reason
|
|
38
|
+
exit status
|
|
39
|
+
end
|
|
40
|
+
status.zero? ? puts(text) : abort(text)
|
|
41
|
+
LAUNCHER_TAIL
|
|
42
|
+
|
|
43
|
+
# The generator's name as an executable launcher's header states it, whoever ran it.
|
|
44
|
+
GENERATOR = "hecks project_cli".freeze
|
|
45
|
+
|
|
17
46
|
module_function
|
|
18
47
|
|
|
19
|
-
#
|
|
20
|
-
#
|
|
48
|
+
# Writes a launcher for each named domain, or for every domain under `root`.
|
|
49
|
+
#
|
|
50
|
+
# `--check` writes nothing and exits 1 when a launcher differs from the one this would
|
|
51
|
+
# write. A domain that cannot boot has none to compare, so it fails too.
|
|
52
|
+
#
|
|
53
|
+
# @param argv [Array<String>] domain paths under `root`, and optionally `--check`
|
|
54
|
+
# @param program [String] how the caller was invoked, named in a launcher's header
|
|
55
|
+
# @param root [String] the directory launchers are written under
|
|
56
|
+
# @param remove_stale_bin [Boolean] delete `root/bin/<name>`, a second front door
|
|
57
|
+
# @return [void]
|
|
58
|
+
# @raise [SystemExit] with status 1 for a launcher out of date, an unreadable domain, a
|
|
59
|
+
# path outside `root` or an unknown flag
|
|
21
60
|
def call(argv, program:, root:, remove_stale_bin: true)
|
|
22
|
-
|
|
61
|
+
flags, paths = argv.partition { |word| word.start_with?("-") }
|
|
62
|
+
unknown = flags - ["--check"]
|
|
63
|
+
abort "hecks project_cli: unknown option #{unknown.first} (the only option is --check)" unless unknown.empty?
|
|
23
64
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
snake = Naming.snake(name)
|
|
27
|
-
file = File.join(root, path, snake)
|
|
65
|
+
check = flags.include?("--check")
|
|
66
|
+
wanted = paths.empty? ? domains(root) : paths.map { |path| under_root(root, path) }
|
|
28
67
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
68
|
+
outcomes = wanted.to_h { |path| [path, one(root, path, program, check, remove_stale_bin)] }
|
|
69
|
+
drifted = outcomes.select { |_, outcome| outcome == :drifted }.keys
|
|
70
|
+
failed = outcomes.select { |_, outcome| outcome == :failed }.keys
|
|
71
|
+
return if drifted.empty? && failed.empty?
|
|
72
|
+
|
|
73
|
+
warn "launcher out of date for: #{drifted.join(', ')}; run `hecks project_cli #{drifted.join(' ')}`" unless drifted.empty?
|
|
74
|
+
warn "no launcher could be checked or written for: #{failed.join(', ')}" unless failed.empty?
|
|
75
|
+
exit 1
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# A domain path as a path under `root`.
|
|
79
|
+
#
|
|
80
|
+
# @param root [String] the directory launchers are written under
|
|
81
|
+
# @param path [String] the path as typed, relative to `root` or absolute
|
|
82
|
+
# @return [String] the path relative to `root`
|
|
83
|
+
# @raise [SystemExit] when the path is outside `root`
|
|
84
|
+
def under_root(root, path)
|
|
85
|
+
expanded = File.expand_path(path, root)
|
|
86
|
+
inside = expanded == root || expanded.start_with?("#{root}/")
|
|
87
|
+
abort "hecks project_cli: #{path.inspect} is outside #{root}" unless inside
|
|
88
|
+
|
|
89
|
+
relative = expanded.delete_prefix(root).delete_prefix("/")
|
|
90
|
+
relative.empty? ? "." : relative
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# @api private
|
|
94
|
+
# @return [Symbol] `:current` when the launcher is (or was made) as generated, `:drifted`
|
|
95
|
+
# when `check` found it out of date, `:failed` when the domain could not be read or its
|
|
96
|
+
# launcher could not be made
|
|
97
|
+
def one(root, path, program, check, remove_stale_bin)
|
|
98
|
+
runtime = Hecks.boot(File.join(root, path), install_doors: false)
|
|
99
|
+
name = runtime.registry.bluebooks.keys.first or raise "it loads no bluebook"
|
|
100
|
+
setting = Doors::LauncherOptions.settings(runtime, name) || {}
|
|
101
|
+
snake = Naming.snake(name)
|
|
102
|
+
executable = setting[:executable]
|
|
103
|
+
label = executable || "#{path}/#{snake}"
|
|
104
|
+
file = File.join(root, label)
|
|
105
|
+
text = launcher(path, name, program, executable: executable, legacy: setting[:legacy],
|
|
106
|
+
opted: !setting.empty?)
|
|
107
|
+
return skip(path, "#{label} is a directory") if File.directory?(file)
|
|
32
108
|
|
|
33
|
-
|
|
109
|
+
return :drifted if check && !(File.file?(file) && File.read(file) == text)
|
|
110
|
+
|
|
111
|
+
unless check
|
|
112
|
+
File.write(file, text)
|
|
113
|
+
FileUtils.chmod("+x", file)
|
|
114
|
+
FileUtils.rm_f(File.join(root, "bin", snake)) if remove_stale_bin && !executable
|
|
34
115
|
end
|
|
116
|
+
puts " #{label} -> #{name}"
|
|
117
|
+
:current
|
|
118
|
+
rescue StandardError => e
|
|
119
|
+
refuse(path, "cannot boot — #{e.message.lines.first.to_s.strip}")
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# @api private
|
|
123
|
+
# @return [Symbol] `:current`: a directory where the launcher would go has nothing to check
|
|
124
|
+
def skip(path, reason)
|
|
125
|
+
warn " #{path}: #{reason}; no launcher written"
|
|
126
|
+
:current
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# @api private
|
|
130
|
+
def refuse(path, reason)
|
|
131
|
+
warn " #{path}: #{reason}"
|
|
132
|
+
:failed
|
|
35
133
|
end
|
|
36
134
|
|
|
37
135
|
def domains(root)
|
|
@@ -44,18 +142,41 @@ module Hecks
|
|
|
44
142
|
.uniq.sort
|
|
45
143
|
end
|
|
46
144
|
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
145
|
+
# The source of one launcher; names and paths go in as they are, so each must be plain.
|
|
146
|
+
# An `opted` one also sets UTF-8 and prints a failed `--wait` record on stdout.
|
|
147
|
+
# @param path [String] the domain's directory under the root
|
|
148
|
+
# @param name [String] the chapter's name
|
|
149
|
+
# @param program [String] the generator's invocation, named in the header
|
|
150
|
+
# @param executable [String, nil] the file's path under the root when it is not beside the
|
|
151
|
+
# domain; its program name is then that file's basename, and its header names the generator
|
|
152
|
+
# @param legacy [Array<String>, nil] verbs an executable hands to `Hecks::CLI` first
|
|
153
|
+
# @param opted [Boolean] whether the chapter's world declares a `launcher` setting
|
|
154
|
+
# @return [String] the Ruby source
|
|
155
|
+
# @raise [ArgumentError] if a name, path, executable or legacy verb is not plain
|
|
156
|
+
def launcher(path, name, program, executable: nil, legacy: nil, opted: !executable.nil?)
|
|
157
|
+
plain!("chapter name", name, NAME)
|
|
158
|
+
plain!("domain path", path, PATH)
|
|
57
159
|
snake = Naming.snake(name)
|
|
58
|
-
|
|
160
|
+
if executable
|
|
161
|
+
plain!("launcher executable", executable, PATH)
|
|
162
|
+
if executable.split("/").include?("..")
|
|
163
|
+
raise ArgumentError, "launcher executable #{executable.inspect} must stay inside the root"
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
up = "../" * File.dirname(executable).split("/").reject { |part| part == "." }.length
|
|
167
|
+
boot = %(File.expand_path("#{up}#{path}", __dir__))
|
|
168
|
+
program = GENERATOR
|
|
169
|
+
where = executable
|
|
170
|
+
shown = File.basename(executable)
|
|
171
|
+
else
|
|
172
|
+
up = "../" * path.count("/").succ
|
|
173
|
+
boot = "__dir__"
|
|
174
|
+
where = shown = "#{path}/#{snake}"
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
handoff = legacy_handoff(Array(legacy)) if executable
|
|
178
|
+
encoding = opted ? ENCODING : ""
|
|
179
|
+
ending = opted ? OPTED_ENDING : PLAIN_ENDING
|
|
59
180
|
|
|
60
181
|
<<~RUBY
|
|
61
182
|
#!/usr/bin/env ruby
|
|
@@ -66,23 +187,94 @@ module Hecks
|
|
|
66
187
|
# projected from the bluebook beside it every time this runs, so a change
|
|
67
188
|
# to the chapter shows up here without re-minting anything.
|
|
68
189
|
#
|
|
69
|
-
# #{
|
|
70
|
-
# #{
|
|
71
|
-
|
|
72
|
-
$LOAD_PATH.unshift File.expand_path("#{up}lib", __dir__)
|
|
190
|
+
# #{where} every verb, and every question
|
|
191
|
+
# #{where} <verb> --help what it wants, and how it refuses
|
|
73
192
|
|
|
193
|
+
#{encoding}$LOAD_PATH.unshift File.expand_path("#{up}lib", __dir__)
|
|
194
|
+
#{handoff}
|
|
74
195
|
require "hecks"
|
|
75
196
|
|
|
197
|
+
#{entry(name, boot, shown, opted)}
|
|
198
|
+
#{ending}
|
|
199
|
+
RUBY
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# @api private
|
|
203
|
+
# @return [String] the launcher's middle: for an opted-in launcher, usage answered from the
|
|
204
|
+
# projection and a boot only for a line that runs a verb; for any other, the boot and
|
|
205
|
+
# dispatch every launcher has always had, byte for byte
|
|
206
|
+
def entry(name, boot, shown, opted)
|
|
207
|
+
opted ? described_entry(name, boot, shown) : plain_entry(name, boot, shown)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# @api private
|
|
211
|
+
# @return [String] the opted-in launcher's middle
|
|
212
|
+
def described_entry(name, boot, shown)
|
|
213
|
+
<<~RUBY.chomp
|
|
214
|
+
# Usage is answered from the projected chapter alone: no adapter is bound and no
|
|
215
|
+
# database is opened. Only a line that runs a verb boots the domain.
|
|
216
|
+
domain = #{boot}
|
|
217
|
+
program = "#{shown}"
|
|
218
|
+
described = begin
|
|
219
|
+
Hecks.describe(domain)
|
|
220
|
+
rescue StandardError => e
|
|
221
|
+
abort "cannot open #{name}: \#{e.message.lines.first.strip}"
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
text, status, reason = Hecks::Doors::CliRunner.usage(
|
|
225
|
+
runtime: described, argv: ARGV, program: program
|
|
226
|
+
)
|
|
227
|
+
unless text
|
|
228
|
+
runtime = begin
|
|
229
|
+
Hecks.boot(domain, install_doors: false)
|
|
230
|
+
rescue StandardError => e
|
|
231
|
+
abort "cannot open #{name}: \#{e.message.lines.first.strip}"
|
|
232
|
+
end
|
|
233
|
+
text, status, reason = Hecks::Doors::CliRunner.call(
|
|
234
|
+
runtime: runtime, argv: ARGV, program: program
|
|
235
|
+
)
|
|
236
|
+
end
|
|
237
|
+
RUBY
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# @api private
|
|
241
|
+
# @return [String] the middle every launcher had before opted-in ones answered usage alone
|
|
242
|
+
def plain_entry(name, boot, shown)
|
|
243
|
+
<<~RUBY.chomp
|
|
76
244
|
runtime = begin
|
|
77
|
-
Hecks.boot(
|
|
245
|
+
Hecks.boot(#{boot}, install_doors: false)
|
|
78
246
|
rescue StandardError => e
|
|
79
247
|
abort "cannot open #{name}: \#{e.message.lines.first.strip}"
|
|
80
248
|
end
|
|
81
249
|
|
|
82
|
-
text, status = Hecks::
|
|
83
|
-
runtime: runtime, argv: ARGV, program: "#{
|
|
250
|
+
text, status = Hecks::Doors::CliRunner.call(
|
|
251
|
+
runtime: runtime, argv: ARGV, program: "#{shown}"
|
|
84
252
|
)
|
|
85
|
-
|
|
253
|
+
RUBY
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# @api private
|
|
257
|
+
def plain!(what, value, pattern)
|
|
258
|
+
return if value.to_s.match?(pattern)
|
|
259
|
+
|
|
260
|
+
raise ArgumentError, "#{what} #{value.to_s.inspect} is not a plain word or path"
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
# @api private
|
|
264
|
+
# @return [String] the lines that hand the legacy verbs to `Hecks::CLI`, or nothing
|
|
265
|
+
def legacy_handoff(legacy)
|
|
266
|
+
return "" if legacy.empty?
|
|
267
|
+
|
|
268
|
+
legacy.each { |verb| plain!("legacy verb", verb, VERB) }
|
|
269
|
+
|
|
270
|
+
<<~RUBY
|
|
271
|
+
|
|
272
|
+
# The names the gem has always shipped keep their positional forms.
|
|
273
|
+
LEGACY = %w[#{legacy.join(' ')}].freeze
|
|
274
|
+
if LEGACY.include?(ARGV.first)
|
|
275
|
+
require "hecks/cli"
|
|
276
|
+
exit Hecks::CLI.start(ARGV) unless Hecks::CLI.launcher_form?(ARGV)
|
|
277
|
+
end
|
|
86
278
|
RUBY
|
|
87
279
|
end
|
|
88
280
|
end
|
|
@@ -2,10 +2,11 @@ require_relative "../../hecks"
|
|
|
2
2
|
|
|
3
3
|
module Hecks
|
|
4
4
|
module CLI
|
|
5
|
-
# The command behind `
|
|
5
|
+
# The command behind `hecks project_diagrams`: boots a
|
|
6
6
|
# domain, finds the chapter it names, and writes its Mermaid diagrams
|
|
7
7
|
# (`Projections::Diagrams`) under `docs/generated/diagrams/<chapter>/` below the
|
|
8
|
-
# root.
|
|
8
|
+
# root. Only this positional form writes; the launcher's `domain=… chapter=…` question
|
|
9
|
+
# prints the same files' text and writes nothing.
|
|
9
10
|
module ProjectDiagrams
|
|
10
11
|
module_function
|
|
11
12
|
|
|
@@ -15,7 +16,7 @@ module Hecks
|
|
|
15
16
|
chapter_name = argv[1] or abort usage
|
|
16
17
|
|
|
17
18
|
runtime = Hecks.boot(File.expand_path(domain_path, Dir.pwd))
|
|
18
|
-
chapter = runtime.registry.bluebook(chapter_name)
|
|
19
|
+
chapter = runtime.registry.bluebook(chapter_name) or abort "no chapter named #{chapter_name}"
|
|
19
20
|
hecksagon = runtime.registry.hecksagon(chapter_name)
|
|
20
21
|
directory = File.expand_path("docs/generated/diagrams/#{Naming.snake(chapter_name)}", root)
|
|
21
22
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require_relative "../../hecks"
|
|
2
|
+
|
|
3
|
+
module Hecks
|
|
4
|
+
module CLI
|
|
5
|
+
# The command behind `hecks glossary`: boots a domain and projects one chapter into its
|
|
6
|
+
# Ubiquitous Language glossary, `glossary.md` plus `html/index.html` rendered from it, in the
|
|
7
|
+
# domain's own `glossary/` folder.
|
|
8
|
+
#
|
|
9
|
+
# A field the deployment marks sensitive (`has_phi(readable_by:)` in the domain's `.hecksagon`)
|
|
10
|
+
# is tagged in the glossary with its category. spec/glossary_spec.rb re-projects every one and
|
|
11
|
+
# refuses a diff, so a committed glossary never lags the bluebook it describes.
|
|
12
|
+
module ProjectGlossary
|
|
13
|
+
module_function
|
|
14
|
+
|
|
15
|
+
# Writes the chapter's glossary and prints each file written.
|
|
16
|
+
#
|
|
17
|
+
# @param argv [Array<String>] the domain path, then the chapter's name
|
|
18
|
+
# @param program [String] the name the usage line shows
|
|
19
|
+
# @return [void]
|
|
20
|
+
# @raise [SystemExit] with the usage line when an argument is missing
|
|
21
|
+
def call(argv, program: "hecks glossary")
|
|
22
|
+
usage = "usage: #{program} <domain-path> <ChapterName>"
|
|
23
|
+
domain_path = argv[0] or abort usage
|
|
24
|
+
chapter_name = argv[1] or abort usage
|
|
25
|
+
|
|
26
|
+
domain = File.expand_path(domain_path, Dir.pwd)
|
|
27
|
+
runtime = Hecks.boot(domain)
|
|
28
|
+
chapter = runtime.registry.bluebook(chapter_name)
|
|
29
|
+
|
|
30
|
+
markings = runtime.registry.pending_privacy_markings.select do |marking|
|
|
31
|
+
marking[:domain].to_s.start_with?("#{chapter_name}::")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
written = Projector.write(
|
|
35
|
+
Projector.call(:glossary, bluebook: chapter, options: { markings: markings }),
|
|
36
|
+
File.join(domain, "glossary"), as: :files
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
puts "wrote #{written.size} file(s):"
|
|
40
|
+
written.each { |path| puts " #{path}" }
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../hecks"
|
|
4
|
+
require_relative "../projection_files"
|
|
5
|
+
|
|
6
|
+
module Hecks
|
|
7
|
+
module CLI
|
|
8
|
+
# The command behind `hecks project_reference`: regenerates `docs/implemented/reference/` from
|
|
9
|
+
# the language's Syntax chapter. Tables come from the declaration; prose is kept from the
|
|
10
|
+
# committed pages.
|
|
11
|
+
module Reference
|
|
12
|
+
module_function
|
|
13
|
+
|
|
14
|
+
# Writes the pages and reports both coverage gates together (`DocCoverage` asks the same
|
|
15
|
+
# as an exit status).
|
|
16
|
+
#
|
|
17
|
+
# @param root [String] the repository root
|
|
18
|
+
# @param out [IO] where the report goes
|
|
19
|
+
# @return [Integer] the exit status, always 0
|
|
20
|
+
def call(root:, out: $stdout)
|
|
21
|
+
directory = File.join(root, "docs/implemented/reference")
|
|
22
|
+
written = Hecks::ProjectionFiles.write(:reference, root: root)
|
|
23
|
+
out.puts "wrote #{written.size - 1} pages to docs/implemented/reference/, " \
|
|
24
|
+
"and regenerated README.md's own indexes"
|
|
25
|
+
{ "prose" => Hecks::Doc::Reference.undocumented(directory),
|
|
26
|
+
"a running example" => Hecks::Doc::Reference.unexemplified(directory) }.each do |owed, missing|
|
|
27
|
+
report(out, owed, missing)
|
|
28
|
+
end
|
|
29
|
+
0
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @param out [IO] where the line goes
|
|
33
|
+
# @param owed [String] what each word owes: prose, or a running example
|
|
34
|
+
# @param missing [Array<String>] the words that lack it
|
|
35
|
+
# @return [void]
|
|
36
|
+
def report(out, owed, missing)
|
|
37
|
+
if missing.empty?
|
|
38
|
+
out.puts "every live word carries #{owed}."
|
|
39
|
+
else
|
|
40
|
+
out.puts "#{missing.size} word(s) still carry no #{owed}:"
|
|
41
|
+
missing.each { |word| out.puts " #{word}" }
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require_relative "../../hecks"
|
|
2
|
+
|
|
3
|
+
module Hecks
|
|
4
|
+
module CLI
|
|
5
|
+
# The logic behind `hecks refresh_projections` and Custodian's `Operation.RefreshProjections`:
|
|
6
|
+
# forces every
|
|
7
|
+
# read-model projection a booted domain declares to catch up now, the same catch-up a boot
|
|
8
|
+
# runs lazily on first read.
|
|
9
|
+
module RefreshProjections
|
|
10
|
+
module_function
|
|
11
|
+
|
|
12
|
+
# Boots the domain `argv` names and refreshes its projections, as `hecks refresh_projections`
|
|
13
|
+
# does.
|
|
14
|
+
#
|
|
15
|
+
# @param argv [Array<String>] the domain directory, first
|
|
16
|
+
# @param program [String] the name the usage message calls this command by
|
|
17
|
+
# @return [Integer] 0
|
|
18
|
+
# @raise [SystemExit] when `argv` is empty
|
|
19
|
+
def run(argv, program: "hecks refresh_projections")
|
|
20
|
+
domain = argv.first or abort "usage: #{program} <domain>"
|
|
21
|
+
call(Hecks.boot(domain))
|
|
22
|
+
0
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Refreshes every projection of every chapter in a booted runtime.
|
|
26
|
+
#
|
|
27
|
+
# @param runtime [Runtime] a booted domain
|
|
28
|
+
# @return [Integer] how many projections were caught up
|
|
29
|
+
def call(runtime)
|
|
30
|
+
refreshed = 0
|
|
31
|
+
runtime.registry.bluebooks.each do |domain, bluebook|
|
|
32
|
+
bluebook.aggregates.each do |aggregate|
|
|
33
|
+
worker = Ports::Projection.worker(runtime.registry, domain, aggregate, policy: :refresh)
|
|
34
|
+
next unless worker
|
|
35
|
+
|
|
36
|
+
worker.catch_up!
|
|
37
|
+
refreshed += 1
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
refreshed
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|