hecks 5.0.0 → 7.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/examples/pizzas/bluebook/pizzas.bluebook +1 -0
- data/exe/hecks +31 -12
- data/lib/hecks/adapters/driven/claude_code.rb +3 -3
- data/lib/hecks/adapters/driven/d1.rb +2 -1
- data/lib/hecks/adapters/driven/folder.rb +44 -28
- data/lib/hecks/adapters/driven/folder_overlay.rb +66 -0
- data/lib/hecks/adapters/driven/google_authentication.adapter +3 -0
- data/lib/hecks/adapters/driven/google_authentication.rb +99 -0
- data/lib/hecks/adapters/driven/governance_authorization.rb +32 -36
- data/lib/hecks/adapters/driven/heki/journal.rb +45 -0
- data/lib/hecks/adapters/driven/heki.rb +1 -1
- data/lib/hecks/adapters/driven/identity_registry.rb +1 -1
- data/lib/hecks/adapters/driven/in_memory_ordering.rb +3 -2
- data/lib/hecks/adapters/driven/in_process_key_vault.rb +1 -1
- data/lib/hecks/adapters/driven/key_keeper.rb +42 -0
- data/lib/hecks/adapters/driven/lambda/client.rb +8 -2
- data/lib/hecks/adapters/driven/lambda/remote_dispatcher.rb +185 -0
- data/lib/hecks/adapters/driven/lambda.rb +14 -2
- data/lib/hecks/adapters/driven/memory/dispatch_claims.rb +25 -0
- data/lib/hecks/adapters/driven/memory/outbox_rows.rb +2 -2
- data/lib/hecks/adapters/driven/memory.rb +15 -4
- data/lib/hecks/adapters/driven/postgres/codec.rb +1 -1
- data/lib/hecks/adapters/driven/postgres/journal.rb +46 -0
- data/lib/hecks/adapters/driven/postgres/name_guard.rb +25 -0
- data/lib/hecks/adapters/driven/postgres/outbox.rb +33 -7
- data/lib/hecks/adapters/driven/postgres/projection.rb +43 -0
- data/lib/hecks/adapters/driven/postgres/repository.rb +2 -2
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +2 -1
- data/lib/hecks/adapters/driven/postgres/set_dialect.rb +44 -0
- data/lib/hecks/adapters/driven/postgres/shared_connection.rb +1 -1
- data/lib/hecks/adapters/driven/postgres.adapter +8 -0
- data/lib/hecks/adapters/driven/postgres.rb +11 -3
- data/lib/hecks/adapters/driven/postgres_dump/connection.rb +57 -0
- data/lib/hecks/adapters/driven/postgres_dump.rb +117 -0
- data/lib/hecks/adapters/driven/postgres_era/boot.rb +58 -0
- data/lib/hecks/{ports/persistence/plugins/era → adapters/driven}/postgres_era/class_methods.rb +28 -8
- data/lib/hecks/{ports/persistence/plugins/era → adapters/driven}/postgres_era/dialect.rb +11 -6
- data/lib/hecks/adapters/driven/postgres_era/field_cache_provisioner.rb +39 -0
- data/lib/hecks/{ports/persistence/plugins/era → adapters/driven}/postgres_era/journal.rb +52 -13
- data/lib/hecks/{ports/persistence/plugins/era → adapters/driven}/postgres_era/lineage/chain_sql.rb +37 -53
- data/lib/hecks/adapters/driven/postgres_era/lineage/direct_sql.rb +73 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/direct_verified.json +10 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/direct_verified.rb +65 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/domain_rename.rb +143 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/domain_rename_state.rb +108 -0
- data/lib/hecks/{ports/persistence/plugins/era → adapters/driven}/postgres_era/lineage/era_integrity.rb +13 -8
- data/lib/hecks/adapters/driven/postgres_era/lineage/era_store.rb +125 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/layered_sql.rb +64 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/ledger_reset.rb +150 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/mint_provisioning.rb +85 -0
- data/lib/hecks/{ports/persistence/plugins/era → adapters/driven}/postgres_era/lineage/mint_transaction.rb +13 -9
- data/lib/hecks/{ports/persistence/plugins/era → adapters/driven}/postgres_era/lineage/provisioning.rb +11 -5
- data/lib/hecks/adapters/driven/postgres_era/lineage/split_sql.rb +76 -0
- data/lib/hecks/{ports/persistence/plugins/era → adapters/driven}/postgres_era/lineage/sql_templates.rb +15 -2
- data/lib/hecks/{ports/persistence/plugins/era → adapters/driven}/postgres_era/lineage/tail_merge.rb +1 -1
- data/lib/hecks/{ports/persistence/plugins/era → adapters/driven}/postgres_era/lineage.rb +11 -3
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/context.rb +68 -0
- data/lib/hecks/{ports/persistence/plugins/era → adapters/driven}/postgres_era/lineage_manager/coverage_check.rb +16 -12
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/disposable_ledger.rb +119 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/era_resolution.rb +219 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/era_resolver.rb +114 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/held_era.rb +68 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/ledger_change.rb +63 -0
- data/lib/hecks/{ports/persistence/plugins/era → adapters/driven}/postgres_era/lineage_manager/merge_coordinator.rb +3 -3
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/mint_decision.rb +163 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/mint_request.rb +24 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/minter.rb +143 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/refusals.rb +76 -0
- data/lib/hecks/{ports/persistence/plugins/era → adapters/driven}/postgres_era/lineage_manager.rb +46 -12
- data/lib/hecks/{ports/persistence/plugins/era → adapters/driven}/postgres_era/query_phases.rb +8 -2
- data/lib/hecks/adapters/driven/postgres_era/shared_tables.rb +32 -0
- data/lib/hecks/adapters/driven/postgres_era.adapter +19 -1
- data/lib/hecks/{ports/persistence/plugins/era → adapters/driven}/postgres_era.rb +39 -23
- data/lib/hecks/adapters/driven/prism.rb +4 -4
- data/lib/hecks/adapters/driven/projection/read_model_walk.rb +126 -0
- data/lib/hecks/adapters/driven/projection/row_decoding.rb +57 -0
- data/lib/hecks/adapters/driven/set_transform/assignments.rb +101 -0
- data/lib/hecks/adapters/driven/set_transform/expressions.rb +138 -0
- data/lib/hecks/adapters/driven/set_transform.rb +81 -0
- data/lib/hecks/adapters/driven/sql_keyset.rb +61 -0
- data/lib/hecks/adapters/driven/sql_query_builder.rb +29 -9
- data/lib/hecks/adapters/driven/sqlite/codec.rb +1 -1
- data/lib/hecks/adapters/driven/sqlite/ddl.rb +7 -0
- data/lib/hecks/adapters/driven/sqlite/dialect.rb +2 -1
- data/lib/hecks/adapters/driven/sqlite/dispatch_claims.rb +28 -0
- data/lib/hecks/adapters/driven/sqlite/journal.rb +46 -0
- data/lib/hecks/adapters/driven/sqlite/name_guard.rb +25 -0
- data/lib/hecks/adapters/driven/sqlite/outbox.rb +5 -4
- data/lib/hecks/adapters/driven/sqlite/projection.rb +9 -135
- data/lib/hecks/adapters/driven/sqlite/repository.rb +2 -2
- data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +36 -4
- data/lib/hecks/adapters/driven/sqlite/set_dialect.rb +39 -0
- data/lib/hecks/adapters/driven/sqlite.adapter +2 -0
- data/lib/hecks/adapters/driven/sqlite.rb +20 -3
- data/lib/hecks/adapters/driven/tenant_provisioner.rb +1 -1
- data/lib/hecks/adapters/driven/worktree_overlay.rb +117 -0
- data/lib/hecks/adapters/driven.rb +8 -3
- data/lib/hecks/adapters/driving/cli/shorthand.rb +5 -1
- data/lib/hecks/adapters/driving/cli.rb +2 -2
- data/lib/hecks/adapters/driving/cli_runner/answers.rb +96 -34
- data/lib/hecks/adapters/driving/cli_runner/bang_rule.rb +35 -0
- data/lib/hecks/adapters/driving/cli_runner/completion_words.rb +36 -0
- data/lib/hecks/adapters/driving/cli_runner/json_words.rb +55 -0
- data/lib/hecks/adapters/driving/cli_runner/name_index.rb +63 -0
- data/lib/hecks/adapters/driving/cli_runner/read_context.rb +32 -0
- data/lib/hecks/adapters/driving/cli_runner/renamed_names.rb +49 -0
- data/lib/hecks/adapters/driving/cli_runner/resolution.rb +66 -39
- data/lib/hecks/adapters/driving/cli_runner/resume_words.rb +63 -0
- data/lib/hecks/adapters/driving/cli_runner/run_reference.rb +66 -0
- data/lib/hecks/adapters/driving/cli_runner/run_replay.rb +118 -0
- data/lib/hecks/adapters/driving/cli_runner/search_words.rb +35 -0
- data/lib/hecks/adapters/driving/cli_runner/settling.rb +14 -9
- data/lib/hecks/adapters/driving/cli_runner/streaming.rb +12 -11
- data/lib/hecks/adapters/driving/cli_runner/suggestions.rb +16 -8
- data/lib/hecks/adapters/driving/cli_runner/tour_words.rb +77 -0
- data/lib/hecks/adapters/driving/cli_runner/verb_names.rb +81 -0
- data/lib/hecks/adapters/driving/cli_runner/verbosity.rb +75 -0
- data/lib/hecks/adapters/driving/cli_runner.rb +110 -9
- data/lib/hecks/adapters/driving/context_line.rb +85 -0
- data/lib/hecks/adapters/driving/exit_status.rb +31 -0
- data/lib/hecks/adapters/driving/github_webhook.rb +2 -1
- data/lib/hecks/adapters/driving/handle/verb_methods.rb +46 -0
- data/lib/hecks/adapters/driving/handle.rb +9 -17
- data/lib/hecks/adapters/driving/json.rb +11 -8
- data/lib/hecks/adapters/driving/launcher_options.rb +41 -34
- data/lib/hecks/adapters/driving/mcp/progress_sink.rb +45 -0
- data/lib/hecks/adapters/driving/mcp/tool_calls.rb +7 -5
- data/lib/hecks/adapters/driving/mcp.rb +25 -5
- data/lib/hecks/adapters/driving/mcp_scope/argument_policy.rb +40 -7
- data/lib/hecks/adapters/driving/mcp_scope/env_problems.rb +3 -1
- data/lib/hecks/adapters/driving/mcp_scope.rb +11 -9
- data/lib/hecks/adapters/driving/newcomer.rb +6 -5
- data/lib/hecks/adapters/driving/ruby/aggregate_module/hooks.rb +154 -0
- data/lib/hecks/adapters/driving/ruby/aggregate_module.rb +73 -101
- data/lib/hecks/adapters/driving/ruby/bulk_verbs.rb +127 -0
- data/lib/hecks/adapters/driving/ruby/{chapter.rb → declaration.rb} +27 -27
- data/lib/hecks/adapters/driving/ruby/query_rows.rb +27 -0
- data/lib/hecks/adapters/driving/ruby.rb +25 -24
- data/lib/hecks/adapters/driving/usage_cache.rb +14 -3
- data/lib/hecks/adapters/driving/usage_log.rb +146 -0
- data/lib/hecks/adapters/driving/write_guard.rb +55 -0
- data/lib/hecks/adapters/driving.rb +0 -1
- data/lib/hecks/assembly.rb +101 -0
- data/lib/hecks/behaviors/dsl.rb +18 -4
- data/lib/hecks/behaviors/expectations/boot.rb +7 -7
- data/lib/hecks/behaviors/expectations/checks.rb +1 -1
- data/lib/hecks/behaviors/expectations/dispatching.rb +10 -9
- data/lib/hecks/behaviors/expectations/qualify.rb +9 -9
- data/lib/hecks/behaviors/expectations.rb +24 -10
- data/lib/hecks/behaviors/ir.rb +4 -2
- data/lib/hecks/behaviors/rspec.rb +1 -1
- data/lib/hecks/behaviors/runner.rb +31 -4
- data/lib/hecks/bench/environment.rb +6 -2
- data/lib/hecks/bench/postgres_probe.rb +3 -1
- data/lib/hecks/bench/report.rb +4 -1
- data/lib/hecks/bench/suite.rb +9 -3
- data/lib/hecks/bluebook/acknowledgements.rb +81 -0
- data/lib/hecks/bluebook/aggregate.rb +29 -17
- data/lib/hecks/bluebook/ask_resolution.rb +17 -17
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +8 -5
- data/lib/hecks/bluebook/assembly/contracts/sagas.rb +2 -0
- data/lib/hecks/bluebook/assembly/contracts/structure.rb +24 -15
- data/lib/hecks/bluebook/assembly/marks.rb +10 -1
- data/lib/hecks/bluebook/assembly/scalars.rb +8 -2
- data/lib/hecks/bluebook/assembly/specializer.rb +2 -2
- data/lib/hecks/bluebook/assembly.rb +10 -10
- data/lib/hecks/bluebook/behaviour/aggregate.rb +29 -4
- data/lib/hecks/bluebook/behaviour/attribute.rb +12 -0
- data/lib/hecks/bluebook/behaviour/command.rb +1 -1
- data/lib/hecks/bluebook/behaviour/{chapter.rb → declaration.rb} +17 -17
- data/lib/hecks/bluebook/behaviour/domain_port.rb +1 -1
- data/lib/hecks/bluebook/behaviour/entity.rb +1 -0
- data/lib/hecks/bluebook/behaviour/hecksagon.rb +8 -1
- data/lib/hecks/bluebook/behaviour/process_manager.rb +4 -1
- data/lib/hecks/bluebook/behaviour/query.rb +5 -0
- data/lib/hecks/bluebook/behaviour/read_model.rb +4 -1
- data/lib/hecks/bluebook/behaviour/traits.rb +13 -0
- data/lib/hecks/bluebook/capabilities/attribute_values.rb +17 -16
- data/lib/hecks/bluebook/capabilities/package_declared.rb +65 -0
- data/lib/hecks/bluebook/capabilities.rb +32 -132
- data/lib/hecks/bluebook/command.rb +33 -7
- data/lib/hecks/bluebook/context_map.rb +104 -0
- data/lib/hecks/bluebook/{chapter.rb → declaration.rb} +45 -17
- data/lib/hecks/bluebook/domain_port.rb +7 -3
- data/lib/hecks/bluebook/dsl/adapter_builder.rb +28 -4
- data/lib/hecks/bluebook/dsl/aggregate_builder/draining.rb +2 -2
- data/lib/hecks/bluebook/dsl/aggregate_builder/one_of_reference.rb +54 -0
- data/lib/hecks/bluebook/dsl/aggregate_builder/query_field_sealing.rb +11 -2
- data/lib/hecks/bluebook/dsl/aggregate_builder/query_sealing.rb +15 -5
- data/lib/hecks/bluebook/dsl/aggregate_builder/relationships.rb +21 -5
- data/lib/hecks/bluebook/dsl/aggregate_builder/renaming.rb +25 -0
- data/lib/hecks/bluebook/dsl/aggregate_builder/rules.rb +22 -22
- data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +2 -2
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +30 -22
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +0 -1
- data/lib/hecks/bluebook/dsl/audience_word.rb +40 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/metadata.rb +56 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/modules.rb +80 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/pending_givens.rb +22 -22
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/computed_sources.rb +27 -21
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/correlation_keys.rb +54 -5
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/event_shapes.rb +5 -4
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/fan_out_rows.rb +3 -3
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/hop_tails.rb +13 -5
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/projected_fields.rb +4 -4
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/provisions.rb +38 -84
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/query_hops.rb +5 -5
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/references.rb +6 -6
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/with_projections.rb +6 -6
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +4 -3
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +75 -92
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +10 -0
- data/lib/hecks/bluebook/dsl/command_builder/folded_sets.rb +48 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +39 -16
- data/lib/hecks/bluebook/dsl/context_map_builder.rb +73 -0
- data/lib/hecks/bluebook/dsl/entity_builder/rules.rb +17 -17
- data/lib/hecks/bluebook/dsl/entity_builder/scope.rb +3 -3
- data/lib/hecks/bluebook/dsl/entity_builder/sealing.rb +2 -2
- data/lib/hecks/bluebook/dsl/entity_builder.rb +3 -5
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +6 -4
- data/lib/hecks/bluebook/dsl/hecksagon_builder/{chapter_scope.rb → bluebook_scope.rb} +14 -14
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +33 -27
- data/lib/hecks/bluebook/dsl/identity_declaration.rb +6 -2
- data/lib/hecks/bluebook/dsl/kinds.rb +53 -0
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +4 -1
- data/lib/hecks/bluebook/dsl/port_operation_builder.rb +9 -2
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +25 -15
- data/lib/hecks/bluebook/dsl/query_builder.rb +14 -8
- data/lib/hecks/bluebook/dsl/read_model_builder/sealing.rb +6 -11
- data/lib/hecks/bluebook/dsl/read_model_builder.rb +1 -2
- data/lib/hecks/bluebook/dsl/translation_builder.rb +16 -1
- data/lib/hecks/bluebook/dsl/word_gate.rb +3 -2
- data/lib/hecks/bluebook/dsl/world_builder.rb +2 -2
- data/lib/hecks/bluebook/dsl.rb +4 -2
- data/lib/hecks/bluebook/expression/ast_json/emitters.rb +4 -0
- data/lib/hecks/bluebook/expression/ast_json.rb +5 -3
- data/lib/hecks/bluebook/expression/ast_reader/blocks.rb +41 -0
- data/lib/hecks/bluebook/expression/ast_reader.rb +2 -10
- data/lib/hecks/bluebook/expression/canonical_form.rb +9 -4
- data/lib/hecks/bluebook/expression/evaluator/parser.rb +4 -1
- data/lib/hecks/bluebook/expression/evaluator.rb +13 -9
- data/lib/hecks/bluebook/expression/projection.json +6 -0
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +50 -2
- data/lib/hecks/bluebook/expression/resolver/lookups.rb +2 -1
- data/lib/hecks/bluebook/expression/resolver/operations.rb +1 -0
- data/lib/hecks/bluebook/expression/resolver/parsing.rb +21 -15
- data/lib/hecks/bluebook/expression/resolver/scanning.rb +4 -1
- data/lib/hecks/bluebook/expression.rb +1 -1
- data/lib/hecks/bluebook/hecksagon.rb +48 -23
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +4 -1
- data/lib/hecks/bluebook/meta_validator/judge/cells.rb +1 -1
- data/lib/hecks/bluebook/meta_validator/judge/identity.rb +11 -5
- data/lib/hecks/bluebook/meta_validator/modes.rb +27 -27
- data/lib/hecks/bluebook/meta_validator/plan/category.rb +10 -2
- data/lib/hecks/bluebook/meta_validator/plan/verbs.rb +9 -0
- data/lib/hecks/bluebook/meta_validator/plan.rb +7 -6
- data/lib/hecks/bluebook/meta_validator/readings/fields.rb +3 -3
- data/lib/hecks/bluebook/meta_validator/reconstruction/heads.rb +14 -4
- data/lib/hecks/bluebook/meta_validator/reconstruction/reading.rb +8 -1
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +24 -19
- data/lib/hecks/bluebook/meta_validator/shapes.rb +9 -1
- data/lib/hecks/bluebook/meta_validator/syntax_boot/disk_cache.rb +19 -16
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +21 -15
- data/lib/hecks/bluebook/meta_validator/verdict_cache/prebuilt.rb +4 -1
- data/lib/hecks/bluebook/meta_validator/verdict_cache.rb +11 -10
- data/lib/hecks/bluebook/meta_validator.rb +25 -22
- data/lib/hecks/bluebook/model_check/aggregate_checks.rb +95 -0
- data/lib/hecks/bluebook/model_check/ask_checks.rb +31 -5
- data/lib/hecks/bluebook/model_check/client_profile.rb +8 -42
- data/lib/hecks/bluebook/model_check/context_checks.rb +97 -0
- data/lib/hecks/bluebook/model_check/context_map_checks.rb +158 -0
- data/lib/hecks/bluebook/model_check/lifecycle_checks.rb +27 -5
- data/lib/hecks/bluebook/model_check/one_of_checks.rb +106 -0
- data/lib/hecks/bluebook/model_check/orphan_checks.rb +129 -0
- data/lib/hecks/bluebook/model_check/reaction_chains.rb +114 -0
- data/lib/hecks/bluebook/model_check/reaction_cycles.rb +53 -0
- data/lib/hecks/bluebook/model_check/reaction_depth_checks.rb +58 -0
- data/lib/hecks/bluebook/model_check/reaction_walk.rb +62 -0
- data/lib/hecks/bluebook/model_check/redundant_relationships.rb +38 -0
- data/lib/hecks/bluebook/model_check/reference_checks.rb +11 -1
- data/lib/hecks/bluebook/model_check/saga_checks.rb +8 -3
- data/lib/hecks/bluebook/model_check/verbs.rb +4 -4
- data/lib/hecks/bluebook/model_check.rb +33 -35
- data/lib/hecks/bluebook/named_pattern.rb +12 -1
- data/lib/hecks/bluebook/one_of_union.rb +35 -0
- data/lib/hecks/bluebook/pattern_subset.rb +12 -3
- data/lib/hecks/bluebook/process_manager.rb +20 -3
- data/lib/hecks/bluebook/project_loader.rb +3 -2
- data/lib/hecks/bluebook/project_register.rb +21 -5
- data/lib/hecks/bluebook/query.rb +4 -1
- data/lib/hecks/bluebook/read_model.rb +5 -5
- data/lib/hecks/bluebook/reference.rb +3 -3
- data/lib/hecks/bluebook/smoke_test.rb +15 -13
- data/lib/hecks/bluebook/synthesizer.rb +48 -13
- data/lib/hecks/bluebook/translation.rb +5 -3
- data/lib/hecks/bluebook/translation_expression/parser.rb +14 -5
- data/lib/hecks/bluebook/translation_plan.rb +9 -2
- data/lib/hecks/bluebook.rb +6 -3
- data/lib/hecks/bulk/bluebook/adapters/row_sweeper.adapter +7 -0
- data/lib/hecks/bulk/bluebook/bulk.behaviors +18 -0
- data/lib/hecks/bulk/bluebook/bulk.bluebook +126 -0
- data/lib/hecks/bulk/bluebook/bulk.hecksagon +11 -0
- data/lib/hecks/bulk/bluebook/bulk.ports.hecksagon +13 -0
- data/lib/hecks/bulk/plan.rb +60 -0
- data/lib/hecks/bulk/row_sweeper.rb +34 -0
- data/lib/hecks/bulk/set_arguments.rb +68 -0
- data/lib/hecks/bulk/set_eligibility.rb +50 -0
- data/lib/hecks/bulk/set_planner.rb +100 -0
- data/lib/hecks/bulk/set_sweep.rb +78 -0
- data/lib/hecks/bulk/sweep.rb +67 -0
- data/lib/hecks/ci_pipeline/adapters/ci_cache.adapter +7 -0
- data/lib/hecks/ci_pipeline/adapters/ci_cache.rb +39 -0
- data/lib/hecks/ci_pipeline/adapters/ci_runner.adapter +7 -0
- data/lib/hecks/ci_pipeline/adapters/ci_runner.rb +55 -0
- data/lib/hecks/ci_pipeline/ci_pipeline.behaviors +322 -0
- data/lib/hecks/ci_pipeline/ci_pipeline.bluebook +938 -0
- data/lib/hecks/ci_pipeline/ci_pipeline.hecksagon +12 -0
- data/lib/hecks/ci_pipeline/ci_pipeline.ports.hecksagon +16 -0
- data/lib/hecks/ci_speed/adapters/ci_reader.adapter +7 -0
- data/lib/hecks/ci_speed/adapters/ci_reader.rb +141 -0
- data/lib/hecks/ci_speed/adapters/local_runner/answer.rb +41 -0
- data/lib/hecks/ci_speed/adapters/local_runner/catalog.rb +89 -0
- data/lib/hecks/ci_speed/adapters/local_runner/checkouts.rb +89 -0
- data/lib/hecks/ci_speed/adapters/local_runner/launcher.rb +69 -0
- data/lib/hecks/ci_speed/adapters/local_runner/load_average.rb +38 -0
- data/lib/hecks/ci_speed/adapters/local_runner/refs.rb +39 -0
- data/lib/hecks/ci_speed/adapters/local_runner/refused.rb +11 -0
- data/lib/hecks/ci_speed/adapters/local_runner/verdict.rb +71 -0
- data/lib/hecks/ci_speed/adapters/local_runner.adapter +7 -0
- data/lib/hecks/ci_speed/adapters/local_runner.rb +168 -0
- data/lib/hecks/ci_speed/adapters/replayed_runner.rb +39 -0
- data/lib/hecks/ci_speed/ci_speed.behaviors +341 -0
- data/lib/hecks/ci_speed/ci_speed.bluebook +1073 -0
- data/lib/hecks/ci_speed/ci_speed.hecksagon +11 -0
- data/lib/hecks/ci_speed/ci_speed.ports.hecksagon +21 -0
- data/lib/hecks/ci_workflows/ci_workflows.behaviors +13 -0
- data/lib/hecks/ci_workflows/ci_workflows.bluebook +173 -0
- data/lib/hecks/ci_workflows/ci_workflows.hecksagon +15 -0
- data/lib/hecks/codemod.rb +3 -3
- data/lib/hecks/coder/coder.bluebook +385 -0
- data/lib/hecks/coder/coder.hecksagon +12 -0
- data/lib/hecks/command_names/check.rb +39 -0
- data/lib/hecks/command_names/extractor.rb +67 -0
- data/lib/hecks/command_names/index.rb +40 -0
- data/lib/hecks/command_names/resolution.rb +81 -0
- data/lib/hecks/command_names/scan.rb +54 -0
- data/lib/hecks/command_names/sources.rb +73 -0
- data/lib/hecks/command_names.rb +26 -0
- data/lib/hecks/composer/adapters/claude_composer.rb +3 -2
- data/lib/hecks/composer/agent.rb +1 -1
- data/lib/hecks/composer/assistant.rb +2 -2
- data/lib/hecks/composer/behavior_run.rb +7 -1
- data/lib/hecks/composer/bluebook/composer.bluebook +18 -25
- data/lib/hecks/composer/bluebook/composer.hecksagon +1 -1
- data/lib/hecks/composer/board.rb +6 -6
- data/lib/hecks/composer/board_edit/command_text.rb +4 -1
- data/lib/hecks/composer/board_edit/source.rb +18 -9
- data/lib/hecks/composer/board_edit.rb +2 -2
- data/lib/hecks/composer/check.rb +22 -22
- data/lib/hecks/composer/domains.rb +1 -1
- data/lib/hecks/composer/jobs.rb +1 -1
- data/lib/hecks/composer/live.rb +19 -13
- data/lib/hecks/composer/outline.rb +4 -1
- data/lib/hecks/composer/page.html +1 -1
- data/lib/hecks/composer/panels.rb +6 -3
- data/lib/hecks/composer/parse.rb +53 -36
- data/lib/hecks/composer/session.rb +22 -16
- data/lib/hecks/composer/toolbox.rb +17 -7
- data/lib/hecks/composer/web.rb +3 -2
- data/lib/hecks/composer/workbench.rb +12 -9
- data/lib/hecks/composer.rb +1 -1
- data/lib/hecks/construct.rb +7 -7
- data/lib/hecks/corpus/adapters.rb +2 -1
- data/lib/hecks/corpus/generated_key.rb +205 -0
- data/lib/hecks/corpus/listing.rb +34 -0
- data/lib/hecks/corpus/routes.rb +25 -5
- data/lib/hecks/corpus/rust.rb +86 -35
- data/lib/hecks/corpus/sources.rb +14 -12
- data/lib/hecks/corpus/worlds.rb +2 -1
- data/lib/hecks/corpus.rb +57 -54
- data/lib/hecks/deploy/bluebook/deploy.bluebook +304 -518
- data/lib/hecks/deprecation.rb +23 -0
- data/lib/hecks/doc/reference/harvester.rb +4 -1
- data/lib/hecks/doc/reference/readme.rb +11 -6
- data/lib/hecks/doc/reference/rendering.rb +12 -6
- data/lib/hecks/doc/reference.rb +8 -6
- data/lib/hecks/embryonaut_bluebook/lock.rb +5 -1
- data/lib/hecks/embryonaut_bluebook/manifest.rb +8 -2
- data/lib/hecks/embryonaut_bluebook/registry/changelog.rb +4 -1
- data/lib/hecks/embryonaut_bluebook/registry/versions.rb +13 -2
- data/lib/hecks/embryonaut_bluebook/registry.rb +5 -2
- data/lib/hecks/embryonaut_bluebook/shape.rb +1 -1
- data/lib/hecks/embryonaut_bluebook/vendor.rb +5 -2
- data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +15 -1
- data/lib/hecks/embryonaut_bluebook.rb +26 -12
- data/lib/hecks/engine_agreement.rb +4 -1
- data/lib/hecks/fixer/fixer.bluebook +240 -0
- data/lib/hecks/fixer/fixer.hecksagon +17 -0
- data/lib/hecks/forms/app/commands.rb +35 -2
- data/lib/hecks/forms/app/records.rb +12 -12
- data/lib/hecks/forms/app/responses.rb +1 -1
- data/lib/hecks/forms/app.rb +22 -19
- data/lib/hecks/forms/command_form_renderer.rb +2 -2
- data/lib/hecks/forms/field_controls.rb +6 -1
- data/lib/hecks/forms/field_shape.rb +14 -6
- data/lib/hecks/forms/html.rb +8 -7
- data/lib/hecks/forms/html_pattern.rb +80 -0
- data/lib/hecks/forms/index_renderer.rb +11 -11
- data/lib/hecks/forms/params.rb +2 -1
- data/lib/hecks/forms/port_argument.rb +4 -1
- data/lib/hecks/forms/query_form_renderer.rb +1 -1
- data/lib/hecks/forms/record_renderer.rb +2 -2
- data/lib/hecks/forms/record_table.rb +1 -1
- data/lib/hecks/forms/reference_options.rb +2 -1
- data/lib/hecks/forms/text_shape.rb +4 -1
- data/lib/hecks/forms/value_object_shape.rb +1 -1
- data/lib/hecks/forms.rb +7 -7
- data/lib/hecks/fqn.rb +8 -2
- data/lib/hecks/framework/bluebook/change.bluebook +10 -15
- data/lib/hecks/framework/bluebook/change.hecksagon +1 -1
- data/lib/hecks/framework/bluebook/compliance.bluebook +27 -126
- data/lib/hecks/framework/bluebook/console_settings.bluebook +199 -114
- data/lib/hecks/framework/bluebook/framework.hecksagon +7 -0
- data/lib/hecks/framework/bluebook/governance.bluebook +36 -14
- data/lib/hecks/framework/bluebook/identity.bluebook +1 -1
- data/lib/hecks/framework/bluebook/privacy.bluebook +123 -19
- data/lib/hecks/framework/bluebook/privacy.key_keeper.adapter +7 -0
- data/lib/hecks/framework/bluebook/privacy.ports.hecksagon +19 -0
- data/lib/hecks/framework/compliance.oidc.json +6 -36
- data/lib/hecks/framework/console_settings.oidc.json +39 -24
- data/lib/hecks/framework/privacy.oidc.json +25 -0
- data/lib/hecks/framework.rb +24 -8
- data/lib/hecks/framework_bluebooks.rb +181 -0
- data/lib/hecks/freezer.rb +7 -1
- data/lib/hecks/fuzzing/combination_miner.rb +9 -6
- data/lib/hecks/fuzzing/concurrent_dispatch/world_copy.rb +4 -1
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +2 -2
- data/lib/hecks/fuzzing/domain_generator.rb +8 -3
- data/lib/hecks/fuzzing/era_boundary.rb +1 -1
- data/lib/hecks/fuzzing/failure_triage.rb +13 -6
- data/lib/hecks/fuzzing/form_census/{chapter_forms.rb → bluebook_forms.rb} +12 -12
- data/lib/hecks/fuzzing/form_census.rb +14 -12
- data/lib/hecks/fuzzing/generated_domain_check.rb +2 -1
- data/lib/hecks/fuzzing/isolated_boot/postgres_scratch.rb +14 -15
- data/lib/hecks/fuzzing/isolated_boot/scratch_schema.rb +19 -9
- data/lib/hecks/fuzzing/isolated_boot/worlds.rb +36 -13
- data/lib/hecks/fuzzing/isolated_boot.rb +5 -6
- data/lib/hecks/fuzzing/mutation/checks.rb +5 -4
- data/lib/hecks/fuzzing/mutation/finders.rb +25 -8
- data/lib/hecks/fuzzing/mutation/observation.rb +3 -1
- data/lib/hecks/fuzzing/mutation/source_map.rb +3 -1
- data/lib/hecks/fuzzing/nondeterministic.rb +10 -4
- data/lib/hecks/fuzzing/outside_world.rb +1 -1
- data/lib/hecks/fuzzing/projection_agreement/binding.rb +63 -0
- data/lib/hecks/fuzzing/projection_agreement/comparison.rb +104 -0
- data/lib/hecks/fuzzing/projection_agreement.rb +68 -0
- data/lib/hecks/fuzzing/properties/aggregation_recompute.rb +1 -1
- data/lib/hecks/fuzzing/properties/bulk_parity.rb +118 -0
- data/lib/hecks/fuzzing/properties/catalog.rb +7 -0
- data/lib/hecks/fuzzing/properties/cursor_walks.rb +56 -0
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +39 -1
- data/lib/hecks/fuzzing/properties/group_by_recompute.rb +6 -2
- data/lib/hecks/fuzzing/properties/grouped_reduction_recompute.rb +88 -0
- data/lib/hecks/fuzzing/properties/guards.rb +4 -1
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +12 -2
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +2 -1
- data/lib/hecks/fuzzing/properties/mutation_recompute.rb +3 -2
- data/lib/hecks/fuzzing/properties/piece_invariants.rb +3 -2
- data/lib/hecks/fuzzing/properties/query_rows.rb +5 -3
- data/lib/hecks/fuzzing/properties/querying.rb +6 -3
- data/lib/hecks/fuzzing/properties/read_model_names.rb +8 -2
- data/lib/hecks/fuzzing/properties/read_models.rb +2 -1
- data/lib/hecks/fuzzing/properties/refusals.rb +35 -0
- data/lib/hecks/fuzzing/properties/role_checks.rb +3 -2
- data/lib/hecks/fuzzing/properties/set_transform_parity.rb +73 -0
- data/lib/hecks/fuzzing/properties/tenant_scope.rb +3 -2
- data/lib/hecks/fuzzing/properties.rb +6 -0
- data/lib/hecks/fuzzing/qa_settings.rb +4 -4
- data/lib/hecks/fuzzing/replay/fan_out.rb +4 -3
- data/lib/hecks/fuzzing/replay/filters.rb +2 -2
- data/lib/hecks/fuzzing/replay/guard_check.rb +2 -2
- data/lib/hecks/fuzzing/replay/mutation_trace.rb +23 -10
- data/lib/hecks/fuzzing/replay/observation.rb +11 -7
- data/lib/hecks/fuzzing/replay/read_only_steps.rb +40 -3
- data/lib/hecks/fuzzing/replay/refusal_trace.rb +44 -0
- data/lib/hecks/fuzzing/replay/role_check.rb +2 -2
- data/lib/hecks/fuzzing/replay/session.rb +38 -18
- data/lib/hecks/fuzzing/replay/validation_reports.rb +61 -0
- data/lib/hecks/fuzzing/replay.rb +2 -2
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +3 -3
- data/lib/hecks/fuzzing/self_consistency/saga_redelivery.rb +18 -8
- data/lib/hecks/fuzzing/self_consistency/sagas.rb +2 -2
- data/lib/hecks/fuzzing/self_consistency/value_objects.rb +9 -2
- data/lib/hecks/fuzzing/self_consistency.rb +4 -8
- data/lib/hecks/fuzzing/sequence_generator/adversary/argument_mutations.rb +15 -5
- data/lib/hecks/fuzzing/sequence_generator/adversary/caller_draw.rb +14 -10
- data/lib/hecks/fuzzing/sequence_generator/adversary/precedence_mutations.rb +1 -1
- data/lib/hecks/fuzzing/sequence_generator/argument_drawing.rb +2 -1
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +21 -13
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +1 -1
- data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +3 -3
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +2 -2
- data/lib/hecks/fuzzing/sequence_generator.rb +1 -2
- data/lib/hecks/fuzzing/shrinker.rb +4 -1
- data/lib/hecks/fuzzing/value_generator.rb +14 -8
- data/lib/hecks/fuzzing.rb +1 -0
- data/lib/hecks/grammar/dialects.rb +56 -0
- data/lib/hecks/grammar/evolve/arguments.rb +1 -1
- data/lib/hecks/grammar/evolve/keywords.rb +1 -1
- data/lib/hecks/grammar/evolve/seeds.rb +34 -8
- data/lib/hecks/grammar/expression.bluebook +3 -0
- data/lib/hecks/grammar/expression_operators.json +1071 -1
- data/lib/hecks/grammar/operators.rb +45 -22
- data/lib/hecks/grammar/translation.bluebook +3 -1
- data/lib/hecks/grammar/translation_ledger.rb +45 -0
- data/lib/hecks/grammar/translation_rules.json +710 -0
- data/lib/hecks/grammar.rb +27 -23
- data/lib/hecks/hecks/adapter_words.json +7 -0
- data/lib/hecks/hecks/adapters/area_overlap.rb +156 -0
- data/lib/hecks/hecks/adapters/claude_agents.adapter +7 -0
- data/lib/hecks/hecks/adapters/claude_agents.rb +124 -0
- data/lib/hecks/hecks/adapters/claude_transcript.rb +71 -0
- data/lib/hecks/hecks/adapters/codebase/batch_runs.rb +60 -0
- data/lib/hecks/hecks/adapters/codebase/cache_clearing.rb +32 -0
- data/lib/hecks/hecks/adapters/codebase/cargo_tests.rb +50 -0
- data/lib/hecks/hecks/adapters/codebase/changed_specs.rb +52 -0
- data/lib/hecks/hecks/adapters/codebase/codemods.rb +3 -2
- data/lib/hecks/hecks/adapters/codebase/composing.rb +3 -2
- data/lib/hecks/hecks/adapters/codebase/conformance.rb +30 -1
- data/lib/hecks/hecks/adapters/codebase/corpus_queries.rb +53 -0
- data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +1 -1
- data/lib/hecks/hecks/adapters/codebase/declarations.rb +144 -0
- data/lib/hecks/hecks/adapters/codebase/generated_keys.rb +31 -0
- data/lib/hecks/hecks/adapters/codebase/impacted_specs.rb +110 -0
- data/lib/hecks/hecks/adapters/codebase/inspection.rb +5 -4
- data/lib/hecks/hecks/adapters/codebase/language.rb +3 -2
- data/lib/hecks/hecks/adapters/codebase/launcher_text.rb +39 -0
- data/lib/hecks/hecks/adapters/codebase/minitest_runs.rb +52 -0
- data/lib/hecks/hecks/adapters/codebase/npm_registry.rb +7 -1
- data/lib/hecks/hecks/adapters/codebase/previewing.rb +62 -0
- data/lib/hecks/hecks/adapters/codebase/promotion/gate.rb +1 -1
- data/lib/hecks/hecks/adapters/codebase/reading.rb +94 -0
- data/lib/hecks/hecks/adapters/codebase/regeneration.rb +57 -10
- data/lib/hecks/hecks/adapters/codebase/release_facts.rb +1 -1
- data/lib/hecks/hecks/adapters/codebase/ruby_child.rb +5 -2
- data/lib/hecks/hecks/adapters/codebase/run_options.rb +35 -0
- data/lib/hecks/hecks/adapters/codebase/scripting.rb +39 -0
- data/lib/hecks/hecks/adapters/codebase/search.rb +91 -0
- data/lib/hecks/hecks/adapters/codebase/source_tree.rb +114 -51
- data/lib/hecks/hecks/adapters/codebase/spec_files/report.rb +71 -0
- data/lib/hecks/hecks/adapters/codebase/spec_files/shared_run.rb +73 -0
- data/lib/hecks/hecks/adapters/codebase/spec_files.rb +95 -0
- data/lib/hecks/hecks/adapters/codebase/static_directory.rb +59 -0
- data/lib/hecks/hecks/adapters/codebase/style.rb +2 -2
- data/lib/hecks/hecks/adapters/codebase/test_runner.rb +82 -14
- data/lib/hecks/hecks/adapters/codebase/test_scope.rb +105 -0
- data/lib/hecks/hecks/adapters/codebase/test_suite.rb +73 -21
- data/lib/hecks/hecks/adapters/console_capture.rb +28 -1
- data/lib/hecks/hecks/adapters/cost_explorer.rb +9 -1
- data/lib/hecks/hecks/adapters/deploy_plans.rb +12 -3
- data/lib/hecks/hecks/adapters/deploy_toolchain/answers.rb +14 -5
- data/lib/hecks/hecks/adapters/deploy_toolchain/scripts.rb +6 -3
- data/lib/hecks/hecks/adapters/deploy_toolchain.rb +3 -3
- data/lib/hecks/hecks/adapters/desktop_alert/alert.rb +50 -0
- data/lib/hecks/hecks/adapters/desktop_alert.adapter +7 -0
- data/lib/hecks/hecks/adapters/desktop_alert.rb +99 -0
- data/lib/hecks/hecks/adapters/dispatching/brief_text.rb +51 -0
- data/lib/hecks/hecks/adapters/dispatching/launcher.rb +97 -0
- data/lib/hecks/hecks/adapters/dispatching/plan.rb +82 -0
- data/lib/hecks/hecks/adapters/dispatching/rows.rb +66 -0
- data/lib/hecks/hecks/adapters/dispatching/settings.rb +81 -0
- data/lib/hecks/hecks/adapters/dispatching/settler.rb +40 -0
- data/lib/hecks/hecks/adapters/dispatching.adapter +7 -0
- data/lib/hecks/hecks/adapters/dispatching.rb +93 -0
- data/lib/hecks/hecks/adapters/doctor_reading/report.rb +27 -0
- data/lib/hecks/hecks/adapters/doctor_reading.adapter +7 -0
- data/lib/hecks/hecks/adapters/doctor_reading.rb +161 -0
- data/lib/hecks/hecks/adapters/finding_github.rb +4 -1
- data/lib/hecks/hecks/adapters/first_admin.rb +16 -9
- data/lib/hecks/hecks/adapters/git.rb +5 -5
- data/lib/hecks/hecks/adapters/git_checkout.adapter +7 -0
- data/lib/hecks/hecks/adapters/git_checkout.rb +99 -0
- data/lib/hecks/hecks/adapters/git_commit.adapter +7 -0
- data/lib/hecks/hecks/adapters/git_commit.rb +61 -0
- data/lib/hecks/hecks/adapters/git_landing/finisher.rb +82 -0
- data/lib/hecks/hecks/adapters/git_landing/foreign_hold.rb +111 -0
- data/lib/hecks/hecks/adapters/git_landing/line.rb +171 -0
- data/lib/hecks/hecks/adapters/git_landing/lineup.rb +98 -0
- data/lib/hecks/hecks/adapters/git_landing/merger.rb +85 -0
- data/lib/hecks/hecks/adapters/git_landing/numbering.rb +54 -0
- data/lib/hecks/hecks/adapters/git_landing/rivals.rb +59 -0
- data/lib/hecks/hecks/adapters/git_landing/ticket.rb +156 -0
- data/lib/hecks/hecks/adapters/git_landing/tidy.rb +147 -0
- data/lib/hecks/hecks/adapters/git_landing/train.rb +104 -0
- data/lib/hecks/hecks/adapters/git_landing/verdict.rb +64 -0
- data/lib/hecks/hecks/adapters/git_landing/waiting.rb +120 -0
- data/lib/hecks/hecks/adapters/git_landing.adapter +7 -0
- data/lib/hecks/hecks/adapters/git_landing.rb +189 -0
- data/lib/hecks/hecks/adapters/git_launcher.adapter +7 -0
- data/lib/hecks/hecks/adapters/git_launcher.rb +82 -0
- data/lib/hecks/hecks/adapters/git_main_pull.rb +99 -0
- data/lib/hecks/hecks/adapters/git_refs.rb +8 -4
- data/lib/hecks/hecks/adapters/git_rehearsal/bench.rb +82 -0
- data/lib/hecks/hecks/adapters/git_rehearsal/due.rb +84 -0
- data/lib/hecks/hecks/adapters/git_rehearsal/impacted/skips.rb +47 -0
- data/lib/hecks/hecks/adapters/git_rehearsal/impacted/spec_run.rb +75 -0
- data/lib/hecks/hecks/adapters/git_rehearsal/impacted.rb +181 -0
- data/lib/hecks/hecks/adapters/git_rehearsal/line.rb +76 -0
- data/lib/hecks/hecks/adapters/git_rehearsal/reading.rb +24 -0
- data/lib/hecks/hecks/adapters/git_rehearsal/record.rb +146 -0
- data/lib/hecks/hecks/adapters/git_rehearsal/spec_map/corpus.rb +25 -0
- data/lib/hecks/hecks/adapters/git_rehearsal/spec_map/needles.rb +61 -0
- data/lib/hecks/hecks/adapters/git_rehearsal/spec_map.rb +105 -0
- data/lib/hecks/hecks/adapters/git_rehearsal/stages.rb +118 -0
- data/lib/hecks/hecks/adapters/git_rehearsal.adapter +7 -0
- data/lib/hecks/hecks/adapters/git_rehearsal.rb +141 -0
- data/lib/hecks/hecks/adapters/git_train/bench.rb +76 -0
- data/lib/hecks/hecks/adapters/git_train/branch_guard.rb +62 -0
- data/lib/hecks/hecks/adapters/git_train/carriage.rb +115 -0
- data/lib/hecks/hecks/adapters/git_train/launcher_shape.rb +75 -0
- data/lib/hecks/hecks/adapters/git_train/local_branch.rb +69 -0
- data/lib/hecks/hecks/adapters/git_train/mint_step.rb +47 -0
- data/lib/hecks/hecks/adapters/git_train/reading.rb +26 -0
- data/lib/hecks/hecks/adapters/git_train/settlement.rb +167 -0
- data/lib/hecks/hecks/adapters/git_train/survey.rb +60 -0
- data/lib/hecks/hecks/adapters/git_train.adapter +7 -0
- data/lib/hecks/hecks/adapters/git_train.rb +146 -0
- data/lib/hecks/hecks/adapters/git_worktree_add.adapter +7 -0
- data/lib/hecks/hecks/adapters/git_worktree_add.rb +68 -0
- data/lib/hecks/hecks/adapters/git_worktrees.rb +81 -0
- data/lib/hecks/hecks/adapters/github_pull_requests.adapter +7 -0
- data/lib/hecks/hecks/adapters/github_pull_requests.rb +109 -0
- data/lib/hecks/hecks/adapters/host_http.rb +9 -8
- data/lib/hecks/hecks/adapters/in_process_access.rb +3 -2
- data/lib/hecks/hecks/adapters/in_process_boot.rb +68 -39
- data/lib/hecks/hecks/adapters/in_process_operations.rb +40 -20
- data/lib/hecks/hecks/adapters/in_process_undo.rb +17 -0
- data/lib/hecks/hecks/adapters/journal_store/changes.rb +18 -9
- data/lib/hecks/hecks/adapters/journal_store/compaction.rb +14 -7
- data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +35 -20
- data/lib/hecks/hecks/adapters/journal_store/examination.rb +20 -4
- data/lib/hecks/hecks/adapters/journal_store/held_domain/renaming.rb +45 -0
- data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +47 -9
- data/lib/hecks/hecks/adapters/journal_store/held_mint.rb +128 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/attestation.rb +3 -3
- data/lib/hecks/hecks/adapters/journal_store/readings/boot_status.rb +58 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/composition.rb +39 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/outcomes.rb +76 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/postgres_reader.rb +44 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/reader.rb +64 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/report.rb +102 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/sqlite_reader.rb +43 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/stores.rb +80 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/subscribers.rb +72 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/summary.rb +39 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/event_trace.rb +39 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/command_line.rb +57 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/edge_guards.rb +107 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/inspection.rb +94 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/plan.rb +66 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/report.rb +72 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/store.rb +34 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/watermark_guards.rb +86 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/world.rb +66 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan.rb +36 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/projection_audit.rb +64 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/scaffolding.rb +10 -7
- data/lib/hecks/hecks/adapters/journal_store/readings/sqlite_status/database_reading.rb +113 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/sqlite_status/read_only.rb +33 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/sqlite_status.rb +32 -0
- data/lib/hecks/hecks/adapters/journal_store/readings.rb +15 -3
- data/lib/hecks/hecks/adapters/journal_store/reconcile_report.rb +60 -0
- data/lib/hecks/hecks/adapters/journal_store/reconciliation.rb +121 -0
- data/lib/hecks/hecks/adapters/journal_store/translation_write/shape_edge.rb +59 -0
- data/lib/hecks/hecks/adapters/journal_store/translation_write.rb +123 -0
- data/lib/hecks/hecks/adapters/journal_store.rb +18 -2
- data/lib/hecks/hecks/adapters/landed_work.adapter +7 -0
- data/lib/hecks/hecks/adapters/landed_work.rb +52 -0
- data/lib/hecks/hecks/adapters/ledger/chain.rb +63 -0
- data/lib/hecks/hecks/adapters/ledger/journal.rb +105 -0
- data/lib/hecks/hecks/adapters/ledger.adapter +7 -0
- data/lib/hecks/hecks/adapters/ledger.rb +89 -0
- data/lib/hecks/hecks/adapters/local_files.rb +21 -7
- data/lib/hecks/hecks/adapters/pg_admin.rb +7 -1
- data/lib/hecks/hecks/adapters/process_pool.rb +3 -2
- data/lib/hecks/hecks/adapters/push_size.rb +57 -0
- data/lib/hecks/hecks/adapters/qa_quiescing.adapter +7 -0
- data/lib/hecks/hecks/adapters/qa_quiescing.rb +57 -0
- data/lib/hecks/hecks/adapters/rails_app_files.rb +64 -0
- data/lib/hecks/hecks/adapters/rehearsal/audit_report.rb +4 -1
- data/lib/hecks/hecks/adapters/rehearsal/inquiry.rb +39 -12
- data/lib/hecks/hecks/adapters/rehearsal/memory_store.rb +65 -5
- data/lib/hecks/hecks/adapters/rehearsal/postgres_census.rb +4 -4
- data/lib/hecks/hecks/adapters/rehearsal/postgres_reading.rb +30 -7
- data/lib/hecks/hecks/adapters/rehearsal/postgres_store.rb +4 -1
- data/lib/hecks/hecks/adapters/rehearsal/rust_audit.rb +1 -1
- data/lib/hecks/hecks/adapters/rehearsal/subject.rb +44 -9
- data/lib/hecks/hecks/adapters/rust_toolchain.rb +15 -4
- data/lib/hecks/hecks/adapters/rust_workspace.rb +1 -1
- data/lib/hecks/hecks/adapters/settings_reading/disposable_ledger.rb +32 -0
- data/lib/hecks/hecks/adapters/settings_reading/push_nudge.rb +26 -0
- data/lib/hecks/hecks/adapters/settings_reading/stores.rb +76 -0
- data/lib/hecks/hecks/adapters/settings_reading/test_scope.rb +28 -0
- data/lib/hecks/hecks/adapters/settings_reading.adapter +7 -0
- data/lib/hecks/hecks/adapters/settings_reading.rb +168 -0
- data/lib/hecks/hecks/adapters/shell.rb +3 -0
- data/lib/hecks/hecks/adapters/site_toolchain.rb +8 -8
- data/lib/hecks/hecks/adapters/started_work.rb +42 -0
- data/lib/hecks/hecks/adapters/terminal.rb +12 -10
- data/lib/hecks/hecks/adapters/where_reading.adapter +7 -0
- data/lib/hecks/hecks/adapters/where_reading.rb +64 -0
- data/lib/hecks/hecks/adapters/work_areas.rb +57 -0
- data/lib/hecks/hecks/adapters/work_limits.rb +57 -0
- data/lib/hecks/hecks/adapters/world_clearing.rb +2 -1
- data/lib/hecks/hecks/build/build.bluebook +576 -0
- data/lib/hecks/hecks/check/check.bluebook +966 -0
- data/lib/hecks/hecks/codebase.behaviors +72 -4
- data/lib/hecks/hecks/composer.behaviors +10 -10
- data/lib/hecks/hecks/context_map.hecksagon +7 -6
- data/lib/hecks/hecks/custodian.behaviors +124 -3
- data/lib/hecks/hecks/delegate/delegate.bluebook +355 -0
- data/lib/hecks/hecks/deliver/deliver.bluebook +945 -0
- data/lib/hecks/hecks/deploy.behaviors +1 -1
- data/lib/hecks/hecks/deploy.world +3 -4
- data/lib/hecks/hecks/evolve/evolve.bluebook +788 -0
- data/lib/hecks/hecks/find/find.bluebook +81 -0
- data/lib/hecks/hecks/hecks.behaviors +2 -2
- data/lib/hecks/hecks/hecks.bluebook +0 -138
- data/lib/hecks/hecks/hecks.contextmap +27 -0
- data/lib/hecks/hecks/hecks.hecksagon +312 -23
- data/lib/hecks/hecks/hecks.world +54 -27
- data/lib/hecks/hecks/implicit_moves.json +24 -0
- data/lib/hecks/hecks/migrate/migrate.bluebook +1066 -0
- data/lib/hecks/hecks/operate/operate.bluebook +695 -0
- data/lib/hecks/hecks/quiesce/quiesce.bluebook +117 -0
- data/lib/hecks/hecks/rehearse/rehearse.bluebook +133 -0
- data/lib/hecks/hecks/release/release.bluebook +916 -0
- data/lib/hecks/hecks/serve/serve.bluebook +134 -0
- data/lib/hecks/hecks/shapes.json +3 -0
- data/lib/hecks/hecks/site.behaviors +1 -1
- data/lib/hecks/hecks/site.world +3 -3
- data/lib/hecks/hecks/start/start.bluebook +194 -0
- data/lib/hecks/hecks/test/test.bluebook +638 -0
- data/lib/hecks/hecks/tickets.world +14 -0
- data/lib/hecks/ir.rb +8 -1
- data/lib/hecks/kernel_capabilities/templates.rb +4 -3
- data/lib/hecks/kernel_capabilities.rb +6 -6
- data/lib/hecks/language/adapter.bluebook +61 -0
- data/lib/hecks/language/bluebook/aggregate.bluebook +58 -6
- data/lib/hecks/language/bluebook/attaches/paging.bluebook +1 -1
- data/lib/hecks/language/bluebook/bluebook.behaviors +6 -6
- data/lib/hecks/language/bluebook/bluebook.bluebook +62 -51
- data/lib/hecks/language/bluebook/bluebook.hecksagon +1 -1
- data/lib/hecks/language/bluebook/command.bluebook +69 -2
- data/lib/hecks/language/bluebook/entity.bluebook +2 -2
- data/lib/hecks/language/bluebook/policy.behaviors +2 -2
- data/lib/hecks/language/bluebook/policy.bluebook +3 -3
- data/lib/hecks/language/bluebook/process_manager.bluebook +17 -4
- data/lib/hecks/language/bluebook/projection.bluebook +11 -10
- data/lib/hecks/language/bluebook/query.bluebook +1 -0
- data/lib/hecks/language/bluebook/shape.bluebook +1 -1
- data/lib/hecks/language/bluebook/syntax.bluebook +3 -1
- data/lib/hecks/language/bluebook/vocabulary.bluebook +417 -16
- data/lib/hecks/language/context_map/context_map.bluebook +90 -0
- data/lib/hecks/language/hecksagon/domain_port.bluebook +3 -2
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +8 -8
- data/lib/hecks/language/hecksagon/port_operation.bluebook +14 -0
- data/lib/hecks/language/kinds/run.kind +120 -0
- data/lib/hecks/language/oidc.json +20 -0
- data/lib/hecks/language/port.bluebook +1 -1
- data/lib/hecks/language/sentence/sentence.bluebook +210 -0
- data/lib/hecks/language/translation/translation_aggregate.bluebook +24 -0
- data/lib/hecks/language/world/world.bluebook +6 -6
- data/lib/hecks/literal.rb +8 -2
- data/lib/hecks/module_folders.rb +31 -0
- data/lib/hecks/naming.rb +44 -14
- data/lib/hecks/persistence_legacy_fixture/postgres_stores.rb +7 -6
- data/lib/hecks/persistence_legacy_fixture/regenerate.rb +6 -2
- data/lib/hecks/ports/access_control.rb +2 -2
- data/lib/hecks/ports/agent/answers.rb +2 -2
- data/lib/hecks/ports/agent.rb +2 -2
- data/lib/hecks/ports/authentication.port +6 -0
- data/lib/hecks/ports/authentication.rb +67 -0
- data/lib/hecks/ports/authorization.rb +3 -3
- data/lib/hecks/ports/dispatch.port +5 -0
- data/lib/hecks/ports/dispatch.rb +28 -0
- data/lib/hecks/ports/key_vault.rb +10 -7
- data/lib/hecks/ports/loading.rb +23 -7
- data/lib/hecks/ports/persistence/append_only.rb +44 -9
- data/lib/hecks/ports/persistence/binding_policy.rb +73 -12
- data/lib/hecks/ports/persistence/codec_boundary.rb +4 -3
- data/lib/hecks/ports/persistence/mint_door.rb +74 -0
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +16 -15
- data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +9 -6
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +11 -11
- data/lib/hecks/ports/persistence/plugins/era/era_status.rb +48 -0
- data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/projected_bluebook.rb +127 -0
- data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +6 -6
- data/lib/hecks/ports/persistence/plugins/era/translation/additive_shape.rb +107 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +9 -3
- data/lib/hecks/ports/persistence/plugins/era/translation/compose.rb +155 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/compose_render.rb +79 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/edge_files.rb +49 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/edge_route.rb +61 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/implicit_edge.rb +67 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/translation/reconcile.rb +130 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/reconcile_files.rb +35 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +32 -19
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +13 -5
- data/lib/hecks/ports/persistence/plugins/era/translation.rb +5 -0
- data/lib/hecks/ports/persistence/plugins/era.rb +1 -1
- data/lib/hecks/ports/persistence/remote_runtime.rb +3 -2
- data/lib/hecks/ports/persistence/repository_factory.rb +11 -3
- data/lib/hecks/ports/persistence/set_statement.rb +29 -0
- data/lib/hecks/ports/persistence/set_transforming.rb +30 -0
- data/lib/hecks/ports/persistence/state_codec.rb +3 -3
- data/lib/hecks/ports/persistence/stored_name_guard.rb +36 -0
- data/lib/hecks/ports/persistence.rb +2 -4
- data/lib/hecks/ports/projection.rb +4 -1
- data/lib/hecks/ports/query/cursor.rb +131 -0
- data/lib/hecks/ports/query/in_memory.rb +17 -10
- data/lib/hecks/ports/query.rb +4 -2
- data/lib/hecks/ports.rb +1 -0
- data/lib/hecks/projection_files/expression_tables.rb +3 -3
- data/lib/hecks/projection_files/sentence_table.rb +17 -0
- data/lib/hecks/projection_files.rb +16 -13
- data/lib/hecks/projections/bootstrap_table.rb +3 -3
- data/lib/hecks/projections/ci_pipeline/table/checks.rb +137 -0
- data/lib/hecks/projections/ci_pipeline/table/lookup.rb +59 -0
- data/lib/hecks/projections/ci_pipeline/table/refusals.rb +58 -0
- data/lib/hecks/projections/ci_pipeline/table/rows.rb +119 -0
- data/lib/hecks/projections/ci_pipeline/table/tree.rb +30 -0
- data/lib/hecks/projections/ci_pipeline/table/typing.rb +92 -0
- data/lib/hecks/projections/ci_pipeline/table.rb +112 -0
- data/lib/hecks/projections/ci_pipeline/workflows.rb +162 -0
- data/lib/hecks/projections/ci_pipeline/yaml_text.rb +104 -0
- data/lib/hecks/projections/command_schema/shape.rb +95 -0
- data/lib/hecks/projections/command_schema.rb +74 -0
- data/lib/hecks/projections/context_map_diagram.rb +135 -0
- data/lib/hecks/projections/context_relationships.rb +125 -0
- data/lib/hecks/projections/deploy/box/access.rb +7 -4
- data/lib/hecks/projections/deploy/box/caddy.rb +2 -1
- data/lib/hecks/projections/deploy/box/compose.rb +4 -8
- data/lib/hecks/projections/deploy/box/edge.rb +2 -1
- data/lib/hecks/projections/deploy/box/hosting.rb +5 -3
- data/lib/hecks/projections/deploy/box/hosting_parts.rb +27 -12
- data/lib/hecks/projections/deploy/box/logging.rb +2 -3
- data/lib/hecks/projections/deploy/box/roll_recipe.rb +2 -4
- data/lib/hecks/projections/deploy/box/roll_scripts.rb +2 -17
- data/lib/hecks/projections/deploy/box/settings/containers.rb +29 -15
- data/lib/hecks/projections/deploy/box/settings/patterns.rb +5 -6
- data/lib/hecks/projections/deploy/box/settings/types.rb +5 -10
- data/lib/hecks/projections/deploy/box/settings.rb +9 -8
- data/lib/hecks/projections/deploy/box/stack_yaml.rb +10 -14
- data/lib/hecks/projections/deploy/box/templates/box.yaml.tmpl +0 -1
- data/lib/hecks/projections/deploy/box/templates/deploy-service.sh.tmpl +16 -3
- data/lib/hecks/projections/deploy/box/templates/hosting.mk.tmpl +7 -6
- data/lib/hecks/projections/deploy/box/templates/render-compose-taskdef.sh.tmpl +2 -6
- data/lib/hecks/projections/deploy/box/templates/render-compose.sh.tmpl +2 -6
- data/lib/hecks/projections/deploy/box.rb +17 -10
- data/lib/hecks/projections/deploy/fargate/assembly.rb +7 -2
- data/lib/hecks/projections/deploy/fargate/cdn/options.rb +4 -1
- data/lib/hecks/projections/deploy/fargate/check.rb +3 -1
- data/lib/hecks/projections/deploy/fargate/containers/rendering.rb +8 -5
- data/lib/hecks/projections/deploy/fargate/containers/routing.rb +2 -1
- data/lib/hecks/projections/deploy/fargate/monitoring/reading.rb +4 -1
- data/lib/hecks/projections/deploy/fargate/sections.rb +7 -4
- data/lib/hecks/projections/deploy/fargate/settings/ids.rb +4 -1
- data/lib/hecks/projections/deploy/fargate/settings/tuning.rb +13 -4
- data/lib/hecks/projections/deploy/fargate/stack/blocks.rb +6 -1
- data/lib/hecks/projections/deploy/fargate/stack/readers.rb +2 -1
- data/lib/hecks/projections/deploy/fargate/stack.rb +11 -6
- data/lib/hecks/projections/deploy/fargate/yaml.rb +10 -3
- data/lib/hecks/projections/deploy/fargate.rb +8 -3
- data/lib/hecks/projections/deploy/lambda/stack/blocks.rb +4 -2
- data/lib/hecks/projections/deploy/lambda/stack/deploy_chain.rb +2 -1
- data/lib/hecks/projections/deploy/lambda/stack/reading.rb +12 -9
- data/lib/hecks/projections/deploy/lambda/stack/reading_web.rb +7 -2
- data/lib/hecks/projections/deploy/lambda/stack/web.rb +2 -1
- data/lib/hecks/projections/deploy/lambda.rb +8 -3
- data/lib/hecks/projections/deploy/preview/containers.rb +14 -1
- data/lib/hecks/projections/deploy/preview/preview.sh.erb +2 -2
- data/lib/hecks/projections/deploy/preview/routing_yaml.rb +8 -6
- data/lib/hecks/projections/deploy/preview/settings.rb +23 -5
- data/lib/hecks/projections/deploy/preview/task_yaml.rb +1 -1
- data/lib/hecks/projections/deploy/preview/yaml_text.rb +2 -1
- data/lib/hecks/projections/deploy/scripts/settings.rb +5 -2
- data/lib/hecks/projections/deploy/shared.rb +12 -1
- data/lib/hecks/projections/deploy/shared_database_instance.rb +1 -1
- data/lib/hecks/projections/deploy/smoke.rb +3 -1
- data/lib/hecks/projections/deploy/template_diff/normalizer.rb +4 -1
- data/lib/hecks/projections/deploy/templates/fargate/Makefile.tmpl +1 -1
- data/lib/hecks/projections/deploy/templates/lambda/Makefile.tmpl +3 -3
- data/lib/hecks/projections/deploy/templates/lambda/mint_era_shared.tmpl +2 -2
- data/lib/hecks/projections/deploy/templates/lambda/nat_comment_oauth.tmpl +1 -1
- data/lib/hecks/projections/deploy/vercel.rb +1 -1
- data/lib/hecks/projections/diagrams/dispatch.rb +5 -3
- data/lib/hecks/projections/diagrams/statecharts.rb +8 -3
- data/lib/hecks/projections/diagrams/structure.rb +9 -6
- data/lib/hecks/projections/diagrams.rb +9 -7
- data/lib/hecks/projections/glossary/entries.rb +4 -4
- data/lib/hecks/projections/glossary/html/page.rb +4 -1
- data/lib/hecks/projections/glossary/html/parser.rb +13 -4
- data/lib/hecks/projections/glossary/html/sections.rb +4 -1
- data/lib/hecks/projections/glossary/html.rb +10 -3
- data/lib/hecks/projections/glossary/markdown.rb +4 -3
- data/lib/hecks/projections/glossary/mermaid.rb +8 -5
- data/lib/hecks/projections/glossary/sections.rb +1 -1
- data/lib/hecks/projections/glossary/sensitivity.rb +11 -4
- data/lib/hecks/projections/glossary/sentences/actions.rb +5 -2
- data/lib/hecks/projections/glossary/sentences/queries.rb +2 -1
- data/lib/hecks/projections/glossary/sentences/value_objects.rb +15 -6
- data/lib/hecks/projections/glossary/sentences.rb +6 -3
- data/lib/hecks/projections/glossary/slugs.rb +8 -1
- data/lib/hecks/projections/glossary.rb +3 -3
- data/lib/hecks/projections/model.rb +10 -6
- data/lib/hecks/projections/oidc.rb +19 -7
- data/lib/hecks/projections/parser_table.rb +10 -10
- data/lib/hecks/projections/phrase_table.rb +105 -0
- data/lib/hecks/projections/plain_english.rb +14 -4
- data/lib/hecks/projections/rails_app.rb +77 -0
- data/lib/hecks/projections/reference.rb +2 -2
- data/lib/hecks/projections/rust_vocabulary/arguments.rb +1 -1
- data/lib/hecks/projections/rust_vocabulary/tables.rb +20 -0
- data/lib/hecks/projections/rust_vocabulary.rb +14 -17
- data/lib/hecks/projections/site/admin.rb +7 -7
- data/lib/hecks/projections/site/admin_cms.rb +1 -1
- data/lib/hecks/projections/site/cms_editor/blocks.rb +5 -2
- data/lib/hecks/projections/site/cms_editor/checks.rb +9 -6
- data/lib/hecks/projections/site/cms_editor/color.rb +4 -1
- data/lib/hecks/projections/site/cms_editor/composition.rb +20 -18
- data/lib/hecks/projections/site/cms_editor/destructive.rb +4 -1
- data/lib/hecks/projections/site/cms_editor/drafts.rb +6 -2
- data/lib/hecks/projections/site/cms_editor/key_kinds.rb +4 -1
- data/lib/hecks/projections/site/cms_editor/limits.rb +1 -1
- data/lib/hecks/projections/site/cms_editor/media.rb +1 -1
- data/lib/hecks/projections/site/cms_editor/moment.rb +3 -1
- data/lib/hecks/projections/site/cms_editor/pickers.rb +1 -1
- data/lib/hecks/projections/site/cms_editor/preview.rb +10 -4
- data/lib/hecks/projections/site/cms_editor/relations.rb +3 -2
- data/lib/hecks/projections/site/cms_editor/scale_checks.rb +32 -25
- data/lib/hecks/projections/site/cms_editor/scheduling.rb +1 -1
- data/lib/hecks/projections/site/cms_editor/schema.rb +31 -29
- data/lib/hecks/projections/site/cms_editor/setting.rb +34 -27
- data/lib/hecks/projections/site/cms_editor/targets.rb +9 -6
- data/lib/hecks/projections/site/cms_editor/templates/src/app.ts.tmpl +3 -3
- data/lib/hecks/projections/site/cms_editor/templates/src/commands.ts.tmpl +2 -2
- data/lib/hecks/projections/site/cms_editor/templates/src/host.ts.tmpl +1 -1
- data/lib/hecks/projections/site/cms_editor/templates/src/media/handler.ts.tmpl +4 -4
- data/lib/hecks/projections/site/cms_editor/templates/src/names.ts.tmpl +14 -14
- data/lib/hecks/projections/site/cms_editor/templates/src/schema.ts.tmpl +12 -12
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/pages.ts.tmpl +12 -12
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/pickers.ts.tmpl +1 -1
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/schedule.ts.tmpl +2 -2
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/shell.ts.tmpl +11 -11
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/world.ts.tmpl +3 -3
- data/lib/hecks/projections/site/cms_editor/theme_checks.rb +8 -2
- data/lib/hecks/projections/site/cms_editor.rb +19 -16
- data/lib/hecks/projections/site/edge/checks.rb +1 -1
- data/lib/hecks/projections/site/edge/function_checks.rb +1 -1
- data/lib/hecks/projections/site/edge/function_code.rb +4 -1
- data/lib/hecks/projections/site/edge/pattern.rb +4 -1
- data/lib/hecks/projections/site/edge/route_checks.rb +2 -2
- data/lib/hecks/projections/site/edge/rules.rb +1 -1
- data/lib/hecks/projections/site/edge.rb +14 -8
- data/lib/hecks/projections/site/live_edge.rb +2 -2
- data/lib/hecks/projections/site/payload/fields/definitions.rb +1 -1
- data/lib/hecks/projections/site/payload/lifecycle/text.rb +1 -1
- data/lib/hecks/projections/site/payload/model.rb +16 -12
- data/lib/hecks/projections/site/payload/specs.rb +4 -2
- data/lib/hecks/projections/site/payload_driver.rb +9 -8
- data/lib/hecks/projections/site/probe.rb +12 -3
- data/lib/hecks/projections/site/regions.rb +9 -1
- data/lib/hecks/projections/site/role_probe.rb +7 -7
- data/lib/hecks/projections/site/root_rows.rb +4 -4
- data/lib/hecks/projections/site/routes_ts/listings.rb +13 -6
- data/lib/hecks/projections/site/routes_ts.rb +6 -3
- data/lib/hecks/projections/site/site_admin.rb +1 -1
- data/lib/hecks/projections/site/site_cdn.rb +3 -2
- data/lib/hecks/projections/site/site_host.rb +1 -1
- data/lib/hecks/projections/site/site_root.rb +4 -4
- data/lib/hecks/projections/site/table/checks.rb +4 -1
- data/lib/hecks/projections/site/table/navigation_checks.rb +2 -2
- data/lib/hecks/projections/site/table/row_builder.rb +7 -7
- data/lib/hecks/projections/site/table/row_defaults.rb +1 -1
- data/lib/hecks/projections/site/table.rb +32 -26
- data/lib/hecks/projections/statements/actions.rb +4 -1
- data/lib/hecks/projections/statements/relationships.rb +15 -2
- data/lib/hecks/projections/statements.rb +2 -2
- data/lib/hecks/projections/undo.rb +46 -0
- data/lib/hecks/projections/vocabulary.rb +6 -6
- data/lib/hecks/projections/world_skeleton.rb +68 -0
- data/lib/hecks/projections.rb +7 -0
- data/lib/hecks/projector/cli_audience.rb +12 -9
- data/lib/hecks/projector/cli_projector/claims.rb +19 -8
- data/lib/hecks/projector/cli_projector/command_help.rb +6 -1
- data/lib/hecks/projector/cli_projector/command_specs.rb +20 -6
- data/lib/hecks/projector/cli_projector/completion.rb +87 -0
- data/lib/hecks/projector/cli_projector/everyday.rb +40 -0
- data/lib/hecks/projector/cli_projector/json_listing.rb +77 -0
- data/lib/hecks/projector/cli_projector/listing.rb +20 -8
- data/lib/hecks/projector/cli_projector/modules.rb +39 -0
- data/lib/hecks/projector/cli_projector/option_specs.rb +1 -1
- data/lib/hecks/projector/cli_projector/query_specs.rb +2 -1
- data/lib/hecks/projector/cli_projector/renames.rb +58 -0
- data/lib/hecks/projector/cli_projector/search.rb +74 -0
- data/lib/hecks/projector/cli_projector/usage.rb +33 -12
- data/lib/hecks/projector/cli_projector.rb +26 -3
- data/lib/hecks/projector/docs_projector/behaviour.rb +5 -4
- data/lib/hecks/projector/docs_projector/closing.rb +3 -3
- data/lib/hecks/projector/docs_projector.rb +12 -7
- data/lib/hecks/projector/exporter/adapters.rb +15 -2
- data/lib/hecks/projector/exporter/bindings.rb +39 -134
- data/lib/hecks/projector/exporter/plugins.rb +55 -0
- data/lib/hecks/projector/exporter.rb +2 -0
- data/lib/hecks/projector/narrate_projector/commands.rb +4 -3
- data/lib/hecks/projector/narrate_projector/reactions.rb +2 -2
- data/lib/hecks/projector/narrate_projector.rb +9 -8
- data/lib/hecks/projector/target.rb +8 -8
- data/lib/hecks/projector.rb +9 -9
- data/lib/hecks/quality_control/adapters/agent.rb +2 -1
- data/lib/hecks/quality_control/adapters/ci_head.adapter +8 -0
- data/lib/hecks/quality_control/adapters/github_checks.adapter +1 -1
- data/lib/hecks/quality_control/adapters/github_issues.adapter +1 -1
- data/lib/hecks/quality_control/adapters/github_issues.rb +6 -2
- data/lib/hecks/quality_control/adapters/image_roll.adapter +9 -0
- data/lib/hecks/quality_control/adapters/image_roll.rb +158 -0
- data/lib/hecks/quality_control/adapters/main_maintenance.adapter +8 -0
- data/lib/hecks/quality_control/adapters/main_maintenance.rb +275 -0
- data/lib/hecks/quality_control/adapters/pump_tools.adapter +7 -0
- data/lib/hecks/quality_control/adapters/pump_tools.rb +18 -0
- data/lib/hecks/quality_control/adapters/push_due_reader.adapter +8 -0
- data/lib/hecks/quality_control/adapters/push_due_reader.rb +99 -0
- data/lib/hecks/quality_control/adapters/qa_auto_mint.rb +183 -0
- data/lib/hecks/quality_control/adapters/qa_era_mint.rb +94 -0
- data/lib/hecks/quality_control/adapters/qa_quiesce_marker.rb +126 -0
- data/lib/hecks/quality_control/adapters/run_keys.rb +36 -0
- data/lib/hecks/quality_control/adapters/run_reader.adapter +7 -0
- data/lib/hecks/quality_control/adapters/run_reader.rb +188 -0
- data/lib/hecks/quality_control/adapters/target_tools.rb +9 -3
- data/lib/hecks/quality_control/cli/child.rb +2 -0
- data/lib/hecks/quality_control/cli/qa_discover_external_domains/scanning.rb +1 -1
- data/lib/hecks/quality_control/cli/qa_domain_novelty/verdict.rb +1 -1
- data/lib/hecks/quality_control/cli/qa_domain_novelty.rb +3 -3
- data/lib/hecks/quality_control/cli/qa_event_pump/attached.rb +67 -0
- data/lib/hecks/quality_control/cli/qa_event_pump/consumer.rb +103 -0
- data/lib/hecks/quality_control/cli/qa_event_pump/cursors.rb +60 -0
- data/lib/hecks/quality_control/cli/qa_event_pump/reactions.rb +46 -0
- data/lib/hecks/quality_control/cli/qa_event_pump/reader.rb +30 -0
- data/lib/hecks/quality_control/cli/qa_event_pump.rb +76 -0
- data/lib/hecks/quality_control/cli/qa_fix_main_bug/publishing.rb +79 -0
- data/lib/hecks/quality_control/cli/qa_fix_main_bug.rb +167 -0
- data/lib/hecks/quality_control/cli/qa_generated_domains/evaluation.rb +13 -3
- data/lib/hecks/quality_control/cli/qa_generated_domains/promotion.rb +7 -4
- data/lib/hecks/quality_control/cli/qa_generated_domains.rb +4 -1
- data/lib/hecks/quality_control/cli/qa_log_bug/proof.rb +16 -3
- data/lib/hecks/quality_control/cli/qa_main_gate/gate_run.rb +52 -0
- data/lib/hecks/quality_control/cli/qa_main_gate/logging.rb +70 -0
- data/lib/hecks/quality_control/cli/qa_main_gate/shell.rb +47 -0
- data/lib/hecks/quality_control/cli/qa_main_gate/sweeping.rb +59 -0
- data/lib/hecks/quality_control/cli/qa_main_gate/worktree.rb +62 -0
- data/lib/hecks/quality_control/cli/qa_main_gate.rb +135 -0
- data/lib/hecks/quality_control/cli/qa_mine_combinations/booting.rb +4 -2
- data/lib/hecks/quality_control/cli/qa_mutate.rb +161 -0
- data/lib/hecks/quality_control/cli/qa_postgres_role.rb +1 -1
- data/lib/hecks/quality_control/cli/qa_pr_check/checking.rb +2 -3
- data/lib/hecks/quality_control/cli/qa_push_nudge.rb +48 -0
- data/lib/hecks/quality_control/cli/qa_seed_angles/seed.rb +1 -1
- data/lib/hecks/quality_control/cli/qa_sweep/all_mode/report.rb +4 -1
- data/lib/hecks/quality_control/cli/qa_sweep/parsing.rb +2 -1
- data/lib/hecks/quality_control/cli/qa_sweep/seat.rb +1 -1
- data/lib/hecks/quality_control/cli/qa_sweep.rb +4 -1
- data/lib/hecks/quality_control/cli/qa_tick/event_pump_step.rb +34 -0
- data/lib/hecks/quality_control/cli/qa_tick/output.rb +43 -26
- data/lib/hecks/quality_control/cli/qa_tick/preflight.rb +12 -3
- data/lib/hecks/quality_control/cli/qa_tick/push_nudge_step.rb +28 -0
- data/lib/hecks/quality_control/cli/qa_tick/quiesce_guard.rb +51 -0
- data/lib/hecks/quality_control/cli/qa_tick.rb +52 -8
- data/lib/hecks/quality_control/quality_control.behaviors +65 -0
- data/lib/hecks/quality_control/quality_control.bluebook +1224 -103
- data/lib/hecks/quality_control/quality_control.hecksagon +14 -3
- data/lib/hecks/quality_control/quality_control.ports.hecksagon +141 -2
- data/lib/hecks/query_ir/rules.rb +9 -9
- data/lib/hecks/query_ir/touchpoints.rb +10 -9
- data/lib/hecks/query_ir.rb +3 -3
- data/lib/hecks/query_specification/common/comparison.rb +1 -1
- data/lib/hecks/query_specification/common/dsl.rb +3 -4
- data/lib/hecks/query_specification/hop_path.rb +7 -4
- data/lib/hecks/rails_app/bluebook/rails_app.bluebook +60 -0
- data/lib/hecks/rails_app/bluebook/rails_app.hecksagon +4 -0
- data/lib/hecks/refused.rb +125 -0
- data/lib/hecks/release/approval.rb +15 -5
- data/lib/hecks/release/conditions.rb +46 -0
- data/lib/hecks/release/gem_pin.rb +7 -3
- data/lib/hecks/release/lane.rb +1 -1
- data/lib/hecks/release/runner/clean_tree.rb +4 -1
- data/lib/hecks/release/runner/console.rb +2 -1
- data/lib/hecks/release/runner/gem_publisher.rb +4 -4
- data/lib/hecks/release/version_commit.rb +48 -0
- data/lib/hecks/router/aggregate_reader.rb +3 -4
- data/lib/hecks/router/namespace_installer.rb +31 -17
- data/lib/hecks/router.rb +2 -10
- data/lib/hecks/runtime/adapter_lookup.rb +30 -7
- data/lib/hecks/runtime/adapter_namespace.rb +21 -0
- data/lib/hecks/runtime/asking.rb +30 -0
- data/lib/hecks/runtime/caller.rb +22 -0
- data/lib/hecks/runtime/capability_graph.rb +2 -1
- data/lib/hecks/runtime/collecting.rb +86 -0
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +13 -8
- data/lib/hecks/runtime/command_interpreter/delegation.rb +46 -17
- data/lib/hecks/runtime/command_interpreter/hydration.rb +22 -25
- data/lib/hecks/runtime/command_interpreter/list_mutations.rb +2 -1
- data/lib/hecks/runtime/command_interpreter/persisting.rb +23 -14
- data/lib/hecks/runtime/command_interpreter.rb +19 -12
- data/lib/hecks/runtime/command_rules/admissibility.rb +17 -12
- data/lib/hecks/runtime/command_rules/authorization.rb +8 -6
- data/lib/hecks/runtime/command_rules/emission.rb +0 -1
- data/lib/hecks/runtime/command_rules/guard_state.rb +10 -10
- data/lib/hecks/runtime/command_rules/invariants.rb +3 -1
- data/lib/hecks/runtime/command_rules/missing_reference.rb +25 -0
- data/lib/hecks/runtime/command_rules/one_of_references.rb +44 -0
- data/lib/hecks/runtime/command_rules/references.rb +14 -14
- data/lib/hecks/runtime/command_rules.rb +2 -0
- data/lib/hecks/runtime/declarations.rb +66 -0
- data/lib/hecks/runtime/dependency_planning/analyzer.rb +2 -1
- data/lib/hecks/runtime/dependency_planning/expression_reads.rb +3 -3
- data/lib/hecks/runtime/dependency_planning/mutation_analysis.rb +2 -1
- data/lib/hecks/runtime/dispatch_claim.rb +72 -0
- data/lib/hecks/runtime/dispatch_context.rb +41 -0
- data/lib/hecks/runtime/dispatcher/planning.rb +24 -0
- data/lib/hecks/runtime/dispatcher/queries.rb +17 -0
- data/lib/hecks/runtime/dispatcher/routing.rb +40 -12
- data/lib/hecks/runtime/dispatcher/validating.rb +73 -0
- data/lib/hecks/runtime/dispatcher/value_routing.rb +54 -0
- data/lib/hecks/runtime/dispatcher.rb +46 -24
- data/lib/hecks/runtime/dry_run_plan.rb +60 -0
- data/lib/hecks/runtime/entity_element/location.rb +15 -8
- data/lib/hecks/runtime/entity_element/mutations.rb +4 -2
- data/lib/hecks/runtime/entity_interpreter/enforcement.rb +1 -1
- data/lib/hecks/runtime/entity_interpreter/locating.rb +6 -1
- data/lib/hecks/runtime/entity_interpreter/saving.rb +5 -5
- data/lib/hecks/runtime/entity_interpreter.rb +11 -5
- data/lib/hecks/runtime/errors.rb +56 -17
- data/lib/hecks/runtime/identity.rb +9 -0
- data/lib/hecks/runtime/instance.rb +3 -3
- data/lib/hecks/runtime/interpreting.rb +63 -6
- data/lib/hecks/runtime/invocation_builder.rb +7 -5
- data/lib/hecks/runtime/invocation_facts.rb +13 -8
- data/lib/hecks/runtime/loader/boot_steps.rb +3 -2
- data/lib/hecks/runtime/loader/described.rb +4 -0
- data/lib/hecks/runtime/loader.rb +52 -62
- data/lib/hecks/runtime/outbox/consumer_runner.rb +9 -1
- data/lib/hecks/runtime/outbox/redrive.rb +105 -0
- data/lib/hecks/runtime/outbox/relay.rb +36 -43
- data/lib/hecks/runtime/outbox/runnable.rb +62 -0
- data/lib/hecks/runtime/outbox.rb +21 -3
- data/lib/hecks/runtime/policy_interpreter/arguments.rb +7 -1
- data/lib/hecks/runtime/policy_interpreter/fan_out.rb +26 -37
- data/lib/hecks/runtime/policy_interpreter.rb +25 -9
- data/lib/hecks/runtime/port_operation_interpreter.rb +47 -19
- data/lib/hecks/runtime/query_interpreter/arguments.rb +6 -5
- data/lib/hecks/runtime/query_interpreter/outside_answer.rb +1 -1
- data/lib/hecks/runtime/query_interpreter/paging.rb +42 -0
- data/lib/hecks/runtime/query_interpreter/plugin_answer.rb +54 -0
- data/lib/hecks/runtime/query_interpreter/store_specification.rb +32 -0
- data/lib/hecks/runtime/query_interpreter.rb +16 -9
- data/lib/hecks/runtime/reaction_invocation/target_resolution.rb +10 -4
- data/lib/hecks/runtime/reaction_invocation.rb +5 -3
- data/lib/hecks/runtime/read_model_interpreter/head_ordering.rb +1 -1
- data/lib/hecks/runtime/read_model_interpreter/reductions.rb +23 -15
- data/lib/hecks/runtime/read_model_interpreter/shaping.rb +18 -7
- data/lib/hecks/runtime/read_model_interpreter.rb +5 -2
- data/lib/hecks/runtime/reference_hop.rb +3 -2
- data/lib/hecks/runtime/refusal_wording.rb +27 -7
- data/lib/hecks/runtime/registry/adapter_capabilities.rb +43 -0
- data/lib/hecks/runtime/registry/ask_verification.rb +15 -4
- data/lib/hecks/runtime/registry/{chapter_verification.rb → bluebook_verification.rb} +23 -23
- data/lib/hecks/runtime/registry/context_maps.rb +26 -0
- data/lib/hecks/runtime/registry/declarations.rb +38 -6
- data/lib/hecks/runtime/registry/durability_warnings.rb +18 -2
- data/lib/hecks/runtime/registry/hecksagon_rules.rb +42 -25
- data/lib/hecks/runtime/registry/plugin_query_verification.rb +45 -0
- data/lib/hecks/runtime/registry/providers.rb +34 -99
- data/lib/hecks/runtime/registry/query_verification.rb +30 -21
- data/lib/hecks/runtime/registry/runtime_state.rb +14 -3
- data/lib/hecks/runtime/registry/saga_persistence.rb +7 -16
- data/lib/hecks/runtime/registry/verification.rb +9 -5
- data/lib/hecks/runtime/registry/world_defaults.rb +31 -6
- data/lib/hecks/runtime/registry/world_names.rb +99 -0
- data/lib/hecks/runtime/registry.rb +84 -53
- data/lib/hecks/runtime/row_sweep.rb +104 -0
- data/lib/hecks/runtime/saga_interpreter/compensation.rb +15 -4
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +29 -3
- data/lib/hecks/runtime/saga_interpreter/delivery.rb +13 -11
- data/lib/hecks/runtime/saga_interpreter/lifecycle.rb +1 -1
- data/lib/hecks/runtime/saga_interpreter/redrive.rb +141 -0
- data/lib/hecks/runtime/saga_interpreter/transitions.rb +35 -6
- data/lib/hecks/runtime/saga_interpreter.rb +82 -6
- data/lib/hecks/runtime/saga_pending_dispatch.rb +4 -2
- data/lib/hecks/runtime/scalar_field.rb +73 -0
- data/lib/hecks/runtime/tenant_scope.rb +2 -1
- data/lib/hecks/runtime/validation.rb +24 -0
- data/lib/hecks/runtime/value/admission.rb +11 -11
- data/lib/hecks/runtime/value/coercion.rb +43 -15
- data/lib/hecks/runtime/value/field_checks.rb +13 -13
- data/lib/hecks/runtime/value/invariant_violation.rb +4 -1
- data/lib/hecks/runtime/value/references.rb +7 -4
- data/lib/hecks/runtime/value/validation.rb +7 -4
- data/lib/hecks/runtime/wasm_plugin.rb +98 -0
- data/lib/hecks/runtime.rb +14 -14
- data/lib/hecks/rust_build/command_schemas.rb +27 -0
- data/lib/hecks/rust_build/conformance/surface.rb +50 -7
- data/lib/hecks/rust_build/conformance.rb +41 -8
- data/lib/hecks/rust_build/conformance_fuzz.rb +2 -2
- data/lib/hecks/rust_build/domain_name.rb +4 -1
- data/lib/hecks/rust_build/host.rb +15 -9
- data/lib/hecks/rust_build/native_build.rb +2 -1
- data/lib/hecks/rust_build/parser.rb +25 -0
- data/lib/hecks/rust_build/prebuilt_binary.rb +25 -5
- data/lib/hecks/rust_build/project_rust/codegen_run.rb +51 -17
- data/lib/hecks/rust_build/project_rust/declared.rb +80 -0
- data/lib/hecks/rust_build/project_rust/domain_loader.rb +15 -2
- data/lib/hecks/rust_build/project_rust/features_header.rb +22 -0
- data/lib/hecks/rust_build/project_rust/manifest.rb +96 -0
- data/lib/hecks/rust_build/project_rust/meta.rb +36 -0
- data/lib/hecks/rust_build/project_rust/root_mod/notes.rb +1 -1
- data/lib/hecks/rust_build/project_rust/target_ir.rb +12 -3
- data/lib/hecks/rust_build/project_rust.rb +31 -73
- data/lib/hecks/rust_build/target_dir.rb +40 -0
- data/lib/hecks/rust_build/wasm.rb +46 -17
- data/lib/hecks/rust_build/wasm_browser.rb +8 -2
- data/lib/hecks/rust_build/write_if_changed.rb +19 -4
- data/lib/hecks/rust_build.rb +31 -3
- data/lib/hecks/rust_format.rb +32 -2
- data/lib/hecks/secrets.rb +111 -0
- data/lib/hecks/sentence_form.rb +212 -0
- data/lib/hecks/served_options.rb +2 -1
- data/lib/hecks/shape_ledger/edge_hygiene.rb +170 -0
- data/lib/hecks/shape_ledger/scope.rb +51 -0
- data/lib/hecks/shape_ledger/status.rb +89 -0
- data/lib/hecks/shape_ledger.rb +194 -0
- data/lib/hecks/site/bluebook/site.bluebook +40 -62
- data/lib/hecks/site/bluebook/site.ports.hecksagon +1 -1
- data/lib/hecks/sme/bluebook/sme.bluebook +7 -1
- data/lib/hecks/storehouse/audit.rb +38 -5
- data/lib/hecks/storehouse/bluebook_words.rb +35 -0
- data/lib/hecks/storehouse/callers.rb +8 -0
- data/lib/hecks/storehouse/dispatching.rb +20 -6
- data/lib/hecks/storehouse/identity.rb +41 -0
- data/lib/hecks/storehouse/introspection.rb +4 -4
- data/lib/hecks/storehouse/querying.rb +9 -9
- data/lib/hecks/storehouse.rb +38 -10
- data/lib/hecks/switches.rb +21 -0
- data/lib/hecks/tenancy/bluebook/tenancy.bluebook +5 -9
- data/lib/hecks/text.rb +57 -0
- data/lib/hecks/tickets/bluebook/adapters/work_areas.adapter +7 -0
- data/lib/hecks/tickets/bluebook/adapters/work_limits.adapter +7 -0
- data/lib/hecks/tickets/bluebook/tickets.behaviors +70 -0
- data/lib/hecks/tickets/bluebook/tickets.bluebook +350 -76
- data/lib/hecks/tickets/bluebook/tickets.hecksagon +8 -1
- data/lib/hecks/tickets/bluebook/tickets.ports.hecksagon +18 -1
- data/lib/hecks/tools/argument_gate_matrix/dispatching.rb +1 -1
- data/lib/hecks/tools/argument_gate_matrix/rows.rb +7 -7
- data/lib/hecks/tools/argument_gate_matrix/violations.rb +1 -1
- data/lib/hecks/tools/argument_gate_matrix.rb +3 -3
- data/lib/hecks/{cli → tools}/behaviors.rb +1 -1
- data/lib/hecks/{cli → tools}/canonicalise.rb +1 -1
- data/lib/hecks/{cli → tools}/check_engine_agreement.rb +1 -1
- data/lib/hecks/{cli → tools}/check_era.rb +7 -7
- data/lib/hecks/tools/ci_gate_decision.rb +5 -2
- data/lib/hecks/tools/ci_gates.rb +9 -3
- data/lib/hecks/tools/ci_workflows.rb +98 -0
- data/lib/hecks/tools/comment_style/caps_words.rb +11 -8
- data/lib/hecks/tools/comment_style/dictionary.rb +7 -2
- data/lib/hecks/tools/comment_style/fixing.rb +10 -5
- data/lib/hecks/tools/comment_style/long_blocks.rb +1 -1
- data/lib/hecks/tools/comment_style/masking.rb +5 -5
- data/lib/hecks/tools/comment_style/run.rb +4 -1
- data/lib/hecks/tools/comment_style/source_file.rb +10 -3
- data/lib/hecks/tools/comment_style/structure_checks.rb +13 -4
- data/lib/hecks/tools/comment_style/text_checks.rb +1 -1
- data/lib/hecks/tools/comment_style.rb +25 -2
- data/lib/hecks/{cli → tools}/console.rb +12 -7
- data/lib/hecks/tools/deploy_recipe/generation.rb +1 -1
- data/lib/hecks/tools/deploy_recipe/targets.rb +1 -1
- data/lib/hecks/tools/deploy_recipe/worlds.rb +15 -9
- data/lib/hecks/tools/deploy_recipe.rb +17 -10
- data/lib/hecks/tools/deploy_recipe_lint/fixtures.rb +1 -1
- data/lib/hecks/tools/deploy_recipe_lint/makefile.rb +7 -1
- data/lib/hecks/{cli → tools}/deploy_template_diff.rb +1 -1
- data/lib/hecks/{cli → tools}/doc_coverage.rb +2 -2
- data/lib/hecks/{cli → tools}/document.rb +15 -10
- data/lib/hecks/{cli → tools}/domain_stub.rb +1 -1
- data/lib/hecks/{cli → tools}/domain_writer.rb +5 -2
- data/lib/hecks/tools/downstream_model_check.rb +122 -0
- data/lib/hecks/tools/drop_implicit_append_fields.rb +4 -1
- data/lib/hecks/tools/era_projection_backfill.rb +11 -6
- data/lib/hecks/tools/era_reattest.rb +11 -6
- data/lib/hecks/tools/evolve_run.rb +2 -2
- data/lib/hecks/tools/expected_era.rb +139 -0
- data/lib/hecks/{cli → tools}/expression_projection.rb +3 -3
- data/lib/hecks/{cli → tools}/follow.rb +4 -4
- data/lib/hecks/tools/fuzz_sweep/findings.rb +18 -2
- data/lib/hecks/tools/fuzz_sweep/options.rb +45 -6
- data/lib/hecks/tools/fuzz_sweep/pool.rb +12 -1
- data/lib/hecks/tools/fuzz_sweep/shards.rb +155 -0
- data/lib/hecks/tools/fuzz_sweep.rb +28 -10
- data/lib/hecks/tools/gate.rb +65 -34
- data/lib/hecks/tools/gate_memo/local_files.rb +33 -0
- data/lib/hecks/tools/gate_memo/rehearsal.rb +54 -0
- data/lib/hecks/tools/gate_memo/ruby_files.rb +152 -0
- data/lib/hecks/tools/gate_memo/session.rb +114 -0
- data/lib/hecks/tools/gate_memo/standalone.rb +67 -0
- data/lib/hecks/tools/gate_memo.rb +196 -0
- data/lib/hecks/tools/gate_report.rb +56 -0
- data/lib/hecks/{cli → tools}/history.rb +5 -2
- data/lib/hecks/tools/hoist_local_givens/rewriting.rb +3 -2
- data/lib/hecks/tools/hoist_local_givens.rb +2 -4
- data/lib/hecks/{cli → tools}/interview_agent.rb +1 -1
- data/lib/hecks/{cli → tools}/interview_aggregate.rb +1 -1
- data/lib/hecks/{cli → tools}/interview_draft.rb +9 -2
- data/lib/hecks/{cli → tools}/interview_record.rb +8 -4
- data/lib/hecks/{cli → tools}/interview_run.rb +9 -7
- data/lib/hecks/{cli → tools}/interview_session/agent_state.rb +1 -1
- data/lib/hecks/{cli → tools}/interview_session/catalog.rb +1 -1
- data/lib/hecks/{cli → tools}/interview_session/manual_findings.rb +1 -1
- data/lib/hecks/{cli → tools}/interview_session/proposals.rb +6 -3
- data/lib/hecks/{cli → tools}/interview_session.rb +5 -4
- data/lib/hecks/tools/interview_shape/lifecycle.rb +92 -0
- data/lib/hecks/{cli → tools}/interview_shape.rb +20 -74
- data/lib/hecks/{cli → tools}/ir.rb +1 -1
- data/lib/hecks/tools/lanes/files.rb +1 -1
- data/lib/hecks/tools/lanes/prebuilt_workflow.rb +1 -1
- data/lib/hecks/tools/lanes/rows.rb +9 -3
- data/lib/hecks/tools/lanes/ruleset.rb +1 -1
- data/lib/hecks/tools/lanes/watch_workflow.rb +7 -9
- data/lib/hecks/tools/lanes/workflow.rb +2 -2
- data/lib/hecks/tools/lanes.rb +2 -2
- data/lib/hecks/{cli → tools}/mcp.rb +1 -1
- data/lib/hecks/tools/model_check/examination.rb +142 -0
- data/lib/hecks/{cli → tools}/model_check/sources.rb +5 -3
- data/lib/hecks/{cli → tools}/model_check.rb +2 -2
- data/lib/hecks/tools/move_disables/reasons.rb +35 -0
- data/lib/hecks/tools/move_disables.rb +211 -0
- data/lib/hecks/tools/move_former_name.rb +105 -0
- data/lib/hecks/tools/oidc_manifests.rb +16 -19
- data/lib/hecks/{cli → tools}/pattern_cases.rb +1 -1
- data/lib/hecks/tools/persistence_notice.rb +45 -0
- data/lib/hecks/{cli → tools}/present.rb +2 -2
- data/lib/hecks/{cli → tools}/project_cli/launcher_source.rb +39 -27
- data/lib/hecks/{cli → tools}/project_cli/templates.rb +42 -14
- data/lib/hecks/{cli → tools}/project_cli.rb +22 -20
- data/lib/hecks/tools/project_diagrams.rb +59 -0
- data/lib/hecks/{cli → tools}/project_glossary.rb +16 -16
- data/lib/hecks/{cli → tools}/reference.rb +3 -3
- data/lib/hecks/{cli → tools}/refresh_projections.rb +17 -12
- data/lib/hecks/{cli → tools}/refresh_rspec_runtime_baseline.rb +1 -1
- data/lib/hecks/tools/regeneration_run/pool.rb +148 -0
- data/lib/hecks/tools/regeneration_run/scratch.rb +76 -0
- data/lib/hecks/tools/regeneration_run.rb +134 -107
- data/lib/hecks/{cli → tools}/release.rb +1 -1
- data/lib/hecks/{cli → tools}/release_gem.rb +1 -1
- data/lib/hecks/tools/release_only.rb +5 -2
- data/lib/hecks/{cli → tools}/rspec_io_parallel_files.rb +1 -1
- data/lib/hecks/{cli → tools}/rspec_shard_files.rb +1 -1
- data/lib/hecks/{cli → tools}/run.rb +36 -7
- data/lib/hecks/{cli → tools}/run_expectations.rb +1 -1
- data/lib/hecks/tools/rust_comment_style/caps_words.rb +5 -5
- data/lib/hecks/tools/rust_comment_style/fixing.rb +1 -1
- data/lib/hecks/tools/rust_comment_style/masking.rb +7 -4
- data/lib/hecks/tools/rust_comment_style/source_file.rb +7 -2
- data/lib/hecks/tools/rust_comment_style/text_checks.rb +1 -1
- data/lib/hecks/tools/rust_comment_style/tokenizer.rb +4 -1
- data/lib/hecks/{cli → tools}/seed_semantics_corpus.rb +18 -8
- data/lib/hecks/{cli → tools}/serve_query_ir_mcp.rb +1 -1
- data/lib/hecks/{cli → tools}/shape.rb +6 -6
- data/lib/hecks/tools/site_routes/editor_files.rb +16 -13
- data/lib/hecks/tools/site_routes/root_files.rb +14 -13
- data/lib/hecks/tools/site_routes/templates.rb +5 -4
- data/lib/hecks/tools/site_routes.rb +18 -15
- data/lib/hecks/{cli → tools}/smoke_http/checks.rb +1 -1
- data/lib/hecks/{cli → tools}/smoke_http/settings.rb +1 -1
- data/lib/hecks/{cli → tools}/smoke_http/transport.rb +4 -3
- data/lib/hecks/{cli → tools}/smoke_http.rb +1 -1
- data/lib/hecks/{cli → tools}/smoke_test.rb +1 -1
- data/lib/hecks/{cli → tools}/spec_example.rb +1 -1
- data/lib/hecks/tools/stage_progress.rb +54 -0
- data/lib/hecks/{cli → tools}/statements.rb +8 -8
- data/lib/hecks/tools/stores.rb +123 -0
- data/lib/hecks/{cli → tools}/stress_concurrency_specs/reporting.rb +5 -2
- data/lib/hecks/{cli → tools}/stress_concurrency_specs/usage.rb +4 -4
- data/lib/hecks/{cli → tools}/stress_concurrency_specs.rb +3 -3
- data/lib/hecks/tools/tail_merge.rb +3 -3
- data/lib/hecks/tools/tenant_provisioning.rb +29 -6
- data/lib/hecks/tools/tools_doc.rb +22 -20
- data/lib/hecks/tools/translation_audit/domain_loading.rb +3 -3
- data/lib/hecks/tools/translation_audit/edges.rb +21 -16
- data/lib/hecks/tools/translation_audit/verdicts.rb +1 -1
- data/lib/hecks/tools/translation_audit.rb +16 -5
- data/lib/hecks/tools/translation_scaffold/reporting.rb +4 -1
- data/lib/hecks/tools/translation_scaffold.rb +5 -15
- data/lib/hecks/tools.rb +4 -1
- data/lib/hecks/vendoring/git_source.rb +7 -4
- data/lib/hecks/version.rb +1 -1
- data/lib/hecks/vocabulary.rb +147 -10
- data/lib/hecks/workflow_pagination/judge.rb +48 -0
- data/lib/hecks/workflow_pagination/statement.rb +50 -0
- data/lib/hecks/workflow_pagination.rb +58 -0
- data/lib/hecks.rb +39 -18
- data/lib/rubocop/cop/hecks/bare_event_and_query_names.rb +58 -0
- data/lib/rubocop/cop/hecks/correlates_by_aggregate.rb +39 -0
- data/lib/rubocop/cop/hecks/creating_command_sets.rb +75 -0
- data/lib/rubocop/cop/hecks/inline_regexp.rb +29 -0
- data/lib/rubocop/cop/hecks/invariant_expression_language.rb +47 -0
- data/lib/rubocop/cop/hecks/lifecycle_needs_attribute.rb +58 -0
- data/lib/rubocop/cop/hecks/no_id_string_attribute.rb +49 -0
- data/lib/rubocop/cop/hecks/no_transport_in_runtime.rb +78 -0
- data/lib/rubocop/cop/hecks/one_terminal_mark_per_lifecycle.rb +47 -0
- data/lib/rubocop/cop/hecks/rails_model_rules.rb +46 -0
- data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +1 -1
- data/lib/rubocop/cop/hecks/train_wreck.rb +69 -0
- data/lib/rubocop/cop/hecks/unnamed_pipeline.rb +51 -0
- data/lib/rubocop/cop/hecks/value_object_shorthand.rb +56 -0
- data/prebuilt/13c04bdc5970295b310f0a980d397ba722232c8da99cc1a0cdb383249921e871.marshal +0 -0
- data/prebuilt/e3857b77f47d9ecc1787b2e1f5136364f3cb3444ef4aea5479f3b98167affea2.marshal +0 -0
- data/qa/settings.yml +32 -0
- data/rust/.gitignore +0 -6
- data/rust/Cargo.lock +8 -1
- data/rust/Cargo.toml +8 -8
- data/rust/build/Cargo.toml +1 -1
- data/rust/build/src/binding_pass.rs +68 -19
- data/rust/build/src/cargo_sync.rs +1 -1
- data/rust/build/src/lineage_pass.rs +4 -71
- data/rust/build/src/pipeline.rs +104 -73
- data/rust/build/src/resolve.rs +86 -29
- data/rust/build/src/seams_pass.rs +117 -99
- data/rust/build/src/world_pass.rs +21 -12
- data/rust/codegen/Cargo.toml +1 -1
- data/rust/codegen/src/domain_generator.rs +27 -2
- data/rust/codegen/src/expr_emitter.rs +6 -0
- data/rust/codegen/src/json_codec.rs +230 -33
- data/rust/codegen/src/main.rs +35 -34
- data/rust/codegen/src/manifest.rs +1 -1
- data/rust/codegen/src/naming.rs +5 -5
- data/rust/codegen/src/one_of_references.rs +125 -0
- data/rust/codegen/src/presenters.rs +3 -3
- data/rust/codegen/src/queries.rs +76 -9
- data/rust/codegen/src/reactions.rs +19 -14
- data/rust/codegen/src/read_models.rs +19 -14
- data/rust/codegen/src/registry.rs +110 -20
- data/rust/codegen/src/sidecars.rs +1 -1
- data/rust/expr/Cargo.lock +54 -0
- data/rust/expr/Cargo.toml +52 -0
- data/rust/{src/kernel → expr/src}/attribute_shapes/composite.rs +45 -14
- data/rust/{src/kernel → expr/src}/attribute_shapes/list.rs +1 -1
- data/rust/{src/kernel → expr/src}/attribute_shapes/mod.rs +2 -2
- data/rust/{src/kernel → expr/src}/attribute_shapes/optional.rs +1 -1
- data/rust/{src/kernel → expr/src}/attribute_shapes/scalar.rs +3 -3
- data/rust/{src/kernel → expr/src}/expr.rs +30 -8
- data/rust/{src/kernel → expr/src}/expression_operators/arithmetic.rs +41 -18
- data/rust/{src/kernel → expr/src}/expression_operators/comparison.rs +54 -8
- data/rust/{src/kernel → expr/src}/expression_operators/enumeration.rs +73 -6
- data/rust/{src/kernel → expr/src}/expression_operators/logical.rs +2 -2
- data/rust/expr/src/expression_operators/membership.rs +33 -0
- data/rust/{src/kernel → expr/src}/expression_operators/mod.rs +2 -2
- data/rust/expr/src/expression_operators/pattern_match.rs +179 -0
- data/rust/{src/kernel → expr/src}/expression_operators/positional.rs +8 -6
- data/rust/{src/kernel → expr/src}/expression_operators/presence.rs +7 -6
- data/rust/{src/kernel → expr/src}/expression_operators/sign_test.rs +14 -4
- data/rust/{src/kernel → expr/src}/expression_operators/sized.rs +16 -9
- data/rust/{src/kernel → expr/src}/expression_operators/text.rs +30 -17
- data/rust/{src/kernel → expr/src}/expression_operators/to_string.rs +8 -6
- data/rust/expr/src/lib.rs +17 -0
- data/rust/expr/src/refusal.rs +62 -0
- data/rust/expr/src/rendering.rs +135 -0
- data/rust/{src/kernel → expr/src}/ruby_float.rs +7 -6
- data/rust/host/Cargo.lock +137 -123
- data/rust/host/Cargo.toml +8 -4
- data/rust/host/HECKS_RELEASE +1 -1
- data/rust/host/core/Cargo.toml +64 -0
- data/rust/host/core/clippy.toml +4 -0
- data/rust/host/core/src/arg_limits.rs +48 -0
- data/rust/host/core/src/clock.rs +146 -0
- data/rust/host/core/src/dispatch.rs +920 -0
- data/rust/host/core/src/expr_json.rs +1137 -0
- data/rust/host/{src → core/src}/host.rs +13 -14
- data/rust/host/{src → core/src}/ir.rs +227 -18
- data/rust/host/core/src/journal.rs +126 -0
- data/rust/host/{src → core/src}/lambda_client.rs +27 -96
- data/rust/host/core/src/lib.rs +37 -0
- data/rust/host/{src → core/src}/needs.rs +66 -20
- data/rust/host/core/src/plugins.rs +269 -0
- data/rust/host/core/src/presentation.rs +471 -0
- data/rust/host/{src → core/src}/presentation_write.rs +75 -43
- data/rust/host/{src → core/src}/query_step.rs +54 -16
- data/rust/host/{src → core/src}/reference_validate.rs +6 -6
- data/rust/host/{src → core/src}/storage_shape.rs +2 -2
- data/rust/host/core/src/store/memory.rs +635 -0
- data/rust/host/core/src/store.rs +418 -0
- data/rust/host/{src → core/src}/ui_schema.rs +8 -8
- data/rust/host/core/src/validation.rs +129 -0
- data/rust/host/core/src/wasm_runner.rs +410 -0
- data/rust/host/fuzz/.gitignore +4 -0
- data/rust/host/fuzz/Cargo.lock +4479 -0
- data/rust/host/fuzz/Cargo.toml +42 -0
- data/rust/host/fuzz/README.md +55 -0
- data/rust/host/fuzz/fuzz_targets/postgres_equivalence.rs +24 -0
- data/rust/host/fuzz/src/backend.rs +273 -0
- data/rust/host/fuzz/src/equivalence.rs +195 -0
- data/rust/host/fuzz/src/footprint.rs +182 -0
- data/rust/host/fuzz/src/lib.rs +17 -0
- data/rust/host/fuzz/src/ops.rs +345 -0
- data/rust/host/fuzz/tests/smoke.rs +50 -0
- data/rust/host/src/api.rs +316 -105
- data/rust/host/src/auth/google_signin.rs +183 -0
- data/rust/host/src/auth.rs +527 -370
- data/rust/host/src/aws_lambda_invoker.rs +61 -0
- data/rust/host/src/bin/expr_harness.rs +9 -4
- data/rust/host/src/bin/ledger.rs +84 -0
- data/rust/host/src/bin/lineage_harness.rs +17 -21
- data/rust/host/src/bin/mint_harness.rs +12 -36
- data/rust/host/src/bin/validate_harness.rs +1 -6
- data/rust/host/src/boot.rs +466 -174
- data/rust/host/src/boundary_fuzz/ir.rs +10 -5
- data/rust/host/src/boundary_fuzz/server.rs +6 -5
- data/rust/host/src/checkout.rs +4 -1
- data/rust/host/src/commerce_ir.rs +126 -105
- data/rust/host/src/{dispatch.rs → dispatch_tests.rs} +367 -847
- data/rust/host/src/extension.rs +3 -4
- data/rust/host/src/hecksagon_boundary_tests.rs +149 -0
- data/rust/host/src/ledger.rs +683 -0
- data/rust/host/src/lib.rs +21 -28
- data/rust/host/src/payments/tests.rs +136 -38
- data/rust/host/src/payments.rs +36 -32
- data/rust/host/src/platform_signin/extension.rs +1 -1
- data/rust/host/src/platform_signin/mapping_tests.rs +12 -9
- data/rust/host/src/platform_signin/session.rs +7 -14
- data/rust/host/src/platform_signin/verify.rs +0 -2
- data/rust/host/src/presentation_tests.rs +382 -0
- data/rust/host/src/rate_limit.rs +18 -2
- data/rust/host/src/server.rs +222 -43
- data/rust/host/src/{journal.rs → store/journal_sql.rs} +21 -127
- data/rust/host/src/{mint.rs → store/mint.rs} +52 -18
- data/rust/host/src/store/postgres.rs +493 -0
- data/rust/host/src/store.rs +97 -0
- data/rust/host/src/store_conformance.rs +1265 -0
- data/rust/host/src/web/commerce.rs +10 -18
- data/rust/host/src/web/newsletter/cooldown.rs +107 -22
- data/rust/host/src/web/newsletter/naming.rs +104 -0
- data/rust/host/src/web/newsletter/tests.rs +53 -0
- data/rust/host/src/web/newsletter.rs +73 -50
- data/rust/host/src/web/newsletter_send.rs +12 -13
- data/rust/host/src/web/registration_receipt.rs +2 -2
- data/rust/host/src/web/registrations.rs +754 -375
- data/rust/host/src/web/resend_webhook.rs +3 -3
- data/rust/host/src/web/signin_tests.rs +131 -0
- data/rust/host/src/web.rs +1479 -149
- data/rust/lsp/Cargo.toml +1 -1
- data/rust/lsp/README.md +27 -27
- data/rust/lsp/src/diagnostics.rs +75 -15
- data/rust/lsp/src/main.rs +101 -5
- data/rust/parser/Cargo.toml +1 -1
- data/rust/parser/fuzz/Cargo.toml +2 -2
- data/rust/parser/fuzz/README.md +3 -3
- data/rust/parser/fuzz/fuzz_targets/{chapter.rs → bluebook.rs} +4 -4
- data/rust/parser/fuzz/fuzz_targets/resolve.rs +2 -2
- data/rust/parser/src/build/correlation_keys.rs +125 -0
- data/rust/parser/src/build/mod.rs +1 -0
- data/rust/parser/src/build/named_pattern.rs +22 -0
- data/rust/parser/src/build/references.rs +52 -0
- data/rust/parser/src/diag.rs +22 -1
- data/rust/parser/src/emit.rs +122 -6
- data/rust/parser/src/expr/ast_json.rs +10 -0
- data/rust/parser/src/expr/resolver.rs +49 -9
- data/rust/parser/src/ir.rs +66 -7
- data/rust/parser/src/keywords.rs +704 -419
- data/rust/parser/src/lex.rs +115 -87
- data/rust/parser/src/main.rs +182 -32
- data/rust/parser/src/parse/adapter.rs +28 -0
- data/rust/parser/src/parse/aggregate.rs +64 -35
- data/rust/parser/src/parse/audience.rs +65 -0
- data/rust/parser/src/parse/command.rs +114 -15
- data/rust/parser/src/parse/{chapter.rs → declaration.rs} +182 -54
- data/rust/parser/src/parse/domain_port.rs +66 -9
- data/rust/parser/src/parse/entity.rs +35 -32
- data/rust/parser/src/parse/file.rs +1 -1
- data/rust/parser/src/parse/hecksagon.rs +15 -5
- data/rust/parser/src/parse/mod.rs +85 -2
- data/rust/parser/src/parse/process_manager.rs +18 -11
- data/rust/parser/src/parse/query.rs +13 -3
- data/rust/parser/src/parse/read_model.rs +2 -1
- data/rust/parser/src/parse/world.rs +12 -8
- data/rust/parser/src/phrases.rs +1258 -0
- data/rust/parser/src/render_ruby.rs +549 -0
- data/rust/parser/src/sentence/changes.rs +437 -0
- data/rust/parser/src/sentence/command_step.rs +206 -0
- data/rust/parser/src/sentence/complete.rs +276 -0
- data/rust/parser/src/sentence/entity.rs +41 -0
- data/rust/parser/src/sentence/examples.rs +1012 -0
- data/rust/parser/src/sentence/format.rs +885 -0
- data/rust/parser/src/sentence/lower.rs +1366 -0
- data/rust/parser/src/sentence/mod.rs +444 -0
- data/rust/parser/src/sentence/names.rs +69 -0
- data/rust/parser/src/sentence/options.rs +154 -0
- data/rust/parser/src/sentence/pattern.rs +433 -0
- data/rust/parser/src/sentence/process.rs +200 -0
- data/rust/parser/src/sentence/queries.rs +431 -0
- data/rust/parser/src/sentence/report.rs +283 -0
- data/rust/parser/src/sentence/token.rs +106 -0
- data/rust/parser/src/sentence/values.rs +498 -0
- data/rust/src/exemplar/json.rs +17 -0
- data/rust/src/exemplar/queries.rs +1 -0
- data/rust/src/exemplar/reactions.rs +1 -1
- data/rust/src/exemplar/registry.rs +30 -0
- data/rust/src/kernel/cli.rs +239 -15
- data/rust/src/kernel/collecting.rs +174 -0
- data/rust/src/kernel/dispatch.rs +59 -29
- data/rust/src/kernel/json.rs +62 -0
- data/rust/src/kernel/mod.rs +7 -67
- data/rust/src/kernel/named_query.rs +225 -11
- data/rust/src/kernel/orchestrate.rs +241 -28
- data/rust/src/kernel/orchestrate_guard_tests.rs +15 -12
- data/rust/src/kernel/query_cursor.rs +251 -0
- data/rust/src/kernel/query_ordering.rs +6 -6
- data/rust/src/kernel/read_model.rs +162 -17
- data/rust/src/kernel/repository.rs +107 -17
- data/rust/src/kernel/vocab/mod.rs +4 -0
- data/rust/src/kernel/vocab/reducer.rs +109 -0
- data/rust/src/kernel/vocab/refusal_class.rs +124 -0
- data/rust/src/kernel/vocab/refusal_template.rs +2 -2
- data/rust/src/lib.rs +1 -1
- data/rust/web/Cargo.lock +47 -0
- data/rust/web/Cargo.toml +1 -1
- metadata +689 -161
- data/lib/hecks/chapters.rb +0 -147
- data/lib/hecks/cli/command_table.rb +0 -72
- data/lib/hecks/cli/launcher_words.rb +0 -168
- data/lib/hecks/cli/model_check/examination.rb +0 -93
- data/lib/hecks/cli/project_diagrams.rb +0 -59
- data/lib/hecks/cli/stores.rb +0 -55
- data/lib/hecks/cli.rb +0 -133
- data/lib/hecks/gate/stages.yml +0 -234
- data/lib/hecks/hecks/codebase.bluebook +0 -3241
- data/lib/hecks/hecks/custodian.bluebook +0 -904
- data/lib/hecks/hecks/governance.world +0 -7
- data/lib/hecks/hecks/rehearsal.bluebook +0 -471
- data/lib/hecks/hecks/tooling.bluebook +0 -1238
- data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +0 -137
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/boot.rb +0 -43
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/domain_rename.rb +0 -91
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +0 -67
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/context.rb +0 -38
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +0 -100
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +0 -102
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/refusals.rb +0 -51
- data/lib/hecks/ports/persistence/postgres_dump/connection.rb +0 -59
- data/lib/hecks/ports/persistence/postgres_dump.rb +0 -100
- data/lib/hecks/projections/deploy/box/templates/tunnel-egress.yaml.tmpl +0 -11
- data/lib/hecks/projector/exporter/capability_values.rb +0 -55
- data/lib/hecks/quality_control/adapters/clearance_recorder.rb +0 -36
- data/lib/hecks/quality_control/adapters/github_ci_webhook.rb +0 -56
- data/lib/hecks/runtime/remote_dispatcher.rb +0 -176
- data/prebuilt/ad68f9e06c8068c2a4176b57abf3083d591d5d8980c2b3e897b97331f965b643.marshal +0 -0
- data/prebuilt/ee22ec8642c4006717ba2b80f46e5efb81de459eef9dfec043e838c0ad4fd720.marshal +0 -0
- data/prebuilt/verdicts-b69f5dcbba79c20daa0493476fa7c317004a30aa2bc3d3dc6a722ea70ae2b43b.json +0 -1
- data/rust/host/src/clock.rs +0 -8
- data/rust/host/src/expr_json.rs +0 -1983
- data/rust/host/src/presentation.rs +0 -842
- data/rust/host/src/wasm_runner.rs +0 -206
- data/rust/src/kernel/expression_operators/membership.rs +0 -20
- data/rust/src/kernel/expression_operators/pattern_match.rs +0 -108
- /data/lib/hecks/{ports/persistence/plugins/era → adapters/driven}/postgres_era/events.rb +0 -0
- /data/lib/hecks/{ports/persistence/plugins/era → adapters/driven}/postgres_era/head_writes.rb +0 -0
- /data/lib/hecks/{ports/persistence/plugins/era → adapters/driven}/postgres_era/lineage/base_sql.rb +0 -0
- /data/lib/hecks/{ports/persistence/plugins/era → adapters/driven}/postgres_era/lineage/field_cache.rb +0 -0
- /data/lib/hecks/{ports/persistence/plugins/era → adapters/driven}/postgres_era/lineage/head_compiler.rb +0 -0
- /data/lib/hecks/{ports/persistence/plugins/era → adapters/driven}/postgres_era/lineage/merge_writes.rb +0 -0
- /data/lib/hecks/{ports/persistence/plugins/era → adapters/driven}/postgres_era/lineage/resumable_backfill.rb +0 -0
- /data/lib/hecks/{ports/persistence/plugins/era → adapters/driven}/postgres_era/lineage/transform_installer.rb +0 -0
- /data/lib/hecks/{ports/persistence/plugins/era → adapters/driven}/postgres_era/lineage/transform_sql.rb +0 -0
- /data/lib/hecks/{ports/persistence/plugins/era → adapters/driven}/postgres_era/sagas.rb +0 -0
- /data/rust/host/{src → core/src}/field_hints.rs +0 -0
- /data/rust/host/{src → core/src}/log.rs +0 -0
- /data/rust/host/{src → core/src}/reference_transform.rs +0 -0
|
@@ -1,745 +1,10 @@
|
|
|
1
|
-
//!
|
|
2
|
-
//!
|
|
3
|
-
|
|
4
|
-
use crate::host::Host;
|
|
5
|
-
use crate::journal;
|
|
6
|
-
use crate::lambda_client::{self};
|
|
7
|
-
use crate::wasm_runner;
|
|
8
|
-
use std::path::Path;
|
|
9
|
-
use tokio::sync::Mutex;
|
|
10
|
-
use tokio_postgres::Client;
|
|
11
|
-
|
|
12
|
-
pub struct Outcome {
|
|
13
|
-
pub result: serde_json::Value,
|
|
14
|
-
pub accepted: bool,
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/// Who a command is dispatched for: the role they state and, when the host knows who they are, the
|
|
18
|
-
/// actor Governance holds assignments for. Both absent is an unidentified caller.
|
|
19
|
-
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
|
20
|
-
pub struct Caller<'a> {
|
|
21
|
-
pub role: Option<&'a str>,
|
|
22
|
-
pub actor_id: Option<&'a str>,
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/// The role an unidentified caller is dispatched under when roles are enforced: no command declares
|
|
26
|
-
/// it, so a command that declares any role refuses it.
|
|
27
|
-
pub const ANONYMOUS_ROLE: &str = "Anonymous";
|
|
28
|
-
|
|
29
|
-
/// What the host does about the role a command declares (`HECKS_ROLE_ENFORCEMENT`).
|
|
30
|
-
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
31
|
-
pub enum Enforcement {
|
|
32
|
-
/// A caller with no role is unchecked, as before.
|
|
33
|
-
Off,
|
|
34
|
-
/// An unidentified or unassigned caller is let through and logged as `would_refuse_role`; a
|
|
35
|
-
/// caller that states a role is checked exactly as under `Enforce`, so shadow never accepts
|
|
36
|
-
/// what `Off` would not.
|
|
37
|
-
Shadow,
|
|
38
|
-
/// An unidentified or unassigned caller is refused.
|
|
39
|
-
Enforce,
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
impl Enforcement {
|
|
43
|
-
/// Reads `off` (the default), `shadow` or `enforce`; anything else is `Off`.
|
|
44
|
-
pub fn parse(value: Option<&str>) -> Self {
|
|
45
|
-
match value.map(|v| v.trim().to_ascii_lowercase()).as_deref() {
|
|
46
|
-
Some("shadow") => Self::Shadow,
|
|
47
|
-
Some("enforce") => Self::Enforce,
|
|
48
|
-
_ => Self::Off,
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
pub fn from_env() -> Self {
|
|
53
|
-
static MODE: std::sync::OnceLock<Enforcement> = std::sync::OnceLock::new();
|
|
54
|
-
*MODE.get_or_init(|| Self::parse(std::env::var("HECKS_ROLE_ENFORCEMENT").ok().as_deref()))
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/// The caller the kernel is asked to check: an unidentified caller becomes the anonymous role
|
|
58
|
-
/// unless enforcement is off.
|
|
59
|
-
pub fn effective(self, caller: Caller<'_>) -> Caller<'_> {
|
|
60
|
-
if self != Self::Off && caller.role.is_none() && caller.actor_id.is_none() {
|
|
61
|
-
return Caller {
|
|
62
|
-
role: Some(ANONYMOUS_ROLE),
|
|
63
|
-
actor_id: None,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
caller
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/// Where a dispatch comes from. A host-internal dispatch is the host acting on its own behalf (a
|
|
71
|
-
/// signup, a provisioning step, a presentation write); it names no caller and is never subject to
|
|
72
|
-
/// `HECKS_ROLE_ENFORCEMENT`, which guards what callers outside the host may do.
|
|
73
|
-
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
74
|
-
enum Origin {
|
|
75
|
-
External,
|
|
76
|
-
HostInternal,
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/// Whether the kernel refused the command for the caller's role.
|
|
80
|
-
fn refused_for_role(result: &serde_json::Value) -> bool {
|
|
81
|
-
result
|
|
82
|
-
.get("refusals")
|
|
83
|
-
.and_then(|r| r.as_array())
|
|
84
|
-
.is_some_and(|all| {
|
|
85
|
-
all.iter()
|
|
86
|
-
.any(|r| r.get("kind").and_then(|k| k.as_str()) == Some("Unauthorized"))
|
|
87
|
-
})
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Distinguishes a module refusal from a kernel failure to run at all.
|
|
91
|
-
#[derive(Debug, PartialEq)]
|
|
92
|
-
enum KernelAnswer {
|
|
93
|
-
Accepted,
|
|
94
|
-
Refused,
|
|
95
|
-
Failed(String),
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// A run that never started has no `refusals` array at all, so absence of
|
|
99
|
-
// refusals doesn't by itself mean the run succeeded.
|
|
100
|
-
fn classify(result: &serde_json::Value) -> KernelAnswer {
|
|
101
|
-
if let Some(error) = result.get("error") {
|
|
102
|
-
return KernelAnswer::Failed(
|
|
103
|
-
error
|
|
104
|
-
.as_str()
|
|
105
|
-
.map_or_else(|| error.to_string(), str::to_string),
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
let refused = result
|
|
109
|
-
.get("refusals")
|
|
110
|
-
.and_then(|r| r.as_array())
|
|
111
|
-
.is_some_and(|r| !r.is_empty());
|
|
112
|
-
if refused {
|
|
113
|
-
KernelAnswer::Refused
|
|
114
|
-
} else {
|
|
115
|
-
KernelAnswer::Accepted
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// A kernel failure becomes `Err`, not a result with no instances read as
|
|
120
|
-
// an empty world.
|
|
121
|
-
fn parse_kernel_output(output: &str) -> anyhow::Result<serde_json::Value> {
|
|
122
|
-
let result: serde_json::Value = serde_json::from_str(output)?;
|
|
123
|
-
match classify(&result) {
|
|
124
|
-
KernelAnswer::Failed(message) => {
|
|
125
|
-
anyhow::bail!("the kernel failed before it could run the command: {message}")
|
|
126
|
-
}
|
|
127
|
-
KernelAnswer::Accepted | KernelAnswer::Refused => Ok(result),
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Kept as one opaque object under the journal's `args` column; the kernel
|
|
132
|
-
// unwraps `to`/`with` itself, so this needs no journal schema migration.
|
|
133
|
-
pub fn routed_invocation(
|
|
134
|
-
to: serde_json::Value,
|
|
135
|
-
facts: serde_json::Value,
|
|
136
|
-
) -> anyhow::Result<serde_json::Value> {
|
|
137
|
-
if !facts.is_object() {
|
|
138
|
-
anyhow::bail!("with must be an object of command facts");
|
|
139
|
-
}
|
|
140
|
-
let mut invocation = serde_json::Map::new();
|
|
141
|
-
invocation.insert("to".to_string(), to);
|
|
142
|
-
invocation.insert("with".to_string(), facts);
|
|
143
|
-
Ok(serde_json::Value::Object(invocation))
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// No `to` route: used only when a command creates a new aggregate, so
|
|
147
|
-
// there is no receiver yet to route to.
|
|
148
|
-
pub fn facts_invocation(facts: serde_json::Value) -> anyhow::Result<serde_json::Value> {
|
|
149
|
-
if !facts.is_object() {
|
|
150
|
-
anyhow::bail!("with must be an object of command facts");
|
|
151
|
-
}
|
|
152
|
-
let mut invocation = serde_json::Map::new();
|
|
153
|
-
invocation.insert("with".to_string(), facts);
|
|
154
|
-
Ok(serde_json::Value::Object(invocation))
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// Route-aware entry point; `handle` below stays the compatibility path
|
|
158
|
-
// for callers still sending the older mixed args shape.
|
|
159
|
-
pub async fn handle_routed(
|
|
160
|
-
host: Host<'_>,
|
|
161
|
-
verb: &str,
|
|
162
|
-
to: serde_json::Value,
|
|
163
|
-
facts: serde_json::Value,
|
|
164
|
-
role: Option<&str>,
|
|
165
|
-
) -> anyhow::Result<Outcome> {
|
|
166
|
-
handle(host, verb, routed_invocation(to, facts)?, role).await
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/// `handle_routed` for a caller the host can name.
|
|
170
|
-
pub async fn handle_routed_as(
|
|
171
|
-
host: Host<'_>,
|
|
172
|
-
verb: &str,
|
|
173
|
-
to: serde_json::Value,
|
|
174
|
-
facts: serde_json::Value,
|
|
175
|
-
caller: Caller<'_>,
|
|
176
|
-
) -> anyhow::Result<Outcome> {
|
|
177
|
-
handle_as(host, verb, routed_invocation(to, facts)?, caller).await
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// Facts-only counterpart to `handle_routed`.
|
|
181
|
-
pub async fn handle_facts(
|
|
182
|
-
host: Host<'_>,
|
|
183
|
-
verb: &str,
|
|
184
|
-
facts: serde_json::Value,
|
|
185
|
-
role: Option<&str>,
|
|
186
|
-
) -> anyhow::Result<Outcome> {
|
|
187
|
-
handle(host, verb, facts_invocation(facts)?, role).await
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/// `handle_facts` for a caller the host can name.
|
|
191
|
-
pub async fn handle_facts_as(
|
|
192
|
-
host: Host<'_>,
|
|
193
|
-
verb: &str,
|
|
194
|
-
facts: serde_json::Value,
|
|
195
|
-
caller: Caller<'_>,
|
|
196
|
-
) -> anyhow::Result<Outcome> {
|
|
197
|
-
handle_as(host, verb, facts_invocation(facts)?, caller).await
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// A Mutex, not a bare Arc<Client>: `handle` needs `Client::transaction`,
|
|
201
|
-
// which takes `&mut Client`. Locking also means concurrent callers on
|
|
202
|
-
// this connection can't interleave statements.
|
|
203
|
-
//
|
|
204
|
-
// `config` is required, not optional: `main.rs` already refused to boot
|
|
205
|
-
// unless the configured domain/era is provisioned and current, so by the
|
|
206
|
-
// time `handle` runs that schema is guaranteed to exist.
|
|
207
|
-
//
|
|
208
|
-
// `role` is optional, matching `Adapters::Lambda::Client#dispatch`'s own
|
|
209
|
-
// `role: nil` default: a step with no role looks the same on the wire
|
|
210
|
-
// whether or not a caller is bound.
|
|
211
|
-
//
|
|
212
|
-
// This entry point and `handle_facts`/`handle_routed` are the host's own: a call with no role is a
|
|
213
|
-
// host-internal dispatch and is unchecked in every enforcement mode. A call that names a role is
|
|
214
|
-
// still checked against it. Callers outside the host go through the `_as` entry points.
|
|
215
|
-
pub async fn handle(
|
|
216
|
-
host: Host<'_>,
|
|
217
|
-
verb: &str,
|
|
218
|
-
args: serde_json::Value,
|
|
219
|
-
role: Option<&str>,
|
|
220
|
-
) -> anyhow::Result<Outcome> {
|
|
221
|
-
let origin = if role.is_none() {
|
|
222
|
-
Origin::HostInternal
|
|
223
|
-
} else {
|
|
224
|
-
Origin::External
|
|
225
|
-
};
|
|
226
|
-
dispatch_in(
|
|
227
|
-
Enforcement::from_env(),
|
|
228
|
-
origin,
|
|
229
|
-
host,
|
|
230
|
-
verb,
|
|
231
|
-
args,
|
|
232
|
-
Caller {
|
|
233
|
-
role,
|
|
234
|
-
actor_id: None,
|
|
235
|
-
},
|
|
236
|
-
)
|
|
237
|
-
.await
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/// Dispatches for a caller, applying `HECKS_ROLE_ENFORCEMENT`: unidentified callers are refused (or,
|
|
241
|
-
/// in shadow, logged as would-be refusals and let through).
|
|
242
|
-
pub async fn handle_as(
|
|
243
|
-
host: Host<'_>,
|
|
244
|
-
verb: &str,
|
|
245
|
-
args: serde_json::Value,
|
|
246
|
-
caller: Caller<'_>,
|
|
247
|
-
) -> anyhow::Result<Outcome> {
|
|
248
|
-
dispatch_in(
|
|
249
|
-
Enforcement::from_env(),
|
|
250
|
-
Origin::External,
|
|
251
|
-
host,
|
|
252
|
-
verb,
|
|
253
|
-
args,
|
|
254
|
-
caller,
|
|
255
|
-
)
|
|
256
|
-
.await
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
async fn dispatch_in(
|
|
260
|
-
mode: Enforcement,
|
|
261
|
-
origin: Origin,
|
|
262
|
-
host: Host<'_>,
|
|
263
|
-
verb: &str,
|
|
264
|
-
args: serde_json::Value,
|
|
265
|
-
caller: Caller<'_>,
|
|
266
|
-
) -> anyhow::Result<Outcome> {
|
|
267
|
-
let checked = if origin == Origin::HostInternal {
|
|
268
|
-
caller
|
|
269
|
-
} else {
|
|
270
|
-
mode.effective(caller)
|
|
271
|
-
};
|
|
272
|
-
let outcome = run(host, verb, args.clone(), checked).await?;
|
|
273
|
-
// Only a caller that stated no role (unidentified, or an actor Governance holds no grant for)
|
|
274
|
-
// is let through; a stated role that does not match stays refused, as it is under `Off`.
|
|
275
|
-
if mode == Enforcement::Shadow
|
|
276
|
-
&& caller.role.is_none()
|
|
277
|
-
&& !outcome.accepted
|
|
278
|
-
&& refused_for_role(&outcome.result)
|
|
279
|
-
{
|
|
280
|
-
crate::log::error(
|
|
281
|
-
"would_refuse_role",
|
|
282
|
-
serde_json::json!({
|
|
283
|
-
"verb": verb, "role": checked.role, "actor_id": checked.actor_id,
|
|
284
|
-
"refusals": outcome.result.get("refusals"),
|
|
285
|
-
}),
|
|
286
|
-
);
|
|
287
|
-
return run(host, verb, args, Caller::default()).await;
|
|
288
|
-
}
|
|
289
|
-
Ok(outcome)
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
async fn run(
|
|
293
|
-
host: Host<'_>,
|
|
294
|
-
verb: &str,
|
|
295
|
-
args: serde_json::Value,
|
|
296
|
-
caller: Caller<'_>,
|
|
297
|
-
) -> anyhow::Result<Outcome> {
|
|
298
|
-
let Host {
|
|
299
|
-
client,
|
|
300
|
-
wasm_path,
|
|
301
|
-
config,
|
|
302
|
-
invoker,
|
|
303
|
-
..
|
|
304
|
-
} = host;
|
|
305
|
-
let role = caller.role;
|
|
306
|
-
let mut guard = client.lock().await;
|
|
307
|
-
let txn = guard.transaction().await?;
|
|
308
|
-
|
|
309
|
-
// Locks the whole read-then-append sequence, not just the INSERT:
|
|
310
|
-
// two concurrent invocations could otherwise both rehydrate against
|
|
311
|
-
// the same prior steps and both pass a uniqueness check the domain
|
|
312
|
-
// thinks it's enforcing. Domain-scoped so unrelated domains sharing
|
|
313
|
-
// one Postgres instance don't serialize against each other.
|
|
314
|
-
txn.execute(
|
|
315
|
-
"SELECT pg_advisory_xact_lock(hashtext('hecks_lambda_journal.' || $1::text))",
|
|
316
|
-
&[&config.domain],
|
|
317
|
-
)
|
|
318
|
-
.await?;
|
|
319
|
-
|
|
320
|
-
// Reads the last snapshot plus only the journal rows after it,
|
|
321
|
-
// instead of replaying the whole history every time. `None` covers
|
|
322
|
-
// a brand-new domain and one with pre-snapshot history alike; both
|
|
323
|
-
// fall back to one full replay, which then leaves a snapshot behind.
|
|
324
|
-
let snapshot = journal::load_snapshot(&txn).await?;
|
|
325
|
-
// `sagas_backfilled` is a latch, not a live check of whether
|
|
326
|
-
// `hecks_lambda_sagas` is empty (empty is the ordinary state, not a
|
|
327
|
-
// signal). Only matters for a domain with real history predating
|
|
328
|
-
// saga durability, where the snapshot cache would otherwise never
|
|
329
|
-
// re-derive sagas from the journal.
|
|
330
|
-
let needs_saga_backfill = snapshot.as_ref().is_some_and(|s| !s.sagas_backfilled);
|
|
331
|
-
let mut steps = match &snapshot {
|
|
332
|
-
Some(s) if !needs_saga_backfill => journal::load_steps_after(&txn, s.ordinal).await?,
|
|
333
|
-
_ => journal::load_steps(&txn).await?,
|
|
334
|
-
};
|
|
335
|
-
// Role goes only on this outermost step; replayed history already
|
|
336
|
-
// carries whatever role it was dispatched with. Built as a mutable
|
|
337
|
-
// step, not inlined into the `json!` literal, so a roleless call
|
|
338
|
-
// still omits the `"role"` key entirely rather than sending null.
|
|
339
|
-
// A fact the command `needs` is answered here, before the kernel's gates read the arguments and
|
|
340
|
-
// before the step is journaled, so a replay re-dispatches the recorded answer (ADR 0081).
|
|
341
|
-
let mut args = args;
|
|
342
|
-
if let Some(domain_ir) = crate::ir::ir() {
|
|
343
|
-
crate::needs::fill_needs(domain_ir, verb, &mut args, &crate::needs::ProcessClock);
|
|
344
|
-
// An argument with a declared default is filled the same way, so the journal holds it too.
|
|
345
|
-
crate::needs::fill_defaults(domain_ir, verb, &mut args);
|
|
346
|
-
}
|
|
347
|
-
let mut step = serde_json::json!({ "verb": verb, "args": args.clone() });
|
|
348
|
-
if let Some(role) = role {
|
|
349
|
-
step["role"] = serde_json::Value::String(role.to_string());
|
|
350
|
-
}
|
|
351
|
-
if let Some(actor_id) = caller.actor_id {
|
|
352
|
-
step["actor_id"] = serde_json::Value::String(actor_id.to_string());
|
|
353
|
-
}
|
|
354
|
-
// Stamped only on this live step; replayed history already carries
|
|
355
|
-
// its own real timestamp, and re-stamping today's time onto a
|
|
356
|
-
// replay would be wrong, not just redundant.
|
|
357
|
-
step["occurred_at"] = serde_json::Value::String(crate::auth::httpdate_now());
|
|
358
|
-
steps.push(step);
|
|
359
|
-
// Must match `steps`' own choice above: a full replay needs an empty
|
|
360
|
-
// seed, or the kernel replays into a world that already has every
|
|
361
|
-
// record being created again, refusing each as a false AlreadyExists.
|
|
362
|
-
let seed = if needs_saga_backfill {
|
|
363
|
-
serde_json::json!({})
|
|
364
|
-
} else {
|
|
365
|
-
snapshot
|
|
366
|
-
.as_ref()
|
|
367
|
-
.map_or_else(|| serde_json::json!({}), |s| s.seed.clone())
|
|
368
|
-
};
|
|
369
|
-
|
|
370
|
-
// Read inside the same advisory-locked transaction: the lock covers
|
|
371
|
-
// saga state too, not just the aggregate journal/snapshot.
|
|
372
|
-
let saga_rows = journal::load_sagas(&txn).await?;
|
|
373
|
-
let sagas_seed = serde_json::json!(saga_rows
|
|
374
|
-
.iter()
|
|
375
|
-
.map(|r| serde_json::json!({
|
|
376
|
-
"process_manager": r.process_manager,
|
|
377
|
-
"correlation": r.correlation,
|
|
378
|
-
"state": r.state,
|
|
379
|
-
"memory": r.memory,
|
|
380
|
-
"completed_compensations": r.completed_compensations,
|
|
381
|
-
}))
|
|
382
|
-
.collect::<Vec<_>>());
|
|
383
|
-
|
|
384
|
-
let mut input = serde_json::json!({ "seed": seed, "steps": steps, "sagas": sagas_seed });
|
|
385
|
-
// Lets the kernel answer a reaction's command that needs a fact the same way (ADR 0081).
|
|
386
|
-
if let Some(domain_ir) = crate::ir::ir() {
|
|
387
|
-
let table = crate::needs::table(domain_ir);
|
|
388
|
-
if table.as_object().is_some_and(|t| !t.is_empty()) {
|
|
389
|
-
input["needs"] = table;
|
|
390
|
-
}
|
|
391
|
-
let defaults = crate::needs::defaults_table(domain_ir);
|
|
392
|
-
if defaults.as_object().is_some_and(|t| !t.is_empty()) {
|
|
393
|
-
input["defaults"] = defaults;
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
let input = input.to_string();
|
|
397
|
-
// `wasm_runner::run` is sync, and wasmtime-wasi's sync bridge spins up
|
|
398
|
-
// its own tokio runtime internally — fatal on a thread already
|
|
399
|
-
// driving one. `spawn_blocking` moves it off this async runtime.
|
|
400
|
-
let owned_wasm_path = wasm_path.to_path_buf();
|
|
401
|
-
let output =
|
|
402
|
-
tokio::task::spawn_blocking(move || wasm_runner::run(&owned_wasm_path, &input)).await??;
|
|
403
|
-
// A kernel failure returns here, before anything is written: dropping `txn`
|
|
404
|
-
// rolls it back, so no journal row, snapshot, saga or mutation is saved.
|
|
405
|
-
let mut result = parse_kernel_output(&output)?;
|
|
406
|
-
|
|
407
|
-
// See journal.rs's own header: every prior step in this replay
|
|
408
|
-
// already succeeded once, deterministically, so the only step that
|
|
409
|
-
// can legitimately show up in `refusals` is the new one just
|
|
410
|
-
// appended last.
|
|
411
|
-
let accepted = classify(&result) == KernelAnswer::Accepted;
|
|
412
|
-
|
|
413
|
-
if accepted {
|
|
414
|
-
let ordinal = journal::append(&txn, verb, &args).await?;
|
|
415
|
-
|
|
416
|
-
// The kernel's "instances" output is already the exact seed
|
|
417
|
-
// shape, so nothing here re-derives or filters it.
|
|
418
|
-
let new_seed = result
|
|
419
|
-
.get("instances")
|
|
420
|
-
.cloned()
|
|
421
|
-
.unwrap_or_else(|| serde_json::json!({}));
|
|
422
|
-
journal::save_snapshot(&txn, ordinal, &new_seed).await?;
|
|
423
|
-
|
|
424
|
-
// Persisted in the same transaction, so a saga checkpoint can
|
|
425
|
-
// never commit independently of the command that produced it.
|
|
426
|
-
// Reconciled against `saga_rows` (pre-run state): present now
|
|
427
|
-
// is upserted, present before but absent now is deleted.
|
|
428
|
-
if let Some(saga_snapshot) = result.get("saga_snapshot").and_then(|v| v.as_array()) {
|
|
429
|
-
let mut still_present: std::collections::HashSet<(String, String)> =
|
|
430
|
-
std::collections::HashSet::new();
|
|
431
|
-
for entry in saga_snapshot {
|
|
432
|
-
let process_manager = entry
|
|
433
|
-
.get("process_manager")
|
|
434
|
-
.and_then(|v| v.as_str())
|
|
435
|
-
.ok_or_else(|| {
|
|
436
|
-
anyhow::anyhow!("saga_snapshot entry missing \"process_manager\": {entry}")
|
|
437
|
-
})?;
|
|
438
|
-
let correlation = entry
|
|
439
|
-
.get("correlation")
|
|
440
|
-
.and_then(|v| v.as_str())
|
|
441
|
-
.ok_or_else(|| {
|
|
442
|
-
anyhow::anyhow!("saga_snapshot entry missing \"correlation\": {entry}")
|
|
443
|
-
})?;
|
|
444
|
-
let state = entry.get("state").and_then(|v| v.as_str()).ok_or_else(|| {
|
|
445
|
-
anyhow::anyhow!("saga_snapshot entry missing \"state\": {entry}")
|
|
446
|
-
})?;
|
|
447
|
-
let memory = entry
|
|
448
|
-
.get("memory")
|
|
449
|
-
.cloned()
|
|
450
|
-
.unwrap_or_else(|| serde_json::json!({}));
|
|
451
|
-
let completed_compensations = entry
|
|
452
|
-
.get("completed_compensations")
|
|
453
|
-
.cloned()
|
|
454
|
-
.unwrap_or_else(|| serde_json::json!([]));
|
|
455
|
-
|
|
456
|
-
journal::save_saga(
|
|
457
|
-
&txn,
|
|
458
|
-
process_manager,
|
|
459
|
-
correlation,
|
|
460
|
-
state,
|
|
461
|
-
&memory,
|
|
462
|
-
&completed_compensations,
|
|
463
|
-
)
|
|
464
|
-
.await?;
|
|
465
|
-
still_present.insert((process_manager.to_string(), correlation.to_string()));
|
|
466
|
-
}
|
|
467
|
-
for row in &saga_rows {
|
|
468
|
-
let key = (row.process_manager.clone(), row.correlation.clone());
|
|
469
|
-
if !still_present.contains(&key) {
|
|
470
|
-
journal::delete_saga(&txn, &row.process_manager, &row.correlation).await?;
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
// One entry per step in `steps`, so the last entry is this
|
|
476
|
-
// call's own new step. Skipped when `config.era` is `None`: a
|
|
477
|
-
// domain with nothing lineage-capable bound never provisions a
|
|
478
|
-
// head-snapshot table to write into (ADR 0034).
|
|
479
|
-
let step_mutations = if config.era.is_some() {
|
|
480
|
-
result
|
|
481
|
-
.get("mutations")
|
|
482
|
-
.and_then(|m| m.as_array())
|
|
483
|
-
.and_then(|steps| steps.last())
|
|
484
|
-
.and_then(|last| last.as_array())
|
|
485
|
-
.cloned()
|
|
486
|
-
.unwrap_or_default()
|
|
487
|
-
} else {
|
|
488
|
-
Vec::new()
|
|
489
|
-
};
|
|
490
|
-
|
|
491
|
-
for mutation in &step_mutations {
|
|
492
|
-
let aggregate = mutation
|
|
493
|
-
.get("aggregate")
|
|
494
|
-
.and_then(|v| v.as_str())
|
|
495
|
-
.ok_or_else(|| {
|
|
496
|
-
anyhow::anyhow!("mutation record missing \"aggregate\": {mutation}")
|
|
497
|
-
})?;
|
|
498
|
-
// `era.is_some()` means the lineage subsystem exists, not that
|
|
499
|
-
// this aggregate has a mirror: `mint` only provisions head
|
|
500
|
-
// snapshots for the capable set, so mirroring anything else
|
|
501
|
-
// would upsert into a relation nobody created.
|
|
502
|
-
if !config.mirrors(aggregate) {
|
|
503
|
-
continue;
|
|
504
|
-
}
|
|
505
|
-
let id = mutation
|
|
506
|
-
.get("id")
|
|
507
|
-
.and_then(|v| v.as_str())
|
|
508
|
-
.ok_or_else(|| anyhow::anyhow!("mutation record missing \"id\": {mutation}"))?;
|
|
509
|
-
let operation = mutation
|
|
510
|
-
.get("operation")
|
|
511
|
-
.and_then(|v| v.as_str())
|
|
512
|
-
.ok_or_else(|| {
|
|
513
|
-
anyhow::anyhow!("mutation record missing \"operation\": {mutation}")
|
|
514
|
-
})?;
|
|
515
|
-
let state = mutation
|
|
516
|
-
.get("state")
|
|
517
|
-
.ok_or_else(|| anyhow::anyhow!("mutation record missing \"state\": {mutation}"))?;
|
|
518
|
-
|
|
519
|
-
journal::append_lineage_mutation(
|
|
520
|
-
&txn,
|
|
521
|
-
config,
|
|
522
|
-
&journal::Mutation {
|
|
523
|
-
aggregate,
|
|
524
|
-
id,
|
|
525
|
-
operation,
|
|
526
|
-
state,
|
|
527
|
-
},
|
|
528
|
-
)
|
|
529
|
-
.await?;
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
// Only this step's own matches, same reason as `step_mutations`
|
|
534
|
-
// above: replaying a prior step's reaction would re-invoke a sibling
|
|
535
|
-
// Lambda on every later replay. Captured before commit, delivered after.
|
|
536
|
-
let pending_cross_domain = result
|
|
537
|
-
.get("cross_domain_reactions")
|
|
538
|
-
.and_then(|r| r.as_array())
|
|
539
|
-
.and_then(|steps| steps.last())
|
|
540
|
-
.and_then(|last| last.as_array())
|
|
541
|
-
.cloned()
|
|
542
|
-
.unwrap_or_default();
|
|
543
|
-
|
|
544
|
-
// Commits (and releases the advisory lock) whether or not anything
|
|
545
|
-
// was appended — a refused command still needs the lock released
|
|
546
|
-
// for the next invocation to proceed.
|
|
547
|
-
txn.commit().await?;
|
|
548
|
-
|
|
549
|
-
// Delivered after commit, deliberately: the local command already
|
|
550
|
-
// succeeded and is durable, so a cross-Lambda notification is
|
|
551
|
-
// best-effort, not a precondition of it. A fault that survives every
|
|
552
|
-
// retry still fails this call via `?`, but never unwinds an
|
|
553
|
-
// already-committed transaction.
|
|
554
|
-
// Every reaction gets its own attempt even after an earlier fails:
|
|
555
|
-
// returning early would silently drop the rest, undelivered and
|
|
556
|
-
// never dead-lettered (`SafeDepositBox.Surrender` fires two from one
|
|
557
|
-
// command). `first_failure` remembers only the first error without
|
|
558
|
-
// cutting the loop short.
|
|
559
|
-
let mut cross_domain_deliveries = Vec::new();
|
|
560
|
-
let mut first_failure: Option<anyhow::Error> = None;
|
|
561
|
-
for reaction in &pending_cross_domain {
|
|
562
|
-
match lambda_client::deliver_with_retry(invoker, reaction).await {
|
|
563
|
-
Ok(record) => {
|
|
564
|
-
if let Some(response) = result.as_object_mut() {
|
|
565
|
-
if let Some(reactions) =
|
|
566
|
-
response.get_mut("reactions").and_then(|r| r.as_array_mut())
|
|
567
|
-
{
|
|
568
|
-
reactions.push(serde_json::json!({
|
|
569
|
-
"policy": record.policy, "on": reaction.get("on").and_then(|v| v.as_str()).unwrap_or_default(),
|
|
570
|
-
"trigger": record.target_verb, "delivered": record.delivered, "reason": record.reason,
|
|
571
|
-
}));
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
cross_domain_deliveries.push(record.to_json());
|
|
575
|
-
}
|
|
576
|
-
Err(failure) => {
|
|
577
|
-
let error_text = format!("{:#}", failure.error);
|
|
578
|
-
crate::log::error(
|
|
579
|
-
"cross_domain_delivery_failed",
|
|
580
|
-
serde_json::json!({
|
|
581
|
-
"policy": failure.policy, "target_domain": failure.target_domain,
|
|
582
|
-
"target_verb": failure.target_verb, "attempts": failure.attempts, "error": error_text,
|
|
583
|
-
}),
|
|
584
|
-
);
|
|
585
|
-
journal::record_dead_letter(
|
|
586
|
-
&*guard,
|
|
587
|
-
&failure.policy,
|
|
588
|
-
&failure.target_domain,
|
|
589
|
-
&failure.target_verb,
|
|
590
|
-
&failure.payload,
|
|
591
|
-
&error_text,
|
|
592
|
-
failure.attempts as i32,
|
|
593
|
-
)
|
|
594
|
-
.await?;
|
|
595
|
-
if first_failure.is_none() {
|
|
596
|
-
first_failure = Some(failure.error);
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
if let Some(error) = first_failure {
|
|
602
|
-
return Err(error);
|
|
603
|
-
}
|
|
604
|
-
if let Some(response) = result.as_object_mut() {
|
|
605
|
-
response.insert(
|
|
606
|
-
"cross_domain_deliveries".to_string(),
|
|
607
|
-
serde_json::Value::Array(cross_domain_deliveries),
|
|
608
|
-
);
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
log_command(verb, role, accepted, &result);
|
|
612
|
-
Ok(Outcome { result, accepted })
|
|
613
|
-
}
|
|
1
|
+
//! The dispatch path against a real Postgres and the Memory store: what `rust_host_core`'s
|
|
2
|
+
//! dispatch does is only observable through a backend, and the backends live here.
|
|
614
3
|
|
|
615
|
-
|
|
616
|
-
// the facts) and what the domain answered.
|
|
617
|
-
fn log_command(verb: &str, role: Option<&str>, accepted: bool, result: &serde_json::Value) {
|
|
618
|
-
let fields = command_fields(verb, role, accepted, result);
|
|
619
|
-
if accepted {
|
|
620
|
-
crate::log::info("command", fields);
|
|
621
|
-
} else {
|
|
622
|
-
crate::log::error("command", fields);
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
fn command_fields(
|
|
627
|
-
verb: &str,
|
|
628
|
-
role: Option<&str>,
|
|
629
|
-
accepted: bool,
|
|
630
|
-
result: &serde_json::Value,
|
|
631
|
-
) -> serde_json::Value {
|
|
632
|
-
let events: Vec<serde_json::Value> = result
|
|
633
|
-
.get("events")
|
|
634
|
-
.and_then(|v| v.as_array())
|
|
635
|
-
.map(|items| {
|
|
636
|
-
items
|
|
637
|
-
.iter()
|
|
638
|
-
.filter_map(|item| item.get("name").cloned())
|
|
639
|
-
.collect()
|
|
640
|
-
})
|
|
641
|
-
.unwrap_or_default();
|
|
642
|
-
serde_json::json!({
|
|
643
|
-
"verb": verb, "role": role, "accepted": accepted, "events": events,
|
|
644
|
-
"refusals": result.get("refusals").cloned().unwrap_or_else(|| serde_json::json!([])),
|
|
645
|
-
})
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
// Read-only: the same seed path `handle` uses, minus the new step and
|
|
649
|
-
// any write. No advisory lock needed since nothing here writes.
|
|
650
|
-
// Returns the whole kernel result verbatim, not just `instances`, so a
|
|
651
|
-
// caller can tell an empty `refusals` from one that was never checked.
|
|
652
|
-
pub async fn read(client: &Mutex<Client>, wasm_path: &Path) -> anyhow::Result<serde_json::Value> {
|
|
653
|
-
let guard = client.lock().await;
|
|
654
|
-
let snapshot = journal::load_snapshot(&*guard).await?;
|
|
655
|
-
|
|
656
|
-
if let Some(s) = &snapshot {
|
|
657
|
-
let steps_since = journal::load_steps_after(&*guard, s.ordinal).await?;
|
|
658
|
-
drop(guard);
|
|
659
|
-
|
|
660
|
-
if steps_since.is_empty() {
|
|
661
|
-
// No wasm invocation needed: the snapshot's seed already is
|
|
662
|
-
// this domain's current "instances" output. Empty
|
|
663
|
-
// events/refusals is correct too — a read reports current
|
|
664
|
-
// state, never event/refusal history.
|
|
665
|
-
return Ok(serde_json::json!({ "instances": s.seed, "events": [], "refusals": [] }));
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
// Self-healing: if steps ever go unaccounted for after the last
|
|
669
|
-
// snapshot, seeding from it and replaying just the gap is
|
|
670
|
-
// still correct and cheap.
|
|
671
|
-
let input = serde_json::json!({ "seed": &s.seed, "steps": steps_since }).to_string();
|
|
672
|
-
let owned_wasm_path = wasm_path.to_path_buf();
|
|
673
|
-
let output =
|
|
674
|
-
tokio::task::spawn_blocking(move || wasm_runner::run(&owned_wasm_path, &input))
|
|
675
|
-
.await??;
|
|
676
|
-
return parse_kernel_output(&output);
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
// No snapshot: either a brand-new domain, or one with history from
|
|
680
|
-
// before this snapshot cache existed — either way, one full replay
|
|
681
|
-
// catches it up.
|
|
682
|
-
let steps = journal::load_steps(&*guard).await?;
|
|
683
|
-
drop(guard);
|
|
684
|
-
let input = serde_json::json!({ "steps": steps }).to_string();
|
|
685
|
-
let owned_wasm_path = wasm_path.to_path_buf();
|
|
686
|
-
let output =
|
|
687
|
-
tokio::task::spawn_blocking(move || wasm_runner::run(&owned_wasm_path, &input)).await??;
|
|
688
|
-
parse_kernel_output(&output)
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
// A declared query, answered against current state. Seeds from `read`
|
|
692
|
-
// rather than replaying history itself, so it sees exactly the state a
|
|
693
|
-
// read would report and pays at most one wasm invocation.
|
|
694
|
-
pub async fn query(
|
|
695
|
-
client: &Mutex<Client>,
|
|
696
|
-
wasm_path: &Path,
|
|
697
|
-
question: &str,
|
|
698
|
-
args: serde_json::Value,
|
|
699
|
-
) -> anyhow::Result<serde_json::Value> {
|
|
700
|
-
// A fact the query `needs` is answered before the kernel checks its arguments (ADR 0081).
|
|
701
|
-
let mut args = args;
|
|
702
|
-
if let Some(domain_ir) = crate::ir::ir() {
|
|
703
|
-
crate::needs::fill_query_needs(domain_ir, question, &mut args, &crate::needs::ProcessClock);
|
|
704
|
-
}
|
|
705
|
-
let state = read(client, wasm_path).await?;
|
|
706
|
-
let seed = state
|
|
707
|
-
.get("instances")
|
|
708
|
-
.cloned()
|
|
709
|
-
.unwrap_or_else(|| serde_json::json!({}));
|
|
710
|
-
let input = serde_json::json!({ "seed": seed, "steps": [{ "query": question, "args": args }] })
|
|
711
|
-
.to_string();
|
|
712
|
-
let owned_wasm_path = wasm_path.to_path_buf();
|
|
713
|
-
let output =
|
|
714
|
-
tokio::task::spawn_blocking(move || wasm_runner::run(&owned_wasm_path, &input)).await??;
|
|
715
|
-
parse_kernel_output(&output)
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
/// Answers `answer` (a kernel answer already computed and persisted) in the bare shape a caller
|
|
719
|
-
/// reads, by one more wasm run of the kernel's `{"present": answer}` input: each single-field
|
|
720
|
-
/// value object as its sole field. Nothing is stored or replayed.
|
|
721
|
-
pub async fn present(
|
|
722
|
-
wasm_path: &Path,
|
|
723
|
-
answer: serde_json::Value,
|
|
724
|
-
) -> anyhow::Result<serde_json::Value> {
|
|
725
|
-
let owned_wasm_path = wasm_path.to_path_buf();
|
|
726
|
-
tokio::task::spawn_blocking(move || {
|
|
727
|
-
present_with(&answer, |input| wasm_runner::run(&owned_wasm_path, input))
|
|
728
|
-
})
|
|
729
|
-
.await?
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
/// Presents `answer` as `present` does, with `run` standing in for the kernel (text in, text out).
|
|
733
|
-
pub(crate) fn present_with(
|
|
734
|
-
answer: &serde_json::Value,
|
|
735
|
-
run: impl FnOnce(&str) -> anyhow::Result<String>,
|
|
736
|
-
) -> anyhow::Result<serde_json::Value> {
|
|
737
|
-
let input = serde_json::json!({ "present": answer }).to_string();
|
|
738
|
-
parse_kernel_output(&run(&input)?)
|
|
739
|
-
}
|
|
4
|
+
#![allow(unused_imports)]
|
|
740
5
|
|
|
741
6
|
#[cfg(test)]
|
|
742
|
-
pub
|
|
7
|
+
pub mod tests {
|
|
743
8
|
|
|
744
9
|
#[test]
|
|
745
10
|
fn a_command_log_line_names_the_verb_events_and_refusals_but_never_the_facts() {
|
|
@@ -755,15 +20,22 @@ pub(crate) mod tests {
|
|
|
755
20
|
assert_eq!(fields["refusals"][0]["kind"], "AlreadyExists");
|
|
756
21
|
assert!(!fields.to_string().contains("a@b.c"));
|
|
757
22
|
}
|
|
758
|
-
use
|
|
23
|
+
use crate::host::Host;
|
|
24
|
+
use crate::journal;
|
|
759
25
|
use crate::journal::LineageConfig;
|
|
26
|
+
use crate::lambda_client;
|
|
760
27
|
use crate::lambda_client::LambdaInvoker;
|
|
761
|
-
use
|
|
28
|
+
use crate::store::journal_sql;
|
|
29
|
+
use crate::store::{Accepted, DeadLetter, LineageWrite, Store, StoreExt, StoreFixtures};
|
|
30
|
+
use crate::wasm_runner;
|
|
31
|
+
use rust_host_core::dispatch::*;
|
|
32
|
+
use std::path::Path;
|
|
33
|
+
use tokio_postgres::{Client, NoTls};
|
|
762
34
|
|
|
763
35
|
// A throwaway Postgres database per test, uniquely named so
|
|
764
36
|
// `cargo test`'s default parallelism doesn't race two tests against
|
|
765
37
|
// the same journal table.
|
|
766
|
-
pub
|
|
38
|
+
pub async fn scratch_db(name: &str) -> Store {
|
|
767
39
|
let (admin, conn) = tokio_postgres::connect(&crate::test_pg::conninfo("postgres"), NoTls)
|
|
768
40
|
.await
|
|
769
41
|
.expect("connect to postgres");
|
|
@@ -785,14 +57,29 @@ pub(crate) mod tests {
|
|
|
785
57
|
tokio::spawn(async move {
|
|
786
58
|
let _ = conn.await;
|
|
787
59
|
});
|
|
788
|
-
|
|
789
|
-
|
|
60
|
+
journal_sql::ensure_schema(&client).await.unwrap();
|
|
61
|
+
crate::store::postgres_store(client)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/// An empty in-memory store, for tests that need a journal and nothing Postgres-specific.
|
|
65
|
+
pub fn memory_store() -> Store {
|
|
66
|
+
Store::memory(crate::store::MemoryStore::new())
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/// The config a memory-backed host runs under: no era, so nothing mirrors into lineage.
|
|
70
|
+
pub fn memory_config(domain: &str) -> LineageConfig {
|
|
71
|
+
LineageConfig {
|
|
72
|
+
domain: domain.to_string(),
|
|
73
|
+
era: None,
|
|
74
|
+
mirrored: None,
|
|
75
|
+
seal_every: None,
|
|
76
|
+
}
|
|
790
77
|
}
|
|
791
78
|
|
|
792
79
|
// Not Ruby's real provisioning — just enough structure for
|
|
793
|
-
// `
|
|
80
|
+
// `journal_sql::current_era` and `append_lineage_mutation` to succeed,
|
|
794
81
|
// without reproducing Ruby's full DDL.
|
|
795
|
-
pub
|
|
82
|
+
pub async fn provision_lineage(
|
|
796
83
|
client: &Client,
|
|
797
84
|
domain: &str,
|
|
798
85
|
era: i32,
|
|
@@ -814,7 +101,7 @@ pub(crate) mod tests {
|
|
|
814
101
|
.await
|
|
815
102
|
.unwrap();
|
|
816
103
|
|
|
817
|
-
let journal_table = format!("hecks_journal_{}",
|
|
104
|
+
let journal_table = format!("hecks_journal_{}", journal_sql::snake(domain));
|
|
818
105
|
client
|
|
819
106
|
.batch_execute(&format!(
|
|
820
107
|
"CREATE TABLE IF NOT EXISTS \"{journal_table}\" (
|
|
@@ -823,7 +110,8 @@ pub(crate) mod tests {
|
|
|
823
110
|
aggregate text NOT NULL,
|
|
824
111
|
aggregate_id text NOT NULL,
|
|
825
112
|
operation text NOT NULL,
|
|
826
|
-
state jsonb
|
|
113
|
+
state jsonb,
|
|
114
|
+
mirrors jsonb
|
|
827
115
|
)"
|
|
828
116
|
))
|
|
829
117
|
.await
|
|
@@ -832,9 +120,9 @@ pub(crate) mod tests {
|
|
|
832
120
|
for name in aggregate_storage_names {
|
|
833
121
|
// Domain-qualified (ADR 0059), matching what a real write
|
|
834
122
|
// targets.
|
|
835
|
-
let snapshot_table =
|
|
123
|
+
let snapshot_table = journal_sql::qualified_name(
|
|
836
124
|
domain,
|
|
837
|
-
&format!("{}_head_snapshot_{era}",
|
|
125
|
+
&format!("{}_head_snapshot_{era}", journal_sql::snake(name)),
|
|
838
126
|
);
|
|
839
127
|
client
|
|
840
128
|
.batch_execute(&format!(
|
|
@@ -877,6 +165,7 @@ pub(crate) mod tests {
|
|
|
877
165
|
domain: "Banking".to_string(),
|
|
878
166
|
era: Some(1),
|
|
879
167
|
mirrored: None,
|
|
168
|
+
seal_every: None,
|
|
880
169
|
};
|
|
881
170
|
let refused = handle_facts(
|
|
882
171
|
Host::new(&client, &wasm, &everything, &invoker),
|
|
@@ -908,6 +197,7 @@ pub(crate) mod tests {
|
|
|
908
197
|
domain: "Banking".to_string(),
|
|
909
198
|
era: Some(1),
|
|
910
199
|
mirrored: Some(std::collections::BTreeSet::new()),
|
|
200
|
+
seal_every: None,
|
|
911
201
|
};
|
|
912
202
|
let outcome = handle_facts(
|
|
913
203
|
Host::new(&client, &wasm, &declared, &invoker),
|
|
@@ -953,6 +243,7 @@ pub(crate) mod tests {
|
|
|
953
243
|
domain: "Banking".to_string(),
|
|
954
244
|
era: Some(1),
|
|
955
245
|
mirrored: Some(std::iter::once("Banking::Customer".to_string()).collect()),
|
|
246
|
+
seal_every: None,
|
|
956
247
|
};
|
|
957
248
|
|
|
958
249
|
handle_facts(
|
|
@@ -978,11 +269,12 @@ pub(crate) mod tests {
|
|
|
978
269
|
assert_eq!(mirrored, 1);
|
|
979
270
|
}
|
|
980
271
|
|
|
981
|
-
fn test_config(domain: &str, era: i32) -> LineageConfig {
|
|
272
|
+
pub fn test_config(domain: &str, era: i32) -> LineageConfig {
|
|
982
273
|
LineageConfig {
|
|
983
274
|
domain: domain.to_string(),
|
|
984
275
|
era: Some(era),
|
|
985
276
|
mirrored: None,
|
|
277
|
+
seal_every: None,
|
|
986
278
|
}
|
|
987
279
|
}
|
|
988
280
|
|
|
@@ -1010,11 +302,11 @@ pub(crate) mod tests {
|
|
|
1010
302
|
assert!(failed.is_err());
|
|
1011
303
|
}
|
|
1012
304
|
|
|
1013
|
-
pub
|
|
305
|
+
pub fn wasm_path() -> std::path::PathBuf {
|
|
1014
306
|
std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../dist/banking.wasm")
|
|
1015
307
|
}
|
|
1016
308
|
|
|
1017
|
-
fn register(reference: &str) -> serde_json::Value {
|
|
309
|
+
pub fn register(reference: &str) -> serde_json::Value {
|
|
1018
310
|
serde_json::json!({
|
|
1019
311
|
"reference": { "value": reference },
|
|
1020
312
|
"name": { "given": "Ada", "family": "Lovelace" },
|
|
@@ -1026,9 +318,8 @@ pub(crate) mod tests {
|
|
|
1026
318
|
// query answered against whatever state the journal currently holds.
|
|
1027
319
|
#[tokio::test]
|
|
1028
320
|
async fn a_declared_query_answers_against_current_state() {
|
|
1029
|
-
let client =
|
|
1030
|
-
|
|
1031
|
-
let config = test_config("Banking", 1);
|
|
321
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
322
|
+
let config = crate::dispatch_tests::tests::memory_config("Banking");
|
|
1032
323
|
|
|
1033
324
|
handle(
|
|
1034
325
|
Host::new(&client, &wasm_path(), &config, &lambda_client::NeverInvoker),
|
|
@@ -1110,7 +401,7 @@ pub(crate) mod tests {
|
|
|
1110
401
|
assert!(outcome.accepted);
|
|
1111
402
|
assert_eq!(outcome.result["refusals"].as_array().unwrap().len(), 0);
|
|
1112
403
|
let guard = client.lock().await;
|
|
1113
|
-
let steps =
|
|
404
|
+
let steps = journal_sql::load_steps(&*guard).await.unwrap();
|
|
1114
405
|
assert_eq!(steps.len(), 1);
|
|
1115
406
|
|
|
1116
407
|
// The lineage write itself: a row landed in the era-tagged,
|
|
@@ -1152,20 +443,59 @@ pub(crate) mod tests {
|
|
|
1152
443
|
assert_eq!(id, "CUST-0001");
|
|
1153
444
|
}
|
|
1154
445
|
|
|
446
|
+
// The seal is part of the commit, not a tool run afterwards: the second accepted command
|
|
447
|
+
// leaves a seal through the second lineage row, and the chain walks clean from it.
|
|
448
|
+
#[tokio::test]
|
|
449
|
+
async fn a_commit_seals_the_lineage_chain_every_so_many_rows() {
|
|
450
|
+
let client = scratch_db("rust_host_dispatch_seals").await;
|
|
451
|
+
provision_lineage(&*client.lock().await, "Banking", 1, &["Customer"]).await;
|
|
452
|
+
let config = LineageConfig {
|
|
453
|
+
seal_every: Some(2),
|
|
454
|
+
..test_config("Banking", 1)
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
for id in ["CUST-0001", "CUST-0002", "CUST-0003"] {
|
|
458
|
+
let outcome = handle(
|
|
459
|
+
Host::new(&client, &wasm_path(), &config, &lambda_client::NeverInvoker),
|
|
460
|
+
"Banking::Customer.Register",
|
|
461
|
+
register(id),
|
|
462
|
+
None,
|
|
463
|
+
)
|
|
464
|
+
.await
|
|
465
|
+
.unwrap();
|
|
466
|
+
assert!(outcome.accepted, "{id} should be accepted");
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
let guard = client.lock().await;
|
|
470
|
+
let seals = crate::ledger::anchors(&*guard, "Banking").await.unwrap();
|
|
471
|
+
assert_eq!(
|
|
472
|
+
seals.iter().map(|seal| seal.through).collect::<Vec<_>>(),
|
|
473
|
+
vec![2],
|
|
474
|
+
"one seal, taken by the commit that made two rows unsealed"
|
|
475
|
+
);
|
|
476
|
+
assert_eq!(
|
|
477
|
+
crate::ledger::verify(&*guard, "Banking").await.unwrap(),
|
|
478
|
+
crate::ledger::Finding::Verified(crate::ledger::Report {
|
|
479
|
+
seals: 1,
|
|
480
|
+
entries: 2,
|
|
481
|
+
unsealed: 1
|
|
482
|
+
})
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
|
|
1155
486
|
// Proves `occurred_at` end to end through the real wasm module: the
|
|
1156
487
|
// string this crate stamps and sends is the one that comes back out
|
|
1157
488
|
// in the returned event, not just what the in-kernel unit tests prove.
|
|
1158
489
|
#[tokio::test]
|
|
1159
490
|
async fn occurred_at_is_stamped_onto_every_returned_event_with_this_crate_s_own_real_clock() {
|
|
1160
|
-
let client =
|
|
1161
|
-
provision_lineage(&*client.lock().await, "Banking", 1, &["Customer"]).await;
|
|
491
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
1162
492
|
|
|
1163
|
-
let before = crate::
|
|
493
|
+
let before = crate::clock::iso8601_now();
|
|
1164
494
|
let outcome = handle(
|
|
1165
495
|
Host::new(
|
|
1166
496
|
&client,
|
|
1167
497
|
&wasm_path(),
|
|
1168
|
-
&
|
|
498
|
+
&crate::dispatch_tests::tests::memory_config("Banking"),
|
|
1169
499
|
&lambda_client::NeverInvoker,
|
|
1170
500
|
),
|
|
1171
501
|
"Banking::Customer.Register",
|
|
@@ -1174,7 +504,7 @@ pub(crate) mod tests {
|
|
|
1174
504
|
)
|
|
1175
505
|
.await
|
|
1176
506
|
.unwrap();
|
|
1177
|
-
let after = crate::
|
|
507
|
+
let after = crate::clock::iso8601_now();
|
|
1178
508
|
|
|
1179
509
|
assert!(outcome.accepted, "{:?}", outcome.result["refusals"]);
|
|
1180
510
|
let events = outcome.result["events"].as_array().unwrap();
|
|
@@ -1193,9 +523,8 @@ pub(crate) mod tests {
|
|
|
1193
523
|
|
|
1194
524
|
#[tokio::test]
|
|
1195
525
|
async fn rehydrates_prior_history_before_evaluating_the_new_command() {
|
|
1196
|
-
let client =
|
|
1197
|
-
|
|
1198
|
-
let config = test_config("Banking", 1);
|
|
526
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
527
|
+
let config = crate::dispatch_tests::tests::memory_config("Banking");
|
|
1199
528
|
|
|
1200
529
|
let first = handle(
|
|
1201
530
|
Host::new(&client, &wasm_path(), &config, &lambda_client::NeverInvoker),
|
|
@@ -1228,7 +557,7 @@ pub(crate) mod tests {
|
|
|
1228
557
|
"duplicate registration should be refused, proving prior state was rehydrated: {:?}",
|
|
1229
558
|
second.result
|
|
1230
559
|
);
|
|
1231
|
-
let steps =
|
|
560
|
+
let steps = client.journal_steps().await;
|
|
1232
561
|
assert_eq!(
|
|
1233
562
|
steps.len(),
|
|
1234
563
|
1,
|
|
@@ -1261,11 +590,11 @@ pub(crate) mod tests {
|
|
|
1261
590
|
);
|
|
1262
591
|
|
|
1263
592
|
let guard = client.lock().await;
|
|
1264
|
-
let snapshot =
|
|
593
|
+
let snapshot = journal_sql::load_snapshot(&*guard)
|
|
1265
594
|
.await
|
|
1266
595
|
.unwrap()
|
|
1267
596
|
.expect("a snapshot should exist after the first accepted command");
|
|
1268
|
-
let tail =
|
|
597
|
+
let tail = journal_sql::load_steps_after(&*guard, snapshot.ordinal)
|
|
1269
598
|
.await
|
|
1270
599
|
.unwrap();
|
|
1271
600
|
assert!(tail.is_empty(), "the snapshot should already reflect every accepted command, leaving nothing to replay");
|
|
@@ -1279,7 +608,7 @@ pub(crate) mod tests {
|
|
|
1279
608
|
);
|
|
1280
609
|
}
|
|
1281
610
|
|
|
1282
|
-
let final_snapshot =
|
|
611
|
+
let final_snapshot = journal_sql::load_snapshot(&*client.lock().await)
|
|
1283
612
|
.await
|
|
1284
613
|
.unwrap()
|
|
1285
614
|
.unwrap();
|
|
@@ -1356,7 +685,7 @@ pub(crate) mod tests {
|
|
|
1356
685
|
.unwrap();
|
|
1357
686
|
assert!(first.accepted, "{:?}", first.result);
|
|
1358
687
|
|
|
1359
|
-
let whole_world =
|
|
688
|
+
let whole_world = journal_sql::load_snapshot(&*client.lock().await)
|
|
1360
689
|
.await
|
|
1361
690
|
.unwrap()
|
|
1362
691
|
.unwrap()
|
|
@@ -1467,7 +796,7 @@ pub(crate) mod tests {
|
|
|
1467
796
|
.await
|
|
1468
797
|
.unwrap();
|
|
1469
798
|
assert!(second.accepted, "{:?}", second.result);
|
|
1470
|
-
let after =
|
|
799
|
+
let after = journal_sql::load_snapshot(&*client.lock().await)
|
|
1471
800
|
.await
|
|
1472
801
|
.unwrap()
|
|
1473
802
|
.unwrap()
|
|
@@ -1482,7 +811,7 @@ pub(crate) mod tests {
|
|
|
1482
811
|
}
|
|
1483
812
|
|
|
1484
813
|
// The snapshot's ordinal and exact seed text, and how many commands are journaled.
|
|
1485
|
-
async fn snapshot_and_journal(client: &
|
|
814
|
+
async fn snapshot_and_journal(client: &Store) -> (i64, String, i64) {
|
|
1486
815
|
let guard = client.lock().await;
|
|
1487
816
|
let snapshot = guard
|
|
1488
817
|
.query_one("SELECT ordinal, seed::text FROM hecks_lambda_snapshot", &[])
|
|
@@ -1504,9 +833,8 @@ pub(crate) mod tests {
|
|
|
1504
833
|
// appended — silently violating the uniqueness the domain
|
|
1505
834
|
// itself enforces. With the lock serializing the whole
|
|
1506
835
|
// read-then-append sequence, exactly one must be accepted.
|
|
1507
|
-
let client =
|
|
1508
|
-
|
|
1509
|
-
let config = test_config("Banking", 1);
|
|
836
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
837
|
+
let config = crate::dispatch_tests::tests::memory_config("Banking");
|
|
1510
838
|
let wasm_path = wasm_path();
|
|
1511
839
|
|
|
1512
840
|
let (first, second) = tokio::join!(
|
|
@@ -1530,7 +858,7 @@ pub(crate) mod tests {
|
|
|
1530
858
|
"exactly one of two concurrent duplicate registrations should be accepted: {:?} / {:?}",
|
|
1531
859
|
first.result, second.result
|
|
1532
860
|
);
|
|
1533
|
-
let steps =
|
|
861
|
+
let steps = client.journal_steps().await;
|
|
1534
862
|
assert_eq!(
|
|
1535
863
|
steps.len(),
|
|
1536
864
|
1,
|
|
@@ -1540,14 +868,13 @@ pub(crate) mod tests {
|
|
|
1540
868
|
|
|
1541
869
|
#[tokio::test]
|
|
1542
870
|
async fn read_reflects_prior_dispatches_without_persisting_anything_new() {
|
|
1543
|
-
let client =
|
|
1544
|
-
provision_lineage(&*client.lock().await, "Banking", 1, &["Customer"]).await;
|
|
871
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
1545
872
|
|
|
1546
873
|
handle(
|
|
1547
874
|
Host::new(
|
|
1548
875
|
&client,
|
|
1549
876
|
&wasm_path(),
|
|
1550
|
-
&
|
|
877
|
+
&crate::dispatch_tests::tests::memory_config("Banking"),
|
|
1551
878
|
&lambda_client::NeverInvoker,
|
|
1552
879
|
),
|
|
1553
880
|
"Banking::Customer.Register",
|
|
@@ -1574,19 +901,19 @@ pub(crate) mod tests {
|
|
|
1574
901
|
|
|
1575
902
|
// The sharp proof a read never appends: the journal is exactly
|
|
1576
903
|
// as long after the read as it was before it.
|
|
1577
|
-
let steps =
|
|
904
|
+
let steps = client.journal_steps().await;
|
|
1578
905
|
assert_eq!(steps.len(), 1, "a read must never persist a journal row");
|
|
1579
906
|
}
|
|
1580
907
|
|
|
1581
908
|
// Records every call and answers with a canned "nothing refused"
|
|
1582
909
|
// body, proving a cross-domain policy reaches `lambda_client::deliver`
|
|
1583
910
|
// with the right name/payload end to end, short of a real AWS Lambda.
|
|
1584
|
-
struct RecordingInvoker {
|
|
911
|
+
pub struct RecordingInvoker {
|
|
1585
912
|
calls: std::sync::Mutex<Vec<(String, String)>>,
|
|
1586
913
|
}
|
|
1587
914
|
|
|
1588
915
|
impl RecordingInvoker {
|
|
1589
|
-
fn new() -> Self {
|
|
916
|
+
pub fn new() -> Self {
|
|
1590
917
|
Self {
|
|
1591
918
|
calls: std::sync::Mutex::new(Vec::new()),
|
|
1592
919
|
}
|
|
@@ -1613,15 +940,8 @@ pub(crate) mod tests {
|
|
|
1613
940
|
|
|
1614
941
|
#[tokio::test]
|
|
1615
942
|
async fn a_cross_domain_policy_delivers_through_the_real_rehydrate_replay_path() {
|
|
1616
|
-
let client =
|
|
1617
|
-
|
|
1618
|
-
&*client.lock().await,
|
|
1619
|
-
"Banking",
|
|
1620
|
-
1,
|
|
1621
|
-
&["Customer", "Account"],
|
|
1622
|
-
)
|
|
1623
|
-
.await;
|
|
1624
|
-
let config = test_config("Banking", 1);
|
|
943
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
944
|
+
let config = crate::dispatch_tests::tests::memory_config("Banking");
|
|
1625
945
|
let invoker = RecordingInvoker::new();
|
|
1626
946
|
|
|
1627
947
|
handle(
|
|
@@ -1693,7 +1013,7 @@ pub(crate) mod tests {
|
|
|
1693
1013
|
.find(|r| r["policy"] == "ReviewOnFreeze")
|
|
1694
1014
|
.expect("ReviewOnFreeze should appear in \"reactions\" too");
|
|
1695
1015
|
assert_eq!(merged["on"], "AccountFrozen");
|
|
1696
|
-
assert_eq!(merged["trigger"], "Compliance::
|
|
1016
|
+
assert_eq!(merged["trigger"], "Compliance::Review.Open");
|
|
1697
1017
|
assert_eq!(merged["delivered"], true);
|
|
1698
1018
|
|
|
1699
1019
|
{
|
|
@@ -1704,9 +1024,10 @@ pub(crate) mod tests {
|
|
|
1704
1024
|
let sent: serde_json::Value = serde_json::from_str(payload).unwrap();
|
|
1705
1025
|
// Fully qualified, not the bare "Compliance.OpenReview":
|
|
1706
1026
|
// generated match arms are always "Domain::Aggregate.Command",
|
|
1707
|
-
// and Compliance's own aggregate is named `
|
|
1708
|
-
assert_eq!(sent["verb"], "Compliance::
|
|
1709
|
-
assert_eq!(sent["args"]["
|
|
1027
|
+
// and Compliance's own aggregate is named `Review`.
|
|
1028
|
+
assert_eq!(sent["verb"], "Compliance::Review.Open");
|
|
1029
|
+
assert_eq!(sent["args"]["subject_kind"], "account_freeze");
|
|
1030
|
+
assert_eq!(sent["args"]["subject_key"], "acct-freeze-me");
|
|
1710
1031
|
}
|
|
1711
1032
|
|
|
1712
1033
|
// Never re-delivered on a later replay: `pending_cross_domain`
|
|
@@ -1734,9 +1055,8 @@ pub(crate) mod tests {
|
|
|
1734
1055
|
// registry — real, corpus-declared.
|
|
1735
1056
|
#[tokio::test]
|
|
1736
1057
|
async fn a_role_gated_command_is_actually_checked_against_the_caller_role() {
|
|
1737
|
-
let client =
|
|
1738
|
-
|
|
1739
|
-
let config = test_config("Banking", 1);
|
|
1058
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
1059
|
+
let config = crate::dispatch_tests::tests::memory_config("Banking");
|
|
1740
1060
|
|
|
1741
1061
|
// The correct role succeeds, same as every other registration,
|
|
1742
1062
|
// just now with a caller actually bound and matching.
|
|
@@ -1781,7 +1101,7 @@ pub(crate) mod tests {
|
|
|
1781
1101
|
|
|
1782
1102
|
// And the refused command was never persisted — same discipline
|
|
1783
1103
|
// every other refusal in this file is held to.
|
|
1784
|
-
let steps =
|
|
1104
|
+
let steps = client.journal_steps().await;
|
|
1785
1105
|
assert_eq!(
|
|
1786
1106
|
steps.len(),
|
|
1787
1107
|
1,
|
|
@@ -1789,6 +1109,25 @@ pub(crate) mod tests {
|
|
|
1789
1109
|
);
|
|
1790
1110
|
}
|
|
1791
1111
|
|
|
1112
|
+
// ADR 0081 keeps a needed fact the caller supplied, but only the host and its peers may: a
|
|
1113
|
+
// request's `now` would move a time-window guard.
|
|
1114
|
+
#[test]
|
|
1115
|
+
fn only_a_request_from_outside_the_host_has_its_needed_facts_replaced() {
|
|
1116
|
+
let ir = serde_json::json!({"name": "Lease", "aggregates": [{"name": "Slot", "commands": [
|
|
1117
|
+
{"name": "Take", "attributes": [{"name": "now", "type": "Integer"}],
|
|
1118
|
+
"needs": [{"fact": "now"}]}
|
|
1119
|
+
]}]});
|
|
1120
|
+
let fill = |origin: Origin| {
|
|
1121
|
+
let mut args = serde_json::json!({"with": {"now": 42}});
|
|
1122
|
+
let clock = crate::needs::FixedClock(7);
|
|
1123
|
+
fill_arguments(origin, &ir, "Lease::Slot.Take", &mut args, &clock);
|
|
1124
|
+
args["with"]["now"].clone()
|
|
1125
|
+
};
|
|
1126
|
+
assert_eq!(fill(Origin::Request), serde_json::json!(7));
|
|
1127
|
+
assert_eq!(fill(Origin::External), serde_json::json!(42));
|
|
1128
|
+
assert_eq!(fill(Origin::HostInternal), serde_json::json!(42));
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1792
1131
|
#[test]
|
|
1793
1132
|
fn enforcement_reads_off_shadow_and_enforce_and_treats_anything_else_as_off() {
|
|
1794
1133
|
assert_eq!(Enforcement::parse(None), Enforcement::Off);
|
|
@@ -1825,9 +1164,8 @@ pub(crate) mod tests {
|
|
|
1825
1164
|
#[tokio::test]
|
|
1826
1165
|
async fn an_unidentified_caller_is_refused_when_enforced_and_let_through_when_off_or_shadowed()
|
|
1827
1166
|
{
|
|
1828
|
-
let client =
|
|
1829
|
-
|
|
1830
|
-
let config = test_config("Banking", 1);
|
|
1167
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
1168
|
+
let config = crate::dispatch_tests::tests::memory_config("Banking");
|
|
1831
1169
|
let go = |mode: Enforcement, id: &'static str| {
|
|
1832
1170
|
let client = &client;
|
|
1833
1171
|
let config = &config;
|
|
@@ -1872,7 +1210,7 @@ pub(crate) mod tests {
|
|
|
1872
1210
|
shadowed.result
|
|
1873
1211
|
);
|
|
1874
1212
|
|
|
1875
|
-
let steps =
|
|
1213
|
+
let steps = client.journal_steps().await;
|
|
1876
1214
|
assert_eq!(
|
|
1877
1215
|
steps.len(),
|
|
1878
1216
|
2,
|
|
@@ -1883,9 +1221,8 @@ pub(crate) mod tests {
|
|
|
1883
1221
|
// Shadow may only let through what Off would: a caller that stated a wrong role is refused.
|
|
1884
1222
|
#[tokio::test]
|
|
1885
1223
|
async fn shadow_refuses_a_stated_wrong_role_and_still_lets_an_unidentified_caller_through() {
|
|
1886
|
-
let client =
|
|
1887
|
-
|
|
1888
|
-
let config = test_config("Banking", 1);
|
|
1224
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
1225
|
+
let config = crate::dispatch_tests::tests::memory_config("Banking");
|
|
1889
1226
|
let go = |mode: Enforcement, origin: Origin, caller: Caller<'static>, id: &'static str| {
|
|
1890
1227
|
let client = &client;
|
|
1891
1228
|
let config = &config;
|
|
@@ -1938,7 +1275,7 @@ pub(crate) mod tests {
|
|
|
1938
1275
|
nobody.result
|
|
1939
1276
|
);
|
|
1940
1277
|
|
|
1941
|
-
let steps =
|
|
1278
|
+
let steps = client.journal_steps().await;
|
|
1942
1279
|
assert_eq!(
|
|
1943
1280
|
steps.len(),
|
|
1944
1281
|
1,
|
|
@@ -1950,9 +1287,8 @@ pub(crate) mod tests {
|
|
|
1950
1287
|
// unidentified caller is refused under enforce.
|
|
1951
1288
|
#[tokio::test]
|
|
1952
1289
|
async fn a_host_internal_dispatch_is_unchecked_under_enforce_but_an_external_one_is_refused() {
|
|
1953
|
-
let client =
|
|
1954
|
-
|
|
1955
|
-
let config = test_config("Banking", 1);
|
|
1290
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
1291
|
+
let config = crate::dispatch_tests::tests::memory_config("Banking");
|
|
1956
1292
|
let go = |mode: Enforcement, origin: Origin, id: &'static str| {
|
|
1957
1293
|
let client = &client;
|
|
1958
1294
|
let config = &config;
|
|
@@ -2263,15 +1599,8 @@ pub(crate) mod tests {
|
|
|
2263
1599
|
#[tokio::test]
|
|
2264
1600
|
async fn a_cross_domain_delivery_that_exhausts_every_retry_dead_letters_and_still_fails_the_invocation(
|
|
2265
1601
|
) {
|
|
2266
|
-
let client =
|
|
2267
|
-
|
|
2268
|
-
&*client.lock().await,
|
|
2269
|
-
"Banking",
|
|
2270
|
-
1,
|
|
2271
|
-
&["Customer", "Account"],
|
|
2272
|
-
)
|
|
2273
|
-
.await;
|
|
2274
|
-
let config = test_config("Banking", 1);
|
|
1602
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
1603
|
+
let config = crate::dispatch_tests::tests::memory_config("Banking");
|
|
2275
1604
|
let invoker = AlwaysFailingInvoker::new();
|
|
2276
1605
|
|
|
2277
1606
|
handle(
|
|
@@ -2331,42 +1660,28 @@ pub(crate) mod tests {
|
|
|
2331
1660
|
// The local command still committed: cross-domain delivery runs
|
|
2332
1661
|
// strictly after commit, so a delivery failure never unwinds it.
|
|
2333
1662
|
// The dead letter existing at all proves the match already ran.
|
|
2334
|
-
let
|
|
2335
|
-
let dead_letters = guard
|
|
2336
|
-
.query("SELECT policy, target_domain, target_verb, attempts FROM hecks_cross_domain_dead_letters", &[])
|
|
2337
|
-
.await
|
|
2338
|
-
.unwrap();
|
|
1663
|
+
let dead_letters = client.dead_letter_rows().await;
|
|
2339
1664
|
assert_eq!(
|
|
2340
1665
|
dead_letters.len(),
|
|
2341
1666
|
1,
|
|
2342
1667
|
"exactly one exhausted delivery should have been dead-lettered: {dead_letters:?}"
|
|
2343
1668
|
);
|
|
2344
|
-
let policy
|
|
2345
|
-
let target_domain: String = dead_letters[0].get(1);
|
|
2346
|
-
let target_verb: String = dead_letters[0].get(2);
|
|
2347
|
-
let attempts: i32 = dead_letters[0].get(3);
|
|
1669
|
+
let (policy, target_domain, target_verb, attempts) = dead_letters[0].clone();
|
|
2348
1670
|
assert_eq!(policy, "ReviewOnFreeze");
|
|
2349
1671
|
assert_eq!(target_domain, "Compliance");
|
|
2350
|
-
assert_eq!(target_verb, "Compliance::
|
|
1672
|
+
assert_eq!(target_verb, "Compliance::Review.Open");
|
|
2351
1673
|
assert_eq!(attempts, lambda_client::MAX_DELIVERY_ATTEMPTS as i32);
|
|
2352
1674
|
}
|
|
2353
1675
|
|
|
2354
1676
|
// Pins a real drop: a second cross-domain reaction from the same
|
|
2355
1677
|
// step must not go dark just because the first one's delivery
|
|
2356
1678
|
// exhausted its retries. `SafeDepositBox.Surrender` emits both
|
|
2357
|
-
// `BoxSurrendered` (-> Compliance) and `
|
|
1679
|
+
// `BoxSurrendered` (-> Compliance) and `KeyReturnRequested` (-> Notifications)
|
|
2358
1680
|
// from one command.
|
|
2359
1681
|
#[tokio::test]
|
|
2360
1682
|
async fn a_failed_cross_domain_delivery_does_not_drop_a_sibling_reaction_from_the_same_step() {
|
|
2361
|
-
let client =
|
|
2362
|
-
|
|
2363
|
-
&*client.lock().await,
|
|
2364
|
-
"Banking",
|
|
2365
|
-
1,
|
|
2366
|
-
&["Customer", "SafeDepositBox"],
|
|
2367
|
-
)
|
|
2368
|
-
.await;
|
|
2369
|
-
let config = test_config("Banking", 1);
|
|
1683
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
1684
|
+
let config = crate::dispatch_tests::tests::memory_config("Banking");
|
|
2370
1685
|
let invoker = AlwaysFailingInvoker::new();
|
|
2371
1686
|
|
|
2372
1687
|
handle(
|
|
@@ -2422,19 +1737,224 @@ pub(crate) mod tests {
|
|
|
2422
1737
|
the fix under test is exactly this: a fresh Vec would only ever show one policy's worth"
|
|
2423
1738
|
);
|
|
2424
1739
|
|
|
2425
|
-
let
|
|
2426
|
-
|
|
2427
|
-
.query(
|
|
2428
|
-
"SELECT policy FROM hecks_cross_domain_dead_letters ORDER BY policy",
|
|
2429
|
-
&[],
|
|
2430
|
-
)
|
|
1740
|
+
let policies: Vec<String> = client
|
|
1741
|
+
.dead_letter_rows()
|
|
2431
1742
|
.await
|
|
2432
|
-
.
|
|
2433
|
-
|
|
1743
|
+
.into_iter()
|
|
1744
|
+
.map(|row| row.0)
|
|
1745
|
+
.collect();
|
|
2434
1746
|
assert_eq!(
|
|
2435
1747
|
policies,
|
|
2436
1748
|
vec!["FlagKeyReturn".to_string(), "ReviewOnBoxSurrender".to_string()],
|
|
2437
1749
|
"BOTH sibling reactions must be dead-lettered, not just whichever ran first: {policies:?}"
|
|
2438
1750
|
);
|
|
2439
1751
|
}
|
|
1752
|
+
/// The wasm plugin fixture (spec/fixtures/rust_host/pluginned): its kernel and its IR, which
|
|
1753
|
+
/// carries the doubler plugin that answers `Ledger.Doubled` and refuses `Ledger.Tripled`.
|
|
1754
|
+
fn pluginned() -> (std::path::PathBuf, serde_json::Value) {
|
|
1755
|
+
let dist = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../dist");
|
|
1756
|
+
let ir = std::fs::read_to_string(dist.join("pluginned.ir.json"))
|
|
1757
|
+
.expect("build the pluginned fixture");
|
|
1758
|
+
(
|
|
1759
|
+
dist.join("pluginned.wasm"),
|
|
1760
|
+
serde_json::from_str(&ir).unwrap(),
|
|
1761
|
+
)
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1764
|
+
async fn ask_pluginned(
|
|
1765
|
+
client: &Store,
|
|
1766
|
+
question: &str,
|
|
1767
|
+
args: serde_json::Value,
|
|
1768
|
+
) -> serde_json::Value {
|
|
1769
|
+
let (wasm, ir) = pluginned();
|
|
1770
|
+
let asked = serde_json::json!({ "query": question, "args": args });
|
|
1771
|
+
crate::query_step::answer(&asked, Some(&ir), "Pluginned", client, &wasm)
|
|
1772
|
+
.await
|
|
1773
|
+
.unwrap()
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
/// A query a wasm plugin answers, end to end: a command through the real kernel stores the
|
|
1777
|
+
/// ledger, and the query step hands the plugin that record's state, read back from Postgres.
|
|
1778
|
+
#[tokio::test]
|
|
1779
|
+
async fn a_plugin_answers_with_the_referenced_record_as_stored() {
|
|
1780
|
+
let client = scratch_db("rust_host_dispatch_test_plugin").await;
|
|
1781
|
+
provision_lineage(&*client.lock().await, "Pluginned", 1, &["Ledger"]).await;
|
|
1782
|
+
let (wasm, _) = pluginned();
|
|
1783
|
+
let config = test_config("Pluginned", 1);
|
|
1784
|
+
let opened = handle(
|
|
1785
|
+
Host::new(&client, &wasm, &config, &lambda_client::NeverInvoker),
|
|
1786
|
+
"Pluginned::Ledger.Open",
|
|
1787
|
+
serde_json::json!({ "name": { "value": "house" }, "note": { "value": "rent" } }),
|
|
1788
|
+
None,
|
|
1789
|
+
)
|
|
1790
|
+
.await
|
|
1791
|
+
.unwrap();
|
|
1792
|
+
assert!(
|
|
1793
|
+
opened.accepted,
|
|
1794
|
+
"opening the ledger: {}",
|
|
1795
|
+
opened.result["refusals"]
|
|
1796
|
+
);
|
|
1797
|
+
|
|
1798
|
+
let answer = ask_pluginned(
|
|
1799
|
+
&client,
|
|
1800
|
+
"Pluginned::Ledger.Doubled",
|
|
1801
|
+
serde_json::json!({ "entry": "house", "amount": 21 }),
|
|
1802
|
+
)
|
|
1803
|
+
.await;
|
|
1804
|
+
|
|
1805
|
+
assert_eq!(
|
|
1806
|
+
answer["queries"][0]["rows"],
|
|
1807
|
+
serde_json::json!([{ "amount": 42, "note": "rent" }])
|
|
1808
|
+
);
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1811
|
+
#[tokio::test]
|
|
1812
|
+
async fn a_plugin_refusal_and_a_missing_record_come_back_as_refusals() {
|
|
1813
|
+
let client = scratch_db("rust_host_dispatch_test_plugin_refusals").await;
|
|
1814
|
+
provision_lineage(&*client.lock().await, "Pluginned", 1, &["Ledger"]).await;
|
|
1815
|
+
|
|
1816
|
+
let refused = ask_pluginned(
|
|
1817
|
+
&client,
|
|
1818
|
+
"Pluginned::Ledger.Tripled",
|
|
1819
|
+
serde_json::json!({ "amount": 1 }),
|
|
1820
|
+
)
|
|
1821
|
+
.await;
|
|
1822
|
+
let missing = ask_pluginned(
|
|
1823
|
+
&client,
|
|
1824
|
+
"Pluginned::Ledger.Doubled",
|
|
1825
|
+
serde_json::json!({ "entry": "nowhere", "amount": 1 }),
|
|
1826
|
+
)
|
|
1827
|
+
.await;
|
|
1828
|
+
|
|
1829
|
+
assert_eq!(refused["refusals"][0]["kind"], "PluginRefusal");
|
|
1830
|
+
let refusal = refused["refusals"][0]["error"].as_str().unwrap();
|
|
1831
|
+
assert!(
|
|
1832
|
+
refusal.contains("doubler does not answer Pluginned::Ledger.Tripled"),
|
|
1833
|
+
"{refusal}"
|
|
1834
|
+
);
|
|
1835
|
+
assert_eq!(missing["refusals"][0]["kind"], "NotFound");
|
|
1836
|
+
assert_eq!(
|
|
1837
|
+
missing["refusals"][0]["error"],
|
|
1838
|
+
"entry: no Ledger \"nowhere\""
|
|
1839
|
+
);
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
|
|
1843
|
+
#[cfg(test)]
|
|
1844
|
+
mod preview_tests {
|
|
1845
|
+
use crate::dispatch_tests::tests::{memory_config, memory_store, register, wasm_path};
|
|
1846
|
+
use crate::host::Host;
|
|
1847
|
+
use crate::journal;
|
|
1848
|
+
use crate::lambda_client;
|
|
1849
|
+
use crate::store::{Accepted, DeadLetter, LineageWrite, Store, StoreExt, StoreFixtures};
|
|
1850
|
+
use crate::wasm_runner;
|
|
1851
|
+
use rust_host_core::dispatch::*;
|
|
1852
|
+
use std::path::Path;
|
|
1853
|
+
|
|
1854
|
+
// The client envelope a preview of `verb` answers for `invocation`.
|
|
1855
|
+
async fn preview_of(
|
|
1856
|
+
client: &Store,
|
|
1857
|
+
verb: &str,
|
|
1858
|
+
invocation: serde_json::Value,
|
|
1859
|
+
) -> serde_json::Value {
|
|
1860
|
+
let config = memory_config("Banking");
|
|
1861
|
+
let wasm = wasm_path();
|
|
1862
|
+
let host = Host::new(client, &wasm, &config, &lambda_client::NeverInvoker);
|
|
1863
|
+
let outcome = preview_as(host, verb, invocation, Caller::default())
|
|
1864
|
+
.await
|
|
1865
|
+
.unwrap();
|
|
1866
|
+
crate::validation::answer(&outcome.result)
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
async fn preview(client: &Store, facts: serde_json::Value) -> serde_json::Value {
|
|
1870
|
+
preview_of(
|
|
1871
|
+
client,
|
|
1872
|
+
"Banking::Customer.Register",
|
|
1873
|
+
facts_invocation(facts).unwrap(),
|
|
1874
|
+
)
|
|
1875
|
+
.await
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1878
|
+
async fn register_for_real(client: &Store, id: &str) -> Outcome {
|
|
1879
|
+
let config = memory_config("Banking");
|
|
1880
|
+
let wasm = wasm_path();
|
|
1881
|
+
let host = Host::new(client, &wasm, &config, &lambda_client::NeverInvoker);
|
|
1882
|
+
handle_facts(host, "Banking::Customer.Register", register(id), None)
|
|
1883
|
+
.await
|
|
1884
|
+
.unwrap()
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
#[tokio::test]
|
|
1888
|
+
async fn a_preview_of_an_acceptable_command_answers_ok_and_keeps_nothing() {
|
|
1889
|
+
let client = memory_store();
|
|
1890
|
+
assert_eq!(
|
|
1891
|
+
preview(&client, register("CUST-P1")).await,
|
|
1892
|
+
serde_json::json!({ "ok": true, "refusals": [] })
|
|
1893
|
+
);
|
|
1894
|
+
assert!(
|
|
1895
|
+
register_for_real(&client, "CUST-P1").await.accepted,
|
|
1896
|
+
"the preview left a record behind, so the real registration was refused"
|
|
1897
|
+
);
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
#[tokio::test]
|
|
1901
|
+
async fn a_preview_of_a_refused_command_answers_why_with_its_kind_and_stage() {
|
|
1902
|
+
let client = memory_store();
|
|
1903
|
+
register_for_real(&client, "CUST-P2").await;
|
|
1904
|
+
let answer = preview(&client, register("CUST-P2")).await;
|
|
1905
|
+
assert_eq!(answer["ok"], false);
|
|
1906
|
+
let refusal = &answer["refusals"][0];
|
|
1907
|
+
assert_eq!(refusal["refusal"], "AlreadyExists");
|
|
1908
|
+
assert_eq!(
|
|
1909
|
+
(refusal["kind"].as_str(), refusal["stage"].as_str()),
|
|
1910
|
+
(Some("refused"), Some("state"))
|
|
1911
|
+
);
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1914
|
+
#[tokio::test]
|
|
1915
|
+
async fn a_preview_names_an_unknown_argument_in_the_arguments_stage() {
|
|
1916
|
+
let client = memory_store();
|
|
1917
|
+
let mut facts = register("CUST-P3");
|
|
1918
|
+
facts["bogus"] = serde_json::json!(1);
|
|
1919
|
+
let answer = preview(&client, facts).await;
|
|
1920
|
+
let refusal = &answer["refusals"][0];
|
|
1921
|
+
assert_eq!(refusal["refusal"], "UnknownArgument");
|
|
1922
|
+
assert_eq!(refusal["stage"], "arguments");
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
#[tokio::test]
|
|
1926
|
+
async fn a_preview_against_an_existing_record_is_routed_to_it() {
|
|
1927
|
+
let client = memory_store();
|
|
1928
|
+
register_for_real(&client, "CUST-P4").await;
|
|
1929
|
+
let close = routed_invocation(serde_json::json!("CUST-P4"), serde_json::json!({})).unwrap();
|
|
1930
|
+
assert_eq!(
|
|
1931
|
+
preview_of(&client, "Banking::Customer.Close", close).await,
|
|
1932
|
+
serde_json::json!({ "ok": true, "refusals": [] })
|
|
1933
|
+
);
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
#[tokio::test]
|
|
1937
|
+
async fn a_preview_against_a_record_that_does_not_exist_is_kind_not_found() {
|
|
1938
|
+
let client = memory_store();
|
|
1939
|
+
let close = routed_invocation(serde_json::json!("NOBODY"), serde_json::json!({})).unwrap();
|
|
1940
|
+
let answer = preview_of(&client, "Banking::Customer.Close", close).await;
|
|
1941
|
+
assert_eq!(answer["ok"], false);
|
|
1942
|
+
assert_eq!(answer["refusals"][0]["kind"], "not_found");
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
// The body protocol: `"dry_run": true` beside a command, answered as the client envelope even
|
|
1946
|
+
// when the request also asks for `bare`.
|
|
1947
|
+
#[tokio::test]
|
|
1948
|
+
async fn the_body_protocol_answers_a_dry_run_as_the_client_envelope() {
|
|
1949
|
+
let client = memory_store();
|
|
1950
|
+
let config = memory_config("Banking");
|
|
1951
|
+
let wasm = wasm_path();
|
|
1952
|
+
let host = Host::new(&client, &wasm, &config, &lambda_client::NeverInvoker);
|
|
1953
|
+
let body = serde_json::json!({
|
|
1954
|
+
"verb": "Banking::Customer.Register", "with": register("CUST-P5"),
|
|
1955
|
+
"dry_run": true, "bare": true,
|
|
1956
|
+
});
|
|
1957
|
+
let answer = crate::server::dispatch_body(body, host).await.unwrap();
|
|
1958
|
+
assert_eq!(answer, serde_json::json!({ "ok": true, "refusals": [] }));
|
|
1959
|
+
}
|
|
2440
1960
|
}
|