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
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
require "fileutils"
|
|
3
|
+
require "open3"
|
|
4
|
+
require "tmpdir"
|
|
5
|
+
|
|
6
|
+
# Opt-in, all-Rust equivalent of hecks project_rust's default path, selected
|
|
7
|
+
# when HECKS_PARSER=rust and HECKS_CODEGEN=rust; never boots a bluebook DSL.
|
|
8
|
+
module RustProjectPipeline
|
|
9
|
+
ROOT = File.expand_path("..", __dir__).freeze
|
|
10
|
+
PARSER_DIR = File.join(ROOT, "rust/parser").freeze
|
|
11
|
+
CODEGEN_DIR = File.join(ROOT, "rust/codegen").freeze
|
|
12
|
+
PARSER_BIN = File.join(PARSER_DIR, "target/debug/hecks-parse").freeze
|
|
13
|
+
CODEGEN_BIN = File.join(CODEGEN_DIR, "target/debug/hecks-codegen").freeze
|
|
14
|
+
|
|
15
|
+
module_function
|
|
16
|
+
|
|
17
|
+
def call(domain)
|
|
18
|
+
ensure_binaries_built!
|
|
19
|
+
|
|
20
|
+
target_mod_name = File.basename(domain)
|
|
21
|
+
# Becomes a directory name, Rust module identifier, and Cargo feature
|
|
22
|
+
# name below (see Projector.valid_domain_mod_name?).
|
|
23
|
+
unless RustProjection::Projector.valid_domain_mod_name?(target_mod_name)
|
|
24
|
+
abort "hecks project_rust (Rust path): domain name #{target_mod_name.inspect} (from #{domain.inspect}) can't be " \
|
|
25
|
+
"used as-is — it has to double as a Rust module identifier and a Cargo feature name, and this one is " \
|
|
26
|
+
"either not a plain lowercase identifier, is a Rust keyword, or collides with a reserved Cargo.toml " \
|
|
27
|
+
"key (#{RustProjection::Projector::CARGO_RESERVED_DOMAIN_NAMES.join(', ')}). Rename the domain directory."
|
|
28
|
+
end
|
|
29
|
+
bluebook_paths = Dir.glob(File.join(domain, "bluebook", "*.bluebook")).sort
|
|
30
|
+
abort "hecks project_rust (Rust path): #{domain} has no .bluebook files" if bluebook_paths.empty?
|
|
31
|
+
hecksagon_path = File.join(domain, "bluebook", "#{target_mod_name}.hecksagon")
|
|
32
|
+
hecksagon_path = nil unless File.exist?(hecksagon_path)
|
|
33
|
+
|
|
34
|
+
target_chapter_name = header_chapter_name(bluebook_paths.first)
|
|
35
|
+
target_bluebooks = bluebook_paths.select { |path| header_chapter_name(path) == target_chapter_name }
|
|
36
|
+
|
|
37
|
+
uses_framework_names, uses_embryonaut_bluebook_names =
|
|
38
|
+
if hecksagon_path
|
|
39
|
+
resolved = JSON.parse(run_capture!(PARSER_BIN, "resolve", "--chapter", target_chapter_name, hecksagon_path))
|
|
40
|
+
[resolved.fetch("uses_framework"), resolved.fetch("uses_embryonaut_bluebook")]
|
|
41
|
+
else
|
|
42
|
+
[[], []]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
target_files = target_bluebooks + [hecksagon_path].compact
|
|
46
|
+
target_ir_text = derive_append_optionals(run_capture!(PARSER_BIN, "chapter", "--chapter", target_chapter_name, *target_files))
|
|
47
|
+
# Only the target gets a lineage sidecar — matches the default path,
|
|
48
|
+
# which never sets one on a framework chapter either.
|
|
49
|
+
target_ir_text = derive_lineage(target_ir_text, hecksagon_path, sibling_world_path(domain, target_mod_name))
|
|
50
|
+
|
|
51
|
+
# Mirrors hecks project_rust's own Framework.load! resolution. A framework
|
|
52
|
+
# member has no .hecksagon of its own, only its .bluebook.
|
|
53
|
+
chapters = uses_framework_names.map do |fw_name|
|
|
54
|
+
fw_path = Hecks::Framework.members.fetch(fw_name) do
|
|
55
|
+
abort "hecks project_rust (Rust path): uses_framework #{fw_name.inspect} names no known framework member — known: #{Hecks::Framework.members.keys.sort.join(', ')}"
|
|
56
|
+
end
|
|
57
|
+
fw_chapter_name = header_chapter_name(fw_path)
|
|
58
|
+
unless fw_chapter_name == fw_name
|
|
59
|
+
abort "hecks project_rust (Rust path): #{fw_path} declares chapter #{fw_chapter_name.inspect}, but uses_framework named #{fw_name.inspect}"
|
|
60
|
+
end
|
|
61
|
+
fw_ir_text = derive_append_optionals(run_capture!(PARSER_BIN, "chapter", "--chapter", fw_chapter_name, fw_path))
|
|
62
|
+
{
|
|
63
|
+
mod_name: fw_name.downcase,
|
|
64
|
+
source_label: "#{domain} (uses_framework #{fw_name.inspect})",
|
|
65
|
+
ir_text: fw_ir_text
|
|
66
|
+
}
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Mirrors EmbryonautBluebook.load!: every .bluebook file directly under
|
|
70
|
+
# vendor/embryonaut_bluebooks/<name>/bluebook/, sorted. A vendored
|
|
71
|
+
# package has no .hecksagon of its own either, just its .bluebook(s).
|
|
72
|
+
chapters += uses_embryonaut_bluebook_names.map do |pkg_name|
|
|
73
|
+
pkg_dir = File.join(domain, "vendor", "embryonaut_bluebooks", pkg_name.to_s, "bluebook")
|
|
74
|
+
pkg_files = Dir.glob(File.join(pkg_dir, "*.bluebook")).sort
|
|
75
|
+
if pkg_files.empty?
|
|
76
|
+
abort "hecks project_rust (Rust path): uses_embryonaut_bluebook #{pkg_name.inspect} names no vendored " \
|
|
77
|
+
"bluebook at #{pkg_dir} — run hecks vendor #{pkg_name}"
|
|
78
|
+
end
|
|
79
|
+
pkg_chapter_name = header_chapter_name(pkg_files.first)
|
|
80
|
+
expected_chapter_name = Hecks::Naming.pascal(pkg_name.to_s)
|
|
81
|
+
unless pkg_chapter_name == expected_chapter_name
|
|
82
|
+
abort "hecks project_rust (Rust path): #{pkg_files.first} declares chapter #{pkg_chapter_name.inspect}, but " \
|
|
83
|
+
"uses_embryonaut_bluebook #{pkg_name.inspect} expects #{expected_chapter_name.inspect}"
|
|
84
|
+
end
|
|
85
|
+
pkg_bluebooks = pkg_files.select { |path| header_chapter_name(path) == pkg_chapter_name }
|
|
86
|
+
pkg_ir_text = derive_append_optionals(run_capture!(PARSER_BIN, "chapter", "--chapter", pkg_chapter_name, *pkg_bluebooks))
|
|
87
|
+
{
|
|
88
|
+
# Derived from the declared chapter name, not pkg_name.downcase
|
|
89
|
+
# directly — the two diverge once a package name has an underscore.
|
|
90
|
+
mod_name: expected_chapter_name.downcase,
|
|
91
|
+
source_label: "#{domain} (uses_embryonaut_bluebook #{pkg_name.inspect})",
|
|
92
|
+
ir_text: pkg_ir_text
|
|
93
|
+
}
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Framework- and embryonaut_bluebook-derived chapters can collide on
|
|
97
|
+
# mod_name (chapters here is a plain Array, not a Hash), so guard
|
|
98
|
+
# explicitly against two entries overwriting each other's sidecars.
|
|
99
|
+
chapters.group_by { |c| c[:mod_name] }.each_value do |group|
|
|
100
|
+
next if group.size == 1
|
|
101
|
+
|
|
102
|
+
abort "hecks project_rust (Rust path): #{group.map { |c| c[:source_label] }.join(' and ')} both resolve to the " \
|
|
103
|
+
"same generated module #{group.first[:mod_name].inspect} — attach #{target_chapter_name} to at most one " \
|
|
104
|
+
"of them"
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# The self-hosted grammar's own "Bluebook" chapter, read without
|
|
108
|
+
# booting anything.
|
|
109
|
+
meta_files = Hecks::Bluebook::MetaValidator::GRAMMAR_FILES
|
|
110
|
+
meta_ir_text = derive_append_optionals(run_capture!(PARSER_BIN, "chapter", "--chapter", "Bluebook", *meta_files))
|
|
111
|
+
|
|
112
|
+
# `HECKS_RUST_DIR` picks the crate to project into, as it does for hecks project_rust's
|
|
113
|
+
# Ruby path; unset, it is this repository's own `rust/`.
|
|
114
|
+
rust_dir = ENV.fetch("HECKS_RUST_DIR", File.expand_path("../rust", __dir__))
|
|
115
|
+
out_root = File.join(rust_dir, "src/generated")
|
|
116
|
+
FileUtils.mkdir_p(out_root)
|
|
117
|
+
# Only this run's own directories are cleared — other domains coexist
|
|
118
|
+
# on disk.
|
|
119
|
+
FileUtils.rm_rf(File.join(out_root, "meta"))
|
|
120
|
+
FileUtils.rm_rf(File.join(out_root, "active"))
|
|
121
|
+
FileUtils.rm_rf(File.join(out_root, target_mod_name))
|
|
122
|
+
chapters.each { |c| FileUtils.rm_rf(File.join(out_root, c[:mod_name])) }
|
|
123
|
+
|
|
124
|
+
Dir.mktmpdir("hecks-codegen-full") do |tmp|
|
|
125
|
+
meta_ir_path = File.join(tmp, "meta_ir.json")
|
|
126
|
+
File.write(meta_ir_path, meta_ir_text)
|
|
127
|
+
meta_source_label = "the self-hosted language (lib/hecks/language/bluebook)"
|
|
128
|
+
run!(CODEGEN_BIN, "full", out_root, "meta", meta_source_label, meta_ir_path)
|
|
129
|
+
write_sidecars!(File.join(out_root, "meta"), meta_ir_text, meta_source_label)
|
|
130
|
+
|
|
131
|
+
target_ir_path = File.join(tmp, "target_ir.json")
|
|
132
|
+
File.write(target_ir_path, target_ir_text)
|
|
133
|
+
|
|
134
|
+
codegen_args = [out_root, target_mod_name, domain, target_ir_path]
|
|
135
|
+
chapters.each_with_index do |c, i|
|
|
136
|
+
ir_path = File.join(tmp, "chapter_#{i}_ir.json")
|
|
137
|
+
File.write(ir_path, c[:ir_text])
|
|
138
|
+
codegen_args.concat([c[:mod_name], c[:source_label], ir_path])
|
|
139
|
+
end
|
|
140
|
+
run!(CODEGEN_BIN, "full", *codegen_args)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
write_sidecars!(File.join(out_root, target_mod_name), target_ir_text, domain)
|
|
144
|
+
chapters.each { |c| write_sidecars!(File.join(out_root, c[:mod_name]), c[:ir_text], c[:source_label]) }
|
|
145
|
+
|
|
146
|
+
sync_mod_and_cargo!(out_root, target_mod_name)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Applies the same append-optional-field derivation domain_generator.rb
|
|
150
|
+
# applies in Ruby — hecks-parse's own ir.json has not had it applied yet.
|
|
151
|
+
def derive_append_optionals(ir_text)
|
|
152
|
+
ir = JSON.parse(ir_text, symbolize_names: true)
|
|
153
|
+
ir[:aggregates].each do |aggregate|
|
|
154
|
+
value_objects_by_name = aggregate[:value_objects].to_h { |vo| [vo[:name], vo] }
|
|
155
|
+
RustProjection::Projector.mark_append_optional_fields!(aggregate, value_objects_by_name)
|
|
156
|
+
end
|
|
157
|
+
JSON.pretty_generate(ir)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Text-based equivalent of Exporter.lineage — no Runtime::Registry boot.
|
|
161
|
+
def derive_lineage(ir_text, hecksagon_path, world_path = nil)
|
|
162
|
+
ir = JSON.parse(ir_text, symbolize_names: true)
|
|
163
|
+
binds = hecksagon_path ? persistence_binds(hecksagon_path) : {}
|
|
164
|
+
fallback = (world_path && default_adapter_name(world_path, ir[:name])) || "Memory"
|
|
165
|
+
capable_adapters = lineage_capable_adapter_names
|
|
166
|
+
|
|
167
|
+
capable = ir[:aggregates].select do |aggregate|
|
|
168
|
+
adapter_name = binds.fetch(aggregate[:name], fallback)
|
|
169
|
+
capable_adapters.include?(adapter_name)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
ir[:lineage] = {
|
|
173
|
+
capable_aggregates: capable.map { |aggregate| { name: aggregate[:name], storage_name: Hecks::Naming.snake(aggregate[:name]) } }
|
|
174
|
+
}
|
|
175
|
+
JSON.pretty_generate(ir)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Matches only role-less persisted_by binds — the sole authoritative kind.
|
|
179
|
+
def persistence_binds(hecksagon_path)
|
|
180
|
+
text = File.read(hecksagon_path)
|
|
181
|
+
binds = {}
|
|
182
|
+
text.each_line do |line|
|
|
183
|
+
next if line =~ /\brole:/
|
|
184
|
+
next unless line =~ /(?:\w+(?:::\w+)*::)?(\w+)\.persisted_by\(\s*"([^"]+)"/
|
|
185
|
+
|
|
186
|
+
binds[Regexp.last_match(1)] = Regexp.last_match(2)
|
|
187
|
+
end
|
|
188
|
+
binds
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# The target's own `.world` file, if it has one — named for the domain the
|
|
192
|
+
# same way its `.hecksagon` is.
|
|
193
|
+
def sibling_world_path(domain, target_mod_name)
|
|
194
|
+
path = File.join(domain, "bluebook", "#{target_mod_name}.world")
|
|
195
|
+
path if File.exist?(path)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# A .world file may hold several worlds (one per chapter) — only lines
|
|
199
|
+
# inside the target chapter's own Hecks.world block count, and the last
|
|
200
|
+
# default_adapter there wins, matching the Ruby builder.
|
|
201
|
+
def default_adapter_name(world_path, chapter)
|
|
202
|
+
in_target_world = false
|
|
203
|
+
found = nil
|
|
204
|
+
File.foreach(world_path) do |line|
|
|
205
|
+
if (opened = line[/\AHecks\.world[^"]*"([^"]*)"/, 1])
|
|
206
|
+
in_target_world = opened == chapter
|
|
207
|
+
elsif in_target_world && (name = line[/\A\s*default_adapter\s+"([^"]*)"/, 1])
|
|
208
|
+
found = name
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
found
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Read off adapter source directly, so a new lineage-capable adapter
|
|
215
|
+
# needs no change here.
|
|
216
|
+
def lineage_capable_adapter_names
|
|
217
|
+
Dir[File.join(ROOT, "lib/hecks/adapters/driven/*.rb")].filter_map do |path|
|
|
218
|
+
text = File.read(path)
|
|
219
|
+
next unless text.match?(/lineage_capable\?\s*=\s*true/)
|
|
220
|
+
|
|
221
|
+
text[/^\s*class\s+(\w+)/, 1]
|
|
222
|
+
end.compact
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# The declared chapter name off a .bluebook file's own header line.
|
|
226
|
+
def header_chapter_name(path)
|
|
227
|
+
line = File.foreach(path).find { |l| l =~ /\A\s*Hecks\.bluebook\s+"([^"]+)"/ }
|
|
228
|
+
(line && Regexp.last_match(1)) or abort "hecks project_rust (Rust path): #{path} has no 'Hecks.bluebook \"Name\"' header"
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# Writes ir.json byte-identical to hecks-parse's own output — never
|
|
232
|
+
# reparsed or reformatted, to avoid a non-byte-exact diff for no reason.
|
|
233
|
+
def write_sidecars!(mod_dir, ir_text, source_label)
|
|
234
|
+
FileUtils.mkdir_p(mod_dir)
|
|
235
|
+
|
|
236
|
+
ir_json_path = File.join(mod_dir, "ir.json")
|
|
237
|
+
File.write(ir_json_path, ir_text)
|
|
238
|
+
puts "wrote #{ir_json_path}"
|
|
239
|
+
|
|
240
|
+
metadata_path = File.join(mod_dir, "metadata.rs")
|
|
241
|
+
File.open(metadata_path, "w") do |f|
|
|
242
|
+
f.puts "// GENERATED by hecks project_rust — #{source_label}'s own canonical IR,"
|
|
243
|
+
f.puts "// embedded for runtime self-description. Not read by any dispatch"
|
|
244
|
+
f.puts "// function in this module — introspection only."
|
|
245
|
+
f.puts "pub const IR_JSON: &str = #{RustProjection::Projector.rust_string_literal(ir_text)};"
|
|
246
|
+
end
|
|
247
|
+
puts "wrote #{metadata_path}"
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def ensure_binaries_built!
|
|
251
|
+
build!(PARSER_DIR)
|
|
252
|
+
build!(CODEGEN_DIR)
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
def build!(crate_dir)
|
|
256
|
+
ok = system("cargo", "build", chdir: crate_dir, out: $stdout, err: $stderr)
|
|
257
|
+
ok or abort "hecks project_rust (Rust path): cargo build failed in #{crate_dir} — run it there directly to see why"
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def run_capture!(*cmd)
|
|
261
|
+
out, err, status = Open3.capture3(*cmd)
|
|
262
|
+
status.success? or abort "hecks project_rust (Rust path): #{cmd.join(' ')} failed:\n#{err}"
|
|
263
|
+
out
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def run!(*cmd)
|
|
267
|
+
ok = system(*cmd)
|
|
268
|
+
ok or abort "hecks project_rust (Rust path): #{cmd.join(' ')} failed"
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
# Duplicates hecks project_rust's own default-path tail (root mod.rs +
|
|
272
|
+
# Cargo.toml feature sync) rather than extracting a shared method, so
|
|
273
|
+
# the default path's own body stays byte-for-byte untouched.
|
|
274
|
+
def sync_mod_and_cargo!(out_root, target_mod_name)
|
|
275
|
+
all_dirs = Dir.children(out_root).select { |name| File.directory?(File.join(out_root, name)) }.sort
|
|
276
|
+
domains = all_dirs.select { |name| File.exist?(File.join(out_root, name, "merged.rs")) }
|
|
277
|
+
|
|
278
|
+
root_mod_path = File.join(out_root, "mod.rs")
|
|
279
|
+
File.open(root_mod_path, "w") do |f|
|
|
280
|
+
f.puts "// GENERATED by hecks project_rust — re-run it to refresh this list."
|
|
281
|
+
f.puts "//"
|
|
282
|
+
f.puts "// BUG#25 — every DOMAIN (an entry in `domains`, below: a directory"
|
|
283
|
+
f.puts "// carrying its own merged.rs and therefore its own Cargo feature) is"
|
|
284
|
+
f.puts "// declared behind that SAME feature, so a broken or absent domain's"
|
|
285
|
+
f.puts "// generated code is never even compiled into a build that selects a"
|
|
286
|
+
f.puts "// DIFFERENT domain — `cargo build --features waybill` used to pull in"
|
|
287
|
+
f.puts "// every OTHER domain's `pub mod` unconditionally, so one domain's own"
|
|
288
|
+
f.puts "// non-compiling generated code (a `has_many` field, before this fix)"
|
|
289
|
+
f.puts "// broke every feature's build, not just its own. A shared FRAMEWORK"
|
|
290
|
+
f.puts "// chapter (governance/identity — no merged.rs of its own, so absent"
|
|
291
|
+
f.puts "// from `domains`) stays unconditional: it has no single feature of its"
|
|
292
|
+
f.puts "// own to gate behind, and is compiled in by whichever domain(s) attach"
|
|
293
|
+
f.puts "// it via `uses_framework`."
|
|
294
|
+
all_dirs.each do |name|
|
|
295
|
+
f.puts "#[cfg(feature = #{name.inspect})]" if domains.include?(name)
|
|
296
|
+
f.puts "pub mod #{name};"
|
|
297
|
+
end
|
|
298
|
+
f.puts
|
|
299
|
+
f.puts "// `active` is whichever ONE domain's own merged Store/dispatch table"
|
|
300
|
+
f.puts "// is selected by Cargo feature (rust/Cargo.toml, kept in sync with this"
|
|
301
|
+
f.puts "// list by hecks project_rust) — kernel/cli.rs imports"
|
|
302
|
+
f.puts "// `crate::generated::active::{dispatch_by_name, Store, ...}` unchanged"
|
|
303
|
+
f.puts "// no matter which domain that resolves to."
|
|
304
|
+
f.puts "//"
|
|
305
|
+
f.puts "// DOMAIN FEATURES ARE MUTUALLY EXCLUSIVE (R5) — Cargo has no native"
|
|
306
|
+
f.puts "// concept of that, and `default = [#{target_mod_name.inspect}]` in"
|
|
307
|
+
f.puts "// Cargo.toml stays enabled unless a build passes"
|
|
308
|
+
f.puts "// `--no-default-features`, so a plain `cargo build --features banking`"
|
|
309
|
+
f.puts "// used to enable BOTH the default domain's feature and banking's,"
|
|
310
|
+
f.puts "// producing two `pub use ... as active;` imports and a hard E0252."
|
|
311
|
+
f.puts "// Fixed two ways below, entirely mechanically from `domains`/"
|
|
312
|
+
f.puts "// `target_mod_name` (this run's new default) — never hand-maintained:"
|
|
313
|
+
f.puts "//"
|
|
314
|
+
f.puts "// 1. THE DEFAULT DOMAIN'S OWN re-export backs off whenever any OTHER"
|
|
315
|
+
f.puts "// domain feature is also enabled, so it never contends for `active`"
|
|
316
|
+
f.puts "// by accident — `cargo build --features banking` (still implicitly"
|
|
317
|
+
f.puts "// carrying the default feature) now resolves to banking alone,"
|
|
318
|
+
f.puts "// same as if `--no-default-features` had been passed explicitly."
|
|
319
|
+
f.puts "// 2. Two NON-default domain features enabled TOGETHER (a genuine,"
|
|
320
|
+
f.puts "// not-accidental conflict — nothing makes that combination"
|
|
321
|
+
f.puts "// meaningful) still fail the build, but with an explicit"
|
|
322
|
+
f.puts "// `compile_error!` naming both features instead of a cryptic"
|
|
323
|
+
f.puts "// \"defined multiple times\"."
|
|
324
|
+
domains.each do |name|
|
|
325
|
+
other_domains = domains - [name]
|
|
326
|
+
if name == target_mod_name && !other_domains.empty?
|
|
327
|
+
guard = other_domains.map { |o| "feature = #{o.inspect}" }.join(", ")
|
|
328
|
+
f.puts "#[cfg(all(feature = #{name.inspect}, not(any(#{guard}))))]"
|
|
329
|
+
else
|
|
330
|
+
f.puts "#[cfg(feature = #{name.inspect})]"
|
|
331
|
+
end
|
|
332
|
+
f.puts "pub use #{name}::merged as active;"
|
|
333
|
+
end
|
|
334
|
+
non_default_domains = domains - [target_mod_name]
|
|
335
|
+
if non_default_domains.size > 1
|
|
336
|
+
f.puts
|
|
337
|
+
f.puts "// Explicit conflict guard — see point 2 above. Only fires when TWO"
|
|
338
|
+
f.puts "// non-default domain features are both turned on; the default"
|
|
339
|
+
f.puts "// domain's own feature never reaches here (point 1 already excludes"
|
|
340
|
+
f.puts "// it whenever any other domain feature is present)."
|
|
341
|
+
non_default_domains.combination(2).each do |a, b|
|
|
342
|
+
f.puts "#[cfg(all(feature = #{a.inspect}, feature = #{b.inspect}))]"
|
|
343
|
+
f.puts "compile_error!(\"domain features are mutually exclusive — enable only one of: #{domains.join(', ')} (both #{a} and #{b} are enabled)\");"
|
|
344
|
+
end
|
|
345
|
+
end
|
|
346
|
+
end
|
|
347
|
+
puts "wrote #{root_mod_path}"
|
|
348
|
+
|
|
349
|
+
# The crate's own Cargo.toml, two levels above src/generated — the one `HECKS_RUST_DIR` chose.
|
|
350
|
+
cargo_toml_path = File.expand_path("../../Cargo.toml", out_root)
|
|
351
|
+
cargo_toml = File.read(cargo_toml_path)
|
|
352
|
+
unless cargo_toml.include?("[features]")
|
|
353
|
+
cargo_toml = cargo_toml.sub(/\A/, <<~TOML)
|
|
354
|
+
# ONE FEATURE PER GENERATED DOMAIN — selects which domain's own
|
|
355
|
+
# generated::<domain>::merged module `generated::active` re-exports
|
|
356
|
+
# (rust/src/generated/mod.rs). Kept in sync by hecks project_rust: a
|
|
357
|
+
# feature is added here whenever a new domain is generated, never
|
|
358
|
+
# removed (the domain's own generated/<name>/ directory is the
|
|
359
|
+
# source of truth for whether it still exists). `default` tracks
|
|
360
|
+
# whichever domain was generated MOST RECENTLY, so a bare
|
|
361
|
+
# `cargo build`/`cargo test` keeps behaving exactly as it always
|
|
362
|
+
# has; any other still-generated domain stays reachable via
|
|
363
|
+
# `--no-default-features --features <name>`.
|
|
364
|
+
[features]
|
|
365
|
+
default = []
|
|
366
|
+
|
|
367
|
+
TOML
|
|
368
|
+
end
|
|
369
|
+
# Scoped to the [features] table only — checking against the whole
|
|
370
|
+
# file false-positives against [package]/[lib] keys sharing a word
|
|
371
|
+
# with a domain name (version, edition, name, path, ...).
|
|
372
|
+
features_table = cargo_toml[/^\[features\](?:\n(?!\[).*)*$/] || ""
|
|
373
|
+
domains.each do |name|
|
|
374
|
+
next if features_table =~ /^#{Regexp.escape(name)}\s*=/
|
|
375
|
+
|
|
376
|
+
cargo_toml = cargo_toml.sub(/^default\s*=.*$/) { "#{Regexp.last_match(0)}\n#{name} = []" }
|
|
377
|
+
features_table = cargo_toml[/^\[features\](?:\n(?!\[).*)*$/] || ""
|
|
378
|
+
end
|
|
379
|
+
cargo_toml = cargo_toml.sub(/^default\s*=.*$/, "default = [#{target_mod_name.inspect}]")
|
|
380
|
+
File.write(cargo_toml_path, cargo_toml)
|
|
381
|
+
puts "wrote #{cargo_toml_path} (default feature: #{target_mod_name})"
|
|
382
|
+
end
|
|
383
|
+
end
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
//! Exemplar shapes for rust/project/commands.rb (see mod.rs).
|
|
2
|
+
//!
|
|
3
|
+
//! `dispatch_fn` proves the outer `pub fn .. -> DispatchResult { .. dispatch(..) .. }` wrapper.
|
|
4
|
+
#![allow(dead_code, unused_variables)]
|
|
5
|
+
|
|
6
|
+
// Minimal element satisfying `dispatch_entity`'s bounds (`Fielded + Clone`).
|
|
7
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
8
|
+
pub struct TmplElement {
|
|
9
|
+
tmpl_field: i64,
|
|
10
|
+
}
|
|
11
|
+
impl crate::kernel::Fielded for TmplElement {
|
|
12
|
+
fn field(&self, name: &str) -> Option<crate::kernel::Field<'_>> {
|
|
13
|
+
None
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
impl TmplElement {
|
|
17
|
+
fn identity(&self) -> String {
|
|
18
|
+
String::new()
|
|
19
|
+
}
|
|
20
|
+
fn extract_id(v: &crate::kernel::Json) -> Result<String, crate::kernel::Refusal> {
|
|
21
|
+
let _ = v;
|
|
22
|
+
Ok(String::new())
|
|
23
|
+
}
|
|
24
|
+
// Generated entities carry both `extract_id` and `extract_id_lenient`.
|
|
25
|
+
fn extract_id_lenient(v: &crate::kernel::Json) -> Result<String, crate::kernel::Refusal> {
|
|
26
|
+
let _ = v;
|
|
27
|
+
Ok(String::new())
|
|
28
|
+
}
|
|
29
|
+
fn extract_wants(v: &crate::kernel::Json) -> String {
|
|
30
|
+
let _ = v;
|
|
31
|
+
String::new()
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
36
|
+
pub struct TmplTargetArgs {
|
|
37
|
+
tmpl_field: i64,
|
|
38
|
+
}
|
|
39
|
+
impl crate::kernel::Fielded for TmplTargetArgs {
|
|
40
|
+
fn field(&self, name: &str) -> Option<crate::kernel::Field<'_>> {
|
|
41
|
+
None
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
impl TmplTargetArgs {
|
|
45
|
+
fn to_json(&self) -> crate::kernel::Json {
|
|
46
|
+
crate::kernel::Json::Null
|
|
47
|
+
}
|
|
48
|
+
fn from_json(v: &crate::kernel::Json) -> Result<Self, crate::kernel::Refusal> {
|
|
49
|
+
let _ = v;
|
|
50
|
+
Ok(TmplTargetArgs { tmpl_field: 0 })
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Stand-in for the aggregate record a generated `dispatch_*` fn targets.
|
|
55
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
56
|
+
pub struct TmplRecord {
|
|
57
|
+
tmpl_field: i64,
|
|
58
|
+
tmpl_list_field: Vec<TmplElement>,
|
|
59
|
+
}
|
|
60
|
+
impl crate::kernel::Fielded for TmplRecord {
|
|
61
|
+
fn field(&self, name: &str) -> Option<crate::kernel::Field<'_>> {
|
|
62
|
+
None
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
impl crate::kernel::ToJson for TmplRecord {
|
|
66
|
+
fn to_json(&self) -> crate::kernel::Json {
|
|
67
|
+
crate::kernel::Json::Null
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
impl crate::kernel::SetProjectedField for TmplRecord {
|
|
71
|
+
fn set_projected_field(&mut self, name: &'static str, value: Option<String>) {
|
|
72
|
+
let _ = (name, value);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
77
|
+
pub struct TmplArgs {
|
|
78
|
+
tmpl_field: i64,
|
|
79
|
+
}
|
|
80
|
+
impl crate::kernel::Fielded for TmplArgs {
|
|
81
|
+
fn field(&self, name: &str) -> Option<crate::kernel::Field<'_>> {
|
|
82
|
+
None
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
impl TmplArgs {
|
|
86
|
+
fn to_json(&self) -> crate::kernel::Json {
|
|
87
|
+
crate::kernel::Json::Null
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
fn tmpl_hydrate_placeholder() -> crate::kernel::Hydrate<'static, TmplRecord> {
|
|
92
|
+
crate::kernel::Hydrate::Act { id: String::new() }
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
fn tmpl_mutation_lines_placeholder(record: &mut TmplRecord) {}
|
|
96
|
+
|
|
97
|
+
fn tmpl_seed_projections_placeholder() -> Vec<(&'static str, Option<String>)> {
|
|
98
|
+
Vec::new()
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// TMPL:dispatch_fn BEGIN
|
|
102
|
+
pub fn dispatch_tmpl(
|
|
103
|
+
repo: &mut impl crate::kernel::Repository<TmplRecord>, id: &str, args: TmplArgs, mutations: &mut Vec<crate::kernel::MutationRecord>, tenant_boundary_check: Result<(), crate::kernel::Refusal>,
|
|
104
|
+
) -> crate::kernel::DispatchResult<TmplRecord> {
|
|
105
|
+
tmpl_invariant_check_placeholder()?;
|
|
106
|
+
let tmpl_eval_fielded = tmpl_with_references_placeholder();
|
|
107
|
+
let tmpl_seed_projections = tmpl_seed_projections_placeholder();
|
|
108
|
+
tmpl_prelude_placeholder();
|
|
109
|
+
crate::kernel::dispatch(
|
|
110
|
+
repo,
|
|
111
|
+
tmpl_hydrate_placeholder(),
|
|
112
|
+
"TmplCmdName",
|
|
113
|
+
"TmplQualifiedName",
|
|
114
|
+
"TmplAggregateName",
|
|
115
|
+
"TmplIdentityReading",
|
|
116
|
+
&tmpl_eval_fielded,
|
|
117
|
+
&[
|
|
118
|
+
tmpl_given_spec_placeholder(),
|
|
119
|
+
],
|
|
120
|
+
tmpl_transition_placeholder(),
|
|
121
|
+
|record| {
|
|
122
|
+
tmpl_mutation_lines_placeholder(record);
|
|
123
|
+
Ok(())
|
|
124
|
+
},
|
|
125
|
+
&[
|
|
126
|
+
tmpl_ensures_spec_placeholder(),
|
|
127
|
+
],
|
|
128
|
+
&tmpl_invariants_placeholder(),
|
|
129
|
+
&[tmpl_emit_placeholder()],
|
|
130
|
+
args.to_json(),
|
|
131
|
+
mutations,
|
|
132
|
+
tmpl_seed_projections,
|
|
133
|
+
tenant_boundary_check,
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
// TMPL:dispatch_fn END
|
|
137
|
+
|
|
138
|
+
fn tmpl_invariant_check_placeholder() -> Result<(), crate::kernel::Refusal> {
|
|
139
|
+
Ok(())
|
|
140
|
+
}
|
|
141
|
+
// Empty for ordinary commands; a delegating command substitutes `delegate_prelude`.
|
|
142
|
+
fn tmpl_prelude_placeholder() {}
|
|
143
|
+
// Plain `TmplArgs` stands in for `kernel::WithReferences` so this exemplar compiles alone.
|
|
144
|
+
fn tmpl_with_references_placeholder() -> TmplArgs {
|
|
145
|
+
TmplArgs { tmpl_field: 0 }
|
|
146
|
+
}
|
|
147
|
+
fn tmpl_given_spec_placeholder() -> crate::kernel::GivenSpec {
|
|
148
|
+
crate::kernel::GivenSpec { description: "", expr: crate::kernel::Expr::Bool(true), corrects_event: None }
|
|
149
|
+
}
|
|
150
|
+
fn tmpl_transition_placeholder() -> Option<crate::kernel::TransitionCheck> {
|
|
151
|
+
None
|
|
152
|
+
}
|
|
153
|
+
fn tmpl_ensures_spec_placeholder() -> crate::kernel::EnsuresSpec {
|
|
154
|
+
crate::kernel::EnsuresSpec { description: "", expr: crate::kernel::Expr::Bool(true) }
|
|
155
|
+
}
|
|
156
|
+
fn tmpl_invariants_placeholder() -> crate::kernel::InvariantSet {
|
|
157
|
+
crate::kernel::InvariantSet { aggregate: vec![], entities: vec![] }
|
|
158
|
+
}
|
|
159
|
+
fn tmpl_emit_placeholder() -> &'static str {
|
|
160
|
+
""
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// `delegates_to "Entity.Command"`: the door runs `apply_entity_command` inside its closure.
|
|
164
|
+
// `delegate_prelude` fills the prelude slot; `delegate_apply` fills the mutation slot.
|
|
165
|
+
// The inner `|record|` deliberately shadows the door's: entity `sets` only reach the element.
|
|
166
|
+
fn tmpl_aliases_placeholder() -> (&'static str, &'static str) {
|
|
167
|
+
("", "")
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
fn tmpl_delegate_prelude_host(
|
|
171
|
+
args: TmplArgs,
|
|
172
|
+
command_deref: Vec<(&'static str, crate::kernel::DerefNode)>,
|
|
173
|
+
owner_deref: Vec<(&'static str, crate::kernel::DerefNode)>,
|
|
174
|
+
) -> Result<(), crate::kernel::Refusal> {
|
|
175
|
+
// TMPL:delegate_prelude BEGIN
|
|
176
|
+
let delegate_facts = args.to_json().with_aliases(&[tmpl_aliases_placeholder()]);
|
|
177
|
+
let target_args = TmplTargetArgs::from_json(&delegate_facts)?;
|
|
178
|
+
let target_with_references = crate::kernel::WithReferences { command_deref: &command_deref, args: &target_args, owner_deref: &owner_deref };
|
|
179
|
+
// TMPL:delegate_prelude END
|
|
180
|
+
let _ = target_with_references;
|
|
181
|
+
Ok(())
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// `element_id` extraction must run after `dispatch`'s hydrate, so it is spliced into the
|
|
185
|
+
// mutation closure rather than the prelude. It uses `extract_id_lenient` because a blank mapped
|
|
186
|
+
// identity is a non-match, not a refusal.
|
|
187
|
+
fn tmpl_delegate_element_host(delegate_facts: crate::kernel::Json) -> Result<(), crate::kernel::Refusal> {
|
|
188
|
+
// TMPL:delegate_element BEGIN
|
|
189
|
+
let element_id = TmplElement::extract_id_lenient(&delegate_facts)?;
|
|
190
|
+
let element_wants = TmplElement::extract_wants(&delegate_facts);
|
|
191
|
+
// TMPL:delegate_element END
|
|
192
|
+
let _ = (element_id, element_wants);
|
|
193
|
+
Ok(())
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
fn tmpl_delegate_apply_host(
|
|
197
|
+
record: &mut TmplRecord,
|
|
198
|
+
id: &str,
|
|
199
|
+
element_id: String,
|
|
200
|
+
element_wants: String,
|
|
201
|
+
target_with_references: TmplArgs,
|
|
202
|
+
) -> Result<(), crate::kernel::Refusal> {
|
|
203
|
+
// TMPL:delegate_apply BEGIN
|
|
204
|
+
crate::kernel::apply_entity_command(
|
|
205
|
+
record,
|
|
206
|
+
id,
|
|
207
|
+
|r: &TmplRecord| &r.tmpl_list_field,
|
|
208
|
+
|r: &mut TmplRecord| &mut r.tmpl_list_field,
|
|
209
|
+
|el: &TmplElement| el.identity() == element_id,
|
|
210
|
+
"TmplQualifiedCommandName",
|
|
211
|
+
"TmplQualifiedName",
|
|
212
|
+
"TmplAggregateName",
|
|
213
|
+
"TmplEntityName",
|
|
214
|
+
"TmplEntityIdentityReading",
|
|
215
|
+
&element_wants,
|
|
216
|
+
&target_with_references,
|
|
217
|
+
&[
|
|
218
|
+
tmpl_given_spec_placeholder(),
|
|
219
|
+
],
|
|
220
|
+
tmpl_transition_placeholder(),
|
|
221
|
+
|record| {
|
|
222
|
+
tmpl_entity_mutation_lines_placeholder(record);
|
|
223
|
+
Ok(())
|
|
224
|
+
},
|
|
225
|
+
&[
|
|
226
|
+
tmpl_ensures_spec_placeholder(),
|
|
227
|
+
],
|
|
228
|
+
true,
|
|
229
|
+
)?;
|
|
230
|
+
// TMPL:delegate_apply END
|
|
231
|
+
Ok(())
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// `entity_dispatch_fn`: `dispatch_fn`'s sibling wrapping `kernel::dispatch_entity`, which
|
|
235
|
+
// addresses one element by `identity()` and never creates.
|
|
236
|
+
fn tmpl_entity_mutation_lines_placeholder(record: &mut TmplElement) {}
|
|
237
|
+
|
|
238
|
+
// TMPL:entity_dispatch_fn BEGIN
|
|
239
|
+
pub fn dispatch_entity_tmpl(
|
|
240
|
+
repo: &mut impl crate::kernel::Repository<TmplRecord>, parent_id: &str, element_id: &str, element_wants: &str, args: TmplArgs,
|
|
241
|
+
mutations: &mut Vec<crate::kernel::MutationRecord>, tmpl_deref_params_placeholder: (),
|
|
242
|
+
) -> crate::kernel::DispatchResult<TmplRecord> {
|
|
243
|
+
tmpl_invariant_check_placeholder()?;
|
|
244
|
+
let tmpl_eval_fielded = tmpl_with_references_placeholder();
|
|
245
|
+
let tmpl_seed_projections = tmpl_seed_projections_placeholder();
|
|
246
|
+
|
|
247
|
+
crate::kernel::dispatch_entity(
|
|
248
|
+
repo,
|
|
249
|
+
parent_id,
|
|
250
|
+
|r: &TmplRecord| &r.tmpl_list_field,
|
|
251
|
+
|r: &mut TmplRecord| &mut r.tmpl_list_field,
|
|
252
|
+
|el: &TmplElement| el.identity() == element_id,
|
|
253
|
+
"TmplQualifiedCommandName",
|
|
254
|
+
"TmplQualifiedName",
|
|
255
|
+
"TmplAggregateName",
|
|
256
|
+
"TmplParentIdentityReading",
|
|
257
|
+
"TmplEntityName",
|
|
258
|
+
"TmplEntityIdentityReading",
|
|
259
|
+
element_wants,
|
|
260
|
+
&tmpl_eval_fielded,
|
|
261
|
+
&[
|
|
262
|
+
tmpl_given_spec_placeholder(),
|
|
263
|
+
],
|
|
264
|
+
tmpl_transition_placeholder(),
|
|
265
|
+
|record| {
|
|
266
|
+
tmpl_entity_mutation_lines_placeholder(record);
|
|
267
|
+
Ok(())
|
|
268
|
+
},
|
|
269
|
+
&[
|
|
270
|
+
tmpl_ensures_spec_placeholder(),
|
|
271
|
+
],
|
|
272
|
+
&tmpl_invariants_placeholder(),
|
|
273
|
+
&[tmpl_emit_placeholder()],
|
|
274
|
+
args.to_json(),
|
|
275
|
+
mutations,
|
|
276
|
+
tmpl_seed_projections,
|
|
277
|
+
)
|
|
278
|
+
}
|
|
279
|
+
// TMPL:entity_dispatch_fn END
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//! Exemplar shapes for rust/project/constraints.rb (see mod.rs).
|
|
2
|
+
//!
|
|
3
|
+
//! Both shapes are single-line refusal checks spliced into a `Result`-returning body.
|
|
4
|
+
#![allow(dead_code, unused_variables)]
|
|
5
|
+
|
|
6
|
+
fn tmpl_admits_check_host(tmpl_scalar: String) -> Result<(), crate::kernel::Refusal> {
|
|
7
|
+
// TMPL:admits_check BEGIN
|
|
8
|
+
if !["tmpl_member_a", "tmpl_member_b"].contains(&tmpl_scalar.as_str()) { return Err(crate::kernel::Refusal::InvariantViolation(crate::kernel::refusal_wording::InvariantViolationAdmitsDeclaredSetArgs { name: "tmpl_admits_name", admits: "tmpl_admits_target", admitted: &["tmpl_member_a", "tmpl_member_b"], offered: format!("{:?}", tmpl_scalar).as_str() }.render_args())); }
|
|
9
|
+
// TMPL:admits_check END
|
|
10
|
+
Ok(())
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
fn tmpl_pattern_check_host(tmpl_scalar: String) -> Result<(), crate::kernel::Refusal> {
|
|
14
|
+
// TMPL:pattern_check BEGIN
|
|
15
|
+
if !crate::kernel::pattern::matches("tmpl_pattern_text", &tmpl_scalar) { return Err(crate::kernel::Refusal::TypeMismatch(crate::kernel::refusal_wording::TypeMismatchPatternMismatchArgs { r#type: "tmpl_pattern_owner", field: "tmpl_pattern_field", pattern: "tmpl_pattern_text", offered: format!("{:?}", tmpl_scalar).as_str() }.render_args())); }
|
|
16
|
+
// TMPL:pattern_check END
|
|
17
|
+
Ok(())
|
|
18
|
+
}
|