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
|
@@ -4,12 +4,12 @@ use crate::clock::unix_now;
|
|
|
4
4
|
use crate::commerce_ir::{payments_provider, PaymentsProvider};
|
|
5
5
|
use crate::dispatch;
|
|
6
6
|
use crate::host::Host;
|
|
7
|
-
use crate::journal::LineageConfig;
|
|
8
7
|
use crate::payments;
|
|
8
|
+
use crate::store::journal_sql::LineageConfig;
|
|
9
|
+
use crate::store::Store;
|
|
9
10
|
use serde_json::{json, Value};
|
|
11
|
+
use std::collections::HashMap;
|
|
10
12
|
use std::path::Path;
|
|
11
|
-
use tokio::sync::Mutex;
|
|
12
|
-
use tokio_postgres::Client;
|
|
13
13
|
|
|
14
14
|
// Routes for /events, /registrations and /webhooks/stripe. Event and
|
|
15
15
|
// Registration names are fixed here rather than read from the IR.
|
|
@@ -44,8 +44,40 @@ fn payment_processor(read: &Value, payments: &PaymentsProvider, reference: &str)
|
|
|
44
44
|
// Payment statuses whose registration still holds a seat come from the
|
|
45
45
|
// payment lifecycle's `holds_seat` mark (`PaymentsProvider::holds_seat`). A
|
|
46
46
|
// registration with no Payment, or one in a state that frees its seat, holds none.
|
|
47
|
+
// A mock walkthrough payment still waiting to be settled holds none either: anyone may open
|
|
48
|
+
// one, nothing ever lapses it, and its seat is taken when it is settled instead.
|
|
47
49
|
|
|
48
|
-
///
|
|
50
|
+
/// The processor a Payment records when checkout is the mock walkthrough.
|
|
51
|
+
const MOCK_PROCESSOR: &str = "mock_stripe";
|
|
52
|
+
|
|
53
|
+
/// The status a Payment waits in until its processor settles it.
|
|
54
|
+
const PENDING: &str = "pending";
|
|
55
|
+
|
|
56
|
+
/// A Payment's `status`, when it has one.
|
|
57
|
+
fn payment_status(read: &Value, payments: &PaymentsProvider, reference: &str) -> Option<String> {
|
|
58
|
+
instances_for(read, &payments.instance_prefix())
|
|
59
|
+
.into_iter()
|
|
60
|
+
.find(|(id, _)| id == reference)
|
|
61
|
+
.and_then(|(_, payment)| {
|
|
62
|
+
payment
|
|
63
|
+
.get("status")
|
|
64
|
+
.and_then(|s| s.as_str())
|
|
65
|
+
.map(String::from)
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/// Whether a Payment holds its registration's seat: its status is one `holds_seat` lists, and
|
|
70
|
+
/// it is not a mock walkthrough payment still waiting to be settled.
|
|
71
|
+
fn payment_holds_seat(payment: &Value, payments: &PaymentsProvider) -> bool {
|
|
72
|
+
let Some(status) = payment.get("status").and_then(|s| s.as_str()) else {
|
|
73
|
+
return false;
|
|
74
|
+
};
|
|
75
|
+
let processor = plain_id(payment.get("processor"));
|
|
76
|
+
let waiting_walkthrough = status == PENDING && processor.as_deref() == Some(MOCK_PROCESSOR);
|
|
77
|
+
payments.holds_seat.iter().any(|held| held == status) && !waiting_walkthrough
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/// Whether a registration's own lifecycle state is one the bluebook declares gives its seat
|
|
49
81
|
/// back (`RegistrationsProvider::frees_seat`). A missing or non-text `status` is active.
|
|
50
82
|
fn registration_frees_seat(registration: &Value, frees_seat: &[String]) -> bool {
|
|
51
83
|
let status = registration.get("status").and_then(|s| s.as_str());
|
|
@@ -77,21 +109,15 @@ fn count_seats(
|
|
|
77
109
|
binding: &crate::commerce_ir::RegistrationsProvider,
|
|
78
110
|
payments: &PaymentsProvider,
|
|
79
111
|
) -> std::collections::HashMap<String, usize> {
|
|
80
|
-
let
|
|
112
|
+
let holding: std::collections::HashSet<String> =
|
|
81
113
|
instances_for(read, &payments.instance_prefix())
|
|
82
114
|
.into_iter()
|
|
83
|
-
.
|
|
84
|
-
|
|
85
|
-
.get("status")
|
|
86
|
-
.and_then(|s| s.as_str())
|
|
87
|
-
.map(|s| (id, s.to_string()))
|
|
88
|
-
})
|
|
115
|
+
.filter(|(_, payment)| payment_holds_seat(payment, payments))
|
|
116
|
+
.map(|(id, _)| id)
|
|
89
117
|
.collect();
|
|
90
118
|
let mut counts = std::collections::HashMap::new();
|
|
91
119
|
for (id, registration) in instances_for(read, &binding.registration_prefix()) {
|
|
92
|
-
let holds =
|
|
93
|
-
.get(&id)
|
|
94
|
-
.is_some_and(|status| payments.holds_seat.iter().any(|held| held == status));
|
|
120
|
+
let holds = holding.contains(&id);
|
|
95
121
|
let freed = registration_frees_seat(®istration, &binding.frees_seat);
|
|
96
122
|
if let (true, false, Some(event_slug)) =
|
|
97
123
|
(holds, freed, plain_id(registration.get("event_slug")))
|
|
@@ -226,12 +252,12 @@ fn seats_path_slug(path: &str) -> Option<&str> {
|
|
|
226
252
|
/// so a site never has to count registrations itself.
|
|
227
253
|
async fn seats_route(
|
|
228
254
|
path: &str,
|
|
229
|
-
|
|
255
|
+
store: &Store,
|
|
230
256
|
wasm_path: &Path,
|
|
231
257
|
config: &LineageConfig,
|
|
232
258
|
payments: &PaymentsProvider,
|
|
233
259
|
) -> Value {
|
|
234
|
-
let read = match dispatch::read(
|
|
260
|
+
let read = match dispatch::read(store, wasm_path).await {
|
|
235
261
|
Ok(r) => r,
|
|
236
262
|
Err(e) => return respond(500, "text/plain", &format!("{e:#}")),
|
|
237
263
|
};
|
|
@@ -259,22 +285,33 @@ pub(super) async fn payments_routes(
|
|
|
259
285
|
method: &str,
|
|
260
286
|
path: &str,
|
|
261
287
|
raw_body: &str,
|
|
262
|
-
|
|
288
|
+
request: &CheckoutRequest<'_>,
|
|
263
289
|
host: Host<'_>,
|
|
264
290
|
) -> Option<Value> {
|
|
265
|
-
let
|
|
266
|
-
|
|
291
|
+
let domain_ir = domain_ir?;
|
|
292
|
+
let payments = payments_provider(domain_ir)?;
|
|
293
|
+
checkout_route(method, path, raw_body, request, host, domain_ir, &payments).await
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/// What a checkout route reads off the request besides its method, path and body.
|
|
297
|
+
pub(super) struct CheckoutRequest<'a> {
|
|
298
|
+
/// The `Stripe-Signature` header, empty when absent.
|
|
299
|
+
pub stripe_signature: &'a str,
|
|
300
|
+
/// The request's cookies, which carry the account cookie POST /events checks.
|
|
301
|
+
pub cookies: &'a HashMap<String, String>,
|
|
267
302
|
}
|
|
303
|
+
|
|
268
304
|
pub(super) async fn checkout_route(
|
|
269
305
|
method: &str,
|
|
270
306
|
path: &str,
|
|
271
307
|
raw_body: &str,
|
|
272
|
-
|
|
308
|
+
request: &CheckoutRequest<'_>,
|
|
273
309
|
host: Host<'_>,
|
|
310
|
+
domain_ir: &Value,
|
|
274
311
|
payments: &PaymentsProvider,
|
|
275
312
|
) -> Option<Value> {
|
|
276
313
|
let Host {
|
|
277
|
-
|
|
314
|
+
store,
|
|
278
315
|
wasm_path,
|
|
279
316
|
config,
|
|
280
317
|
..
|
|
@@ -294,53 +331,155 @@ pub(super) async fn checkout_route(
|
|
|
294
331
|
// query string.
|
|
295
332
|
("GET", path) if path.starts_with("/registrations/") && !path.ends_with("/complete") => {
|
|
296
333
|
let registration_id = path.trim_start_matches("/registrations/");
|
|
297
|
-
Some(
|
|
298
|
-
registration_show_route(registration_id, client, wasm_path, config, payments).await,
|
|
299
|
-
)
|
|
334
|
+
Some(registration_show_route(registration_id, store, wasm_path, config, payments).await)
|
|
300
335
|
}
|
|
301
336
|
// POST /registrations/:id/complete: mock checkout's Pay/Cancel button,
|
|
302
|
-
// refused unless the Payment's own processor is
|
|
337
|
+
// refused unless checkout is the walkthrough and the Payment's own processor is
|
|
338
|
+
// "mock_stripe". Settles
|
|
303
339
|
// through the same PaymentGateway port as POST /webhooks/stripe.
|
|
304
340
|
("POST", path) if path.starts_with("/registrations/") && path.ends_with("/complete") => {
|
|
305
341
|
let registration_id = path
|
|
306
342
|
.trim_start_matches("/registrations/")
|
|
307
343
|
.trim_end_matches("/complete")
|
|
308
344
|
.trim_end_matches('/');
|
|
309
|
-
Some(
|
|
345
|
+
Some(
|
|
346
|
+
registration_complete_route(
|
|
347
|
+
registration_id,
|
|
348
|
+
raw_body,
|
|
349
|
+
&payments::PlatformConfig::load().await,
|
|
350
|
+
host,
|
|
351
|
+
payments,
|
|
352
|
+
)
|
|
353
|
+
.await,
|
|
354
|
+
)
|
|
310
355
|
}
|
|
311
356
|
("POST", "/webhooks/stripe") => Some(
|
|
312
357
|
webhook_route(
|
|
313
358
|
raw_body,
|
|
314
|
-
stripe_signature,
|
|
359
|
+
request.stripe_signature,
|
|
315
360
|
&payments::PlatformConfig::load().await,
|
|
316
361
|
host,
|
|
317
362
|
payments,
|
|
318
363
|
)
|
|
319
364
|
.await,
|
|
320
365
|
),
|
|
321
|
-
// POST /events: a mock-payments service schedules a new session
|
|
322
|
-
// when an editor picks a date. Idempotent — Event.find first means
|
|
323
|
-
// a repeat call for the same slug is a no-op, not an error.
|
|
324
366
|
("GET", "/events/seats") => {
|
|
325
|
-
Some(seats_route(path,
|
|
367
|
+
Some(seats_route(path, store, wasm_path, config, payments).await)
|
|
326
368
|
}
|
|
327
369
|
("GET", path) if seats_path_slug(path).is_some() => {
|
|
328
|
-
Some(seats_route(path,
|
|
370
|
+
Some(seats_route(path, store, wasm_path, config, payments).await)
|
|
329
371
|
}
|
|
330
|
-
|
|
372
|
+
// POST /events: an Admin or Owner schedules a new session by hand. The CMS schedules
|
|
373
|
+
// through the internal dispatch protocol instead, so this route answers no guest.
|
|
374
|
+
("POST", "/events") => Some(
|
|
375
|
+
events_route(
|
|
376
|
+
raw_body,
|
|
377
|
+
domain_ir,
|
|
378
|
+
request.cookies,
|
|
379
|
+
// Unset, it verifies no cookie, so every caller is refused.
|
|
380
|
+
&crate::secrets::var("SESSION_SECRET").unwrap_or_default(),
|
|
381
|
+
host,
|
|
382
|
+
)
|
|
383
|
+
.await,
|
|
384
|
+
),
|
|
331
385
|
_ => None,
|
|
332
386
|
}
|
|
333
387
|
}
|
|
334
388
|
|
|
335
|
-
///
|
|
336
|
-
///
|
|
337
|
-
async fn
|
|
389
|
+
/// The account cookie's person, when they are an active Admin or Owner; otherwise the 401 or 403
|
|
390
|
+
/// to answer. Read before anything else, so a refused caller learns nothing about the domain.
|
|
391
|
+
async fn require_admin_caller(
|
|
392
|
+
domain_ir: &Value,
|
|
393
|
+
cookies: &HashMap<String, String>,
|
|
394
|
+
secret: &str,
|
|
395
|
+
store: &Store,
|
|
396
|
+
) -> Result<String, Value> {
|
|
397
|
+
let Some(caller) = cookies
|
|
398
|
+
.get(&crate::auth::account_cookie_name())
|
|
399
|
+
.filter(|_| !secret.is_empty())
|
|
400
|
+
.and_then(|token| crate::auth::verify_account_token(secret, token))
|
|
401
|
+
else {
|
|
402
|
+
return Err(super::json_error(401, "not logged in"));
|
|
403
|
+
};
|
|
404
|
+
match crate::auth::caller_is_admin(store, domain_ir, &caller).await {
|
|
405
|
+
Ok(true) => Ok(caller),
|
|
406
|
+
Ok(false) => Err(super::json_error(403, "admins only")),
|
|
407
|
+
Err(e) => Err(super::json_error(
|
|
408
|
+
500,
|
|
409
|
+
&format!("members lookup failed: {e}"),
|
|
410
|
+
)),
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/// The fields POST /events schedules an event with, as `Event.Schedule` takes them.
|
|
415
|
+
fn schedule_args(body: &Value) -> Result<Value, Value> {
|
|
416
|
+
let missing = |field: &str| {
|
|
417
|
+
respond(
|
|
418
|
+
400,
|
|
419
|
+
"application/json",
|
|
420
|
+
&json!({"error": format!("missing {field}")}).to_string(),
|
|
421
|
+
)
|
|
422
|
+
};
|
|
423
|
+
let slug = body
|
|
424
|
+
.get("slug")
|
|
425
|
+
.and_then(|v| v.as_str())
|
|
426
|
+
.ok_or_else(|| missing("slug"))?;
|
|
427
|
+
let name = body
|
|
428
|
+
.get("name")
|
|
429
|
+
.and_then(|v| v.as_str())
|
|
430
|
+
.ok_or_else(|| missing("name"))?;
|
|
431
|
+
let price_cents = body
|
|
432
|
+
.get("price_cents")
|
|
433
|
+
.and_then(Value::as_i64)
|
|
434
|
+
.ok_or_else(|| missing("price_cents"))?;
|
|
435
|
+
let capacity = body
|
|
436
|
+
.get("capacity")
|
|
437
|
+
.and_then(Value::as_i64)
|
|
438
|
+
.ok_or_else(|| missing("capacity"))?;
|
|
439
|
+
Ok(json!({
|
|
440
|
+
"slug": {"value": slug},
|
|
441
|
+
"name": {"value": name},
|
|
442
|
+
"price": {"cents": price_cents},
|
|
443
|
+
"capacity": {"value": capacity},
|
|
444
|
+
}))
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/// Whether a scheduled event already carries the name, price and capacity of `args`. A
|
|
448
|
+
/// single-field value reads the same bare or wrapped as `{"value": ...}`.
|
|
449
|
+
fn schedules_the_same(event: &Value, args: &Value) -> bool {
|
|
450
|
+
let plain = |v: &Value, field: &str| {
|
|
451
|
+
v.get(field)
|
|
452
|
+
.map(|value| value.get("value").unwrap_or(value).clone())
|
|
453
|
+
};
|
|
454
|
+
let cents = |v: &Value| v.get("price").and_then(|p| p.get("cents")).cloned();
|
|
455
|
+
["name", "capacity"]
|
|
456
|
+
.iter()
|
|
457
|
+
.all(|field| plain(event, field) == plain(args, field))
|
|
458
|
+
&& cents(event) == cents(args)
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/// POST /events. Dispatches `<domain>::Event.Schedule` — Event is this deploy's own top-level
|
|
462
|
+
/// aggregate, not a vendored bluebook like Payments — for an active Admin or Owner holding the
|
|
463
|
+
/// account cookie. The host vouches for the caller as GET /registrations does and dispatches
|
|
464
|
+
/// host-internally: a member's role (Admin, Owner) is not one the domain's commands declare.
|
|
465
|
+
/// A repeat call for a scheduled slug answers the event as it stands when every field matches,
|
|
466
|
+
/// and 409 when any differs, so nobody can hold a slug at a price the editor never set.
|
|
467
|
+
async fn events_route(
|
|
468
|
+
raw_body: &str,
|
|
469
|
+
domain_ir: &Value,
|
|
470
|
+
cookies: &HashMap<String, String>,
|
|
471
|
+
secret: &str,
|
|
472
|
+
host: Host<'_>,
|
|
473
|
+
) -> Value {
|
|
338
474
|
let Host {
|
|
339
|
-
|
|
475
|
+
store,
|
|
340
476
|
wasm_path,
|
|
341
477
|
config,
|
|
342
478
|
..
|
|
343
479
|
} = host;
|
|
480
|
+
if let Err(response) = require_admin_caller(domain_ir, cookies, secret, store).await {
|
|
481
|
+
return response;
|
|
482
|
+
}
|
|
344
483
|
let body: Value = match serde_json::from_str(raw_body) {
|
|
345
484
|
Ok(v) => v,
|
|
346
485
|
Err(e) => {
|
|
@@ -351,15 +490,16 @@ async fn events_route(raw_body: &str, host: Host<'_>) -> Value {
|
|
|
351
490
|
)
|
|
352
491
|
}
|
|
353
492
|
};
|
|
354
|
-
let
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
"application/json",
|
|
358
|
-
&json!({"error": "missing slug"}).to_string(),
|
|
359
|
-
);
|
|
493
|
+
let args = match schedule_args(&body) {
|
|
494
|
+
Ok(args) => args,
|
|
495
|
+
Err(response) => return response,
|
|
360
496
|
};
|
|
497
|
+
let slug = args["slug"]["value"]
|
|
498
|
+
.as_str()
|
|
499
|
+
.unwrap_or_default()
|
|
500
|
+
.to_string();
|
|
361
501
|
|
|
362
|
-
let read = match dispatch::read(
|
|
502
|
+
let read = match dispatch::read(store, wasm_path).await {
|
|
363
503
|
Ok(r) => r,
|
|
364
504
|
Err(e) => return respond(500, "text/plain", &format!("{e:#}")),
|
|
365
505
|
};
|
|
@@ -367,42 +507,22 @@ async fn events_route(raw_body: &str, host: Host<'_>) -> Value {
|
|
|
367
507
|
&read,
|
|
368
508
|
&crate::commerce_ir::registrations_binding(&config.domain).event_prefix(),
|
|
369
509
|
);
|
|
370
|
-
if let Some((_, existing)) = events.iter().find(|(id, _)| id == slug) {
|
|
510
|
+
if let Some((_, existing)) = events.iter().find(|(id, _)| *id == slug) {
|
|
511
|
+
if !schedules_the_same(existing, &args) {
|
|
512
|
+
return respond(
|
|
513
|
+
409,
|
|
514
|
+
"application/json",
|
|
515
|
+
&json!({"error": "an event with this slug is already scheduled with other details"})
|
|
516
|
+
.to_string(),
|
|
517
|
+
);
|
|
518
|
+
}
|
|
371
519
|
return respond(
|
|
372
520
|
200,
|
|
373
521
|
"application/json",
|
|
374
|
-
&serde_json::to_string_pretty(&with_id(slug, existing)).unwrap_or_default(),
|
|
522
|
+
&serde_json::to_string_pretty(&with_id(&slug, existing)).unwrap_or_default(),
|
|
375
523
|
);
|
|
376
524
|
}
|
|
377
525
|
|
|
378
|
-
let Some(name) = body.get("name").and_then(|v| v.as_str()) else {
|
|
379
|
-
return respond(
|
|
380
|
-
400,
|
|
381
|
-
"application/json",
|
|
382
|
-
&json!({"error": "missing name"}).to_string(),
|
|
383
|
-
);
|
|
384
|
-
};
|
|
385
|
-
let Some(price_cents) = body.get("price_cents").and_then(serde_json::Value::as_i64) else {
|
|
386
|
-
return respond(
|
|
387
|
-
400,
|
|
388
|
-
"application/json",
|
|
389
|
-
&json!({"error": "missing price_cents"}).to_string(),
|
|
390
|
-
);
|
|
391
|
-
};
|
|
392
|
-
let Some(capacity) = body.get("capacity").and_then(serde_json::Value::as_i64) else {
|
|
393
|
-
return respond(
|
|
394
|
-
400,
|
|
395
|
-
"application/json",
|
|
396
|
-
&json!({"error": "missing capacity"}).to_string(),
|
|
397
|
-
);
|
|
398
|
-
};
|
|
399
|
-
|
|
400
|
-
let args = json!({
|
|
401
|
-
"slug": {"value": slug},
|
|
402
|
-
"name": {"value": name},
|
|
403
|
-
"price": {"cents": price_cents},
|
|
404
|
-
"capacity": {"value": capacity},
|
|
405
|
-
});
|
|
406
526
|
let verb = crate::commerce_ir::registrations_binding(&config.domain).schedule;
|
|
407
527
|
let outcome = match dispatch::handle(host, &verb, args, None).await {
|
|
408
528
|
Ok(o) => o,
|
|
@@ -416,7 +536,7 @@ async fn events_route(raw_body: &str, host: Host<'_>) -> Value {
|
|
|
416
536
|
);
|
|
417
537
|
}
|
|
418
538
|
|
|
419
|
-
let read = match dispatch::read(
|
|
539
|
+
let read = match dispatch::read(store, wasm_path).await {
|
|
420
540
|
Ok(r) => r,
|
|
421
541
|
Err(e) => return respond(500, "text/plain", &format!("{e:#}")),
|
|
422
542
|
};
|
|
@@ -424,7 +544,7 @@ async fn events_route(raw_body: &str, host: Host<'_>) -> Value {
|
|
|
424
544
|
&read,
|
|
425
545
|
&crate::commerce_ir::registrations_binding(&config.domain).event_prefix(),
|
|
426
546
|
);
|
|
427
|
-
let Some((_, event)) = events.iter().find(|(id, _)| id == slug) else {
|
|
547
|
+
let Some((_, event)) = events.iter().find(|(id, _)| *id == slug) else {
|
|
428
548
|
return respond(
|
|
429
549
|
500,
|
|
430
550
|
"text/plain",
|
|
@@ -434,20 +554,21 @@ async fn events_route(raw_body: &str, host: Host<'_>) -> Value {
|
|
|
434
554
|
respond(
|
|
435
555
|
201,
|
|
436
556
|
"application/json",
|
|
437
|
-
&serde_json::to_string_pretty(&with_id(slug, event)).unwrap_or_default(),
|
|
557
|
+
&serde_json::to_string_pretty(&with_id(&slug, event)).unwrap_or_default(),
|
|
438
558
|
)
|
|
439
559
|
}
|
|
440
560
|
|
|
441
|
-
/// GET /registrations/:id: event
|
|
442
|
-
///
|
|
561
|
+
/// GET /registrations/:id: the event, the attendee's name, and amount_cents and payment_status
|
|
562
|
+
/// from the same-reference Payment. Anyone holding the id may ask (it rides in the pay and
|
|
563
|
+
/// confirmation URLs), so the answer carries no contact detail: no email, no phone.
|
|
443
564
|
async fn registration_show_route(
|
|
444
565
|
registration_id: &str,
|
|
445
|
-
|
|
566
|
+
store: &Store,
|
|
446
567
|
wasm_path: &Path,
|
|
447
568
|
config: &LineageConfig,
|
|
448
569
|
payments: &PaymentsProvider,
|
|
449
570
|
) -> Value {
|
|
450
|
-
let read = match dispatch::read(
|
|
571
|
+
let read = match dispatch::read(store, wasm_path).await {
|
|
451
572
|
Ok(r) => r,
|
|
452
573
|
Err(e) => return respond(500, "text/plain", &format!("{e:#}")),
|
|
453
574
|
};
|
|
@@ -490,24 +611,26 @@ async fn registration_show_route(
|
|
|
490
611
|
"attendee": {
|
|
491
612
|
"first_name": attendee.get("first_name"),
|
|
492
613
|
"last_name": attendee.get("last_name"),
|
|
493
|
-
"email": attendee.get("email"),
|
|
494
|
-
"phone": attendee.get("phone"),
|
|
495
614
|
},
|
|
496
615
|
"amount_cents": payment.and_then(|p| p.get("amount")).and_then(|a| a.get("cents")),
|
|
497
616
|
"payment_status": payment.and_then(|p| p.get("status")),
|
|
498
617
|
}).to_string())
|
|
499
618
|
}
|
|
500
619
|
|
|
501
|
-
/// POST /registrations/:id/complete. Refused unless the
|
|
502
|
-
/// initiated on "mock_stripe"
|
|
620
|
+
/// POST /registrations/:id/complete. Refused unless checkout is the mock walkthrough right now
|
|
621
|
+
/// and the Payment itself was initiated on "mock_stripe", so a walkthrough payment left over from
|
|
622
|
+
/// before real payments were switched on can never be settled for free; settles through the same
|
|
623
|
+
/// PaymentGateway port webhook_route uses. A walkthrough payment holds no seat while it waits, so
|
|
624
|
+
/// a success takes the seat here and is refused when the event has none left.
|
|
503
625
|
pub(crate) async fn registration_complete_route(
|
|
504
626
|
registration_id: &str,
|
|
505
627
|
raw_body: &str,
|
|
628
|
+
platform: &payments::PlatformConfig,
|
|
506
629
|
host: Host<'_>,
|
|
507
630
|
payments: &PaymentsProvider,
|
|
508
631
|
) -> Value {
|
|
509
632
|
let Host {
|
|
510
|
-
|
|
633
|
+
store,
|
|
511
634
|
wasm_path,
|
|
512
635
|
config,
|
|
513
636
|
..
|
|
@@ -537,7 +660,7 @@ pub(crate) async fn registration_complete_route(
|
|
|
537
660
|
);
|
|
538
661
|
}
|
|
539
662
|
|
|
540
|
-
let read = match dispatch::read(
|
|
663
|
+
let read = match dispatch::read(store, wasm_path).await {
|
|
541
664
|
Ok(r) => r,
|
|
542
665
|
Err(e) => return respond(500, "text/plain", &format!("{e:#}")),
|
|
543
666
|
};
|
|
@@ -545,16 +668,23 @@ pub(crate) async fn registration_complete_route(
|
|
|
545
668
|
&read,
|
|
546
669
|
&crate::commerce_ir::registrations_binding(&config.domain).registration_prefix(),
|
|
547
670
|
);
|
|
548
|
-
|
|
671
|
+
let Some((_, registration)) = registrations.iter().find(|(id, _)| id == registration_id) else {
|
|
549
672
|
return respond(
|
|
550
673
|
404,
|
|
551
674
|
"application/json",
|
|
552
675
|
&json!({"error": "no such registration"}).to_string(),
|
|
553
676
|
);
|
|
554
|
-
}
|
|
677
|
+
};
|
|
555
678
|
|
|
679
|
+
let walkthrough = matches!(
|
|
680
|
+
payments::checkout_plan(
|
|
681
|
+
payments::connection(&read, &config.domain).as_ref(),
|
|
682
|
+
platform
|
|
683
|
+
),
|
|
684
|
+
payments::CheckoutPlan::Mock
|
|
685
|
+
);
|
|
556
686
|
let processor = match payment_processor(&read, payments, registration_id) {
|
|
557
|
-
Some(processor) if processor ==
|
|
687
|
+
Some(processor) if walkthrough && processor == MOCK_PROCESSOR => processor,
|
|
558
688
|
_ => {
|
|
559
689
|
return respond(
|
|
560
690
|
403,
|
|
@@ -563,6 +693,18 @@ pub(crate) async fn registration_complete_route(
|
|
|
563
693
|
)
|
|
564
694
|
}
|
|
565
695
|
};
|
|
696
|
+
let event_slug = plain_id(registration.get("event_slug")).unwrap_or_default();
|
|
697
|
+
let waiting = payment_status(&read, payments, registration_id).as_deref() == Some(PENDING);
|
|
698
|
+
if outcome == "succeeded"
|
|
699
|
+
&& waiting
|
|
700
|
+
&& seats_left(&read, &config.domain, payments, &event_slug) == Some(0)
|
|
701
|
+
{
|
|
702
|
+
return respond(
|
|
703
|
+
409,
|
|
704
|
+
"application/json",
|
|
705
|
+
&json!({"error": "this event is full"}).to_string(),
|
|
706
|
+
);
|
|
707
|
+
}
|
|
566
708
|
let reported_processor = json!({"value": processor});
|
|
567
709
|
// `reference_to Payment, as: :reference` keeps `reference` inside `with:`
|
|
568
710
|
// too — `to:` alone isn't enough, the argument parser still expects it
|
|
@@ -604,7 +746,7 @@ pub(crate) async fn registration_complete_route(
|
|
|
604
746
|
super::registration_receipt::deliver_receipt(registration_id, host, payments).await;
|
|
605
747
|
}
|
|
606
748
|
|
|
607
|
-
let read = match dispatch::read(
|
|
749
|
+
let read = match dispatch::read(store, wasm_path).await {
|
|
608
750
|
Ok(r) => r,
|
|
609
751
|
Err(e) => return respond(500, "text/plain", &format!("{e:#}")),
|
|
610
752
|
};
|
|
@@ -669,7 +811,7 @@ pub(crate) async fn registrations_route_at(
|
|
|
669
811
|
now_secs: i64,
|
|
670
812
|
) -> Value {
|
|
671
813
|
let Host {
|
|
672
|
-
|
|
814
|
+
store,
|
|
673
815
|
wasm_path,
|
|
674
816
|
config,
|
|
675
817
|
..
|
|
@@ -709,7 +851,7 @@ pub(crate) async fn registrations_route_at(
|
|
|
709
851
|
);
|
|
710
852
|
};
|
|
711
853
|
|
|
712
|
-
let read = match dispatch::read(
|
|
854
|
+
let read = match dispatch::read(store, wasm_path).await {
|
|
713
855
|
Ok(r) => r,
|
|
714
856
|
Err(e) => return respond(500, "text/plain", &format!("{e:#}")),
|
|
715
857
|
};
|
|
@@ -762,14 +904,14 @@ pub(crate) async fn registrations_route_at(
|
|
|
762
904
|
.unwrap_or("");
|
|
763
905
|
|
|
764
906
|
// What checkout does is decided per request from this tenant's own
|
|
765
|
-
// PaymentConnection, before anything is written — a
|
|
766
|
-
// must never fall back to the mock walkthrough.
|
|
907
|
+
// PaymentConnection, before anything is written — a connection that is
|
|
908
|
+
// not enabled must never fall back to the mock walkthrough.
|
|
767
909
|
let plan = payments::checkout_plan(
|
|
768
910
|
payments::connection(&read, &config.domain).as_ref(),
|
|
769
911
|
platform,
|
|
770
912
|
);
|
|
771
913
|
let processor = match plan {
|
|
772
|
-
payments::CheckoutPlan::Mock =>
|
|
914
|
+
payments::CheckoutPlan::Mock => MOCK_PROCESSOR,
|
|
773
915
|
payments::CheckoutPlan::Stripe { .. } => "stripe",
|
|
774
916
|
payments::CheckoutPlan::Paused => {
|
|
775
917
|
return respond(
|
|
@@ -889,12 +1031,17 @@ pub(crate) async fn registrations_route_at(
|
|
|
889
1031
|
&last_refusal(&outcome.result).to_string(),
|
|
890
1032
|
);
|
|
891
1033
|
}
|
|
1034
|
+
if let Some(full) =
|
|
1035
|
+
give_back_an_oversold_seat(&reference, event_slug, processor, host, payments).await
|
|
1036
|
+
{
|
|
1037
|
+
return full;
|
|
1038
|
+
}
|
|
892
1039
|
|
|
893
1040
|
// The domain's reaction has already subscribed the address by now; a
|
|
894
1041
|
// registrant who ticked the box gets the same signed confirm link as the
|
|
895
1042
|
// footer form. Best effort: the registration stands whatever mail does.
|
|
896
1043
|
if forwards_newsletter && news_signup {
|
|
897
|
-
super::newsletter::send_confirmation_if_pending(email,
|
|
1044
|
+
super::newsletter::send_confirmation_if_pending(email, store, wasm_path).await;
|
|
898
1045
|
}
|
|
899
1046
|
|
|
900
1047
|
if let Some(embedded) = embedded_checkout {
|
|
@@ -932,8 +1079,8 @@ pub(crate) async fn registrations_route_at(
|
|
|
932
1079
|
confirm_query("cancelled")
|
|
933
1080
|
);
|
|
934
1081
|
|
|
935
|
-
// A tenant with no connection
|
|
936
|
-
//
|
|
1082
|
+
// A tenant with no connection is on the mock walkthrough, never a
|
|
1083
|
+
// misconfiguration to refuse. success_url/cancel_url
|
|
937
1084
|
// belong to this walkthrough only — an embedded session redirects nowhere.
|
|
938
1085
|
let checkout_url =
|
|
939
1086
|
checkout::mock_checkout_session(&reference, &success_url, &cancel_url, site_url);
|
|
@@ -944,6 +1091,61 @@ pub(crate) async fn registrations_route_at(
|
|
|
944
1091
|
)
|
|
945
1092
|
}
|
|
946
1093
|
|
|
1094
|
+
/// The failure reason a Payment records when its registration lost the event's last seat.
|
|
1095
|
+
const EVENT_FULL_REASON: &str = "event_full";
|
|
1096
|
+
|
|
1097
|
+
/// The seat check of POST /registrations, made again once its Payment and Registration are
|
|
1098
|
+
/// written: the first check and these writes are seconds apart (a Stripe session opens in
|
|
1099
|
+
/// between), so two guests can both pass it for the last seat. When the event now holds more
|
|
1100
|
+
/// registrations than seats, this one's Payment fails, which gives its seat back, and the answer
|
|
1101
|
+
/// is the 409 of a full event. When both racers see the overflow both give their seat back,
|
|
1102
|
+
/// which leaves a seat open rather than one too many taken.
|
|
1103
|
+
async fn give_back_an_oversold_seat(
|
|
1104
|
+
reference: &str,
|
|
1105
|
+
event_slug: &str,
|
|
1106
|
+
processor: &str,
|
|
1107
|
+
host: Host<'_>,
|
|
1108
|
+
payments: &PaymentsProvider,
|
|
1109
|
+
) -> Option<Value> {
|
|
1110
|
+
let Host {
|
|
1111
|
+
store,
|
|
1112
|
+
wasm_path,
|
|
1113
|
+
config,
|
|
1114
|
+
..
|
|
1115
|
+
} = host;
|
|
1116
|
+
let read = match dispatch::read(store, wasm_path).await {
|
|
1117
|
+
Ok(r) => r,
|
|
1118
|
+
Err(e) => return Some(respond(500, "text/plain", &format!("{e:#}"))),
|
|
1119
|
+
};
|
|
1120
|
+
let events = instances_for(
|
|
1121
|
+
&read,
|
|
1122
|
+
&crate::commerce_ir::registrations_binding(&config.domain).event_prefix(),
|
|
1123
|
+
);
|
|
1124
|
+
let capacity = events
|
|
1125
|
+
.iter()
|
|
1126
|
+
.find(|(id, _)| id == event_slug)
|
|
1127
|
+
.and_then(|(_, event)| event_capacity(event))?;
|
|
1128
|
+
let taken = seats_taken(&read, &config.domain, payments, event_slug);
|
|
1129
|
+
if taken as i64 <= capacity {
|
|
1130
|
+
return None;
|
|
1131
|
+
}
|
|
1132
|
+
let facts = json!({
|
|
1133
|
+
"reference": {"value": reference},
|
|
1134
|
+
"reason": {"value": EVENT_FULL_REASON},
|
|
1135
|
+
"reported_processor": {"value": processor},
|
|
1136
|
+
});
|
|
1137
|
+
if let Err(e) =
|
|
1138
|
+
dispatch::handle_routed(host, &payments.failed, json!(reference), facts, None).await
|
|
1139
|
+
{
|
|
1140
|
+
return Some(respond(500, "text/plain", &format!("{e:#}")));
|
|
1141
|
+
}
|
|
1142
|
+
Some(respond(
|
|
1143
|
+
409,
|
|
1144
|
+
"application/json",
|
|
1145
|
+
&json!({"error": "this event is full"}).to_string(),
|
|
1146
|
+
))
|
|
1147
|
+
}
|
|
1148
|
+
|
|
947
1149
|
// The answer for an event that only the public mock secret could vouch for.
|
|
948
1150
|
fn mock_secret_refused() -> Value {
|
|
949
1151
|
respond(
|
|
@@ -955,6 +1157,81 @@ fn mock_secret_refused() -> Value {
|
|
|
955
1157
|
)
|
|
956
1158
|
}
|
|
957
1159
|
|
|
1160
|
+
/// Whether a Checkout Session collected what its Payment asked for: Stripe reports it `paid`, for
|
|
1161
|
+
/// the Payment's amount, in its currency. A session paid by a delayed method (a bank debit)
|
|
1162
|
+
/// completes `unpaid` and is settled later by `checkout.session.async_payment_succeeded`.
|
|
1163
|
+
fn session_collected(session: &Value, payment: Option<&Value>) -> bool {
|
|
1164
|
+
let Some(amount) = payment.and_then(|p| p.get("amount")) else {
|
|
1165
|
+
return false;
|
|
1166
|
+
};
|
|
1167
|
+
let lower = |v: Option<&Value>| v.and_then(Value::as_str).map(str::to_lowercase);
|
|
1168
|
+
let asked_currency =
|
|
1169
|
+
lower(amount.get("currency")).unwrap_or_else(|| checkout::CURRENCY.to_string());
|
|
1170
|
+
let paid = session.get("payment_status").and_then(Value::as_str) == Some("paid");
|
|
1171
|
+
let asked_cents = amount.get("cents").and_then(Value::as_i64);
|
|
1172
|
+
paid && asked_cents.is_some()
|
|
1173
|
+
&& session.get("amount_total").and_then(Value::as_i64) == asked_cents
|
|
1174
|
+
&& lower(session.get("currency")) == Some(asked_currency)
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
/// What one Checkout Session event settles, as the port operation and its facts. A session that
|
|
1178
|
+
/// collected the Payment's money succeeds it; one that expired, or whose delayed payment failed,
|
|
1179
|
+
/// fails it. A session not yet paid, or paid a sum other than the Payment's, settles nothing: the
|
|
1180
|
+
/// mismatch is logged for the business to reconcile. A mock walkthrough payment settles on the
|
|
1181
|
+
/// event alone, since the mock webhook carries no amounts and the walkthrough charges nothing.
|
|
1182
|
+
fn settlement<'a>(
|
|
1183
|
+
event_type: &str,
|
|
1184
|
+
session: &Value,
|
|
1185
|
+
payment: Option<&Value>,
|
|
1186
|
+
reference_fact: &Value,
|
|
1187
|
+
reported_processor: &Value,
|
|
1188
|
+
payments: &'a PaymentsProvider,
|
|
1189
|
+
) -> Option<(&'a str, Value)> {
|
|
1190
|
+
let fail = |reason: &str| {
|
|
1191
|
+
Some((
|
|
1192
|
+
payments.failed.as_str(),
|
|
1193
|
+
json!({"reference": reference_fact, "reason": {"value": reason}, "reported_processor": reported_processor}),
|
|
1194
|
+
))
|
|
1195
|
+
};
|
|
1196
|
+
match event_type {
|
|
1197
|
+
"checkout.session.completed" | "checkout.session.async_payment_succeeded" => {
|
|
1198
|
+
let walkthrough = reported_processor["value"] == MOCK_PROCESSOR;
|
|
1199
|
+
if !walkthrough && !session_collected(session, payment) {
|
|
1200
|
+
if session.get("payment_status").and_then(Value::as_str) == Some("paid") {
|
|
1201
|
+
eprintln!(
|
|
1202
|
+
"webhook: a paid Checkout Session does not match its Payment's amount, so it was not settled: {}",
|
|
1203
|
+
reference_fact["value"]
|
|
1204
|
+
);
|
|
1205
|
+
}
|
|
1206
|
+
return None;
|
|
1207
|
+
}
|
|
1208
|
+
// The PaymentIntent id when one exists, else the Checkout
|
|
1209
|
+
// Session's own id — `.get`, not a panic, since a synthetic
|
|
1210
|
+
// test payload carries no payment_intent at all.
|
|
1211
|
+
let transaction_id = session
|
|
1212
|
+
.get("payment_intent")
|
|
1213
|
+
.and_then(|v| v.as_str())
|
|
1214
|
+
.or_else(|| session.get("id").and_then(|v| v.as_str()))
|
|
1215
|
+
.unwrap_or("")
|
|
1216
|
+
.to_string();
|
|
1217
|
+
Some((
|
|
1218
|
+
payments.succeeded.as_str(),
|
|
1219
|
+
json!({
|
|
1220
|
+
"reference": reference_fact,
|
|
1221
|
+
"transaction_id": {"value": transaction_id},
|
|
1222
|
+
"reported_processor": reported_processor,
|
|
1223
|
+
}),
|
|
1224
|
+
))
|
|
1225
|
+
}
|
|
1226
|
+
"checkout.session.expired" => fail(&payments.lapse_reason),
|
|
1227
|
+
"checkout.session.async_payment_failed" => fail(ASYNC_PAYMENT_FAILED_REASON),
|
|
1228
|
+
_ => None,
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
/// The failure reason a Payment records when the processor reports its delayed payment failed.
|
|
1233
|
+
const ASYNC_PAYMENT_FAILED_REASON: &str = "async_payment_failed";
|
|
1234
|
+
|
|
958
1235
|
/// POST /webhooks/stripe. Verifies the signature against
|
|
959
1236
|
/// `STRIPE_WEBHOOK_SECRET`, a saved signing secret, or — only while neither
|
|
960
1237
|
/// is set — the public mock secret, refusing anything only a real processor
|
|
@@ -967,7 +1244,7 @@ pub(crate) async fn webhook_route(
|
|
|
967
1244
|
payments: &PaymentsProvider,
|
|
968
1245
|
) -> Value {
|
|
969
1246
|
let Host {
|
|
970
|
-
|
|
1247
|
+
store, wasm_path, ..
|
|
971
1248
|
} = host;
|
|
972
1249
|
let now = unix_now();
|
|
973
1250
|
// The environment's signing secret and any saved with the business's own
|
|
@@ -1000,7 +1277,7 @@ pub(crate) async fn webhook_route(
|
|
|
1000
1277
|
Err(_) => return respond(400, "text/plain", "invalid JSON"),
|
|
1001
1278
|
};
|
|
1002
1279
|
|
|
1003
|
-
let read = match dispatch::read(
|
|
1280
|
+
let read = match dispatch::read(store, wasm_path).await {
|
|
1004
1281
|
Ok(r) => r,
|
|
1005
1282
|
Err(e) => return respond(500, "text/plain", &format!("{e:#}")),
|
|
1006
1283
|
};
|
|
@@ -1028,7 +1305,7 @@ pub(crate) async fn webhook_route(
|
|
|
1028
1305
|
// Defaults to "stripe" when there's no matching Payment.
|
|
1029
1306
|
let processor =
|
|
1030
1307
|
payment_processor(&read, payments, &reference).unwrap_or_else(|| "stripe".to_string());
|
|
1031
|
-
if fallback_secret && processor !=
|
|
1308
|
+
if fallback_secret && processor != MOCK_PROCESSOR {
|
|
1032
1309
|
return refuse_fallback();
|
|
1033
1310
|
}
|
|
1034
1311
|
let reported_processor = json!({"value": processor});
|
|
@@ -1037,36 +1314,18 @@ pub(crate) async fn webhook_route(
|
|
|
1037
1314
|
// string, and `reference` stays inside `with:` too, since the
|
|
1038
1315
|
// argument parser still expects to find it in facts.
|
|
1039
1316
|
let reference_fact = json!({"value": reference.clone()});
|
|
1040
|
-
let
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
payments.succeeded.as_str(),
|
|
1053
|
-
json!({
|
|
1054
|
-
"reference": reference_fact,
|
|
1055
|
-
"transaction_id": {"value": transaction_id},
|
|
1056
|
-
"reported_processor": reported_processor,
|
|
1057
|
-
}),
|
|
1058
|
-
))
|
|
1059
|
-
}
|
|
1060
|
-
"checkout.session.expired" => Some((
|
|
1061
|
-
payments.failed.as_str(),
|
|
1062
|
-
json!({
|
|
1063
|
-
"reference": reference_fact,
|
|
1064
|
-
"reason": {"value": payments.lapse_reason},
|
|
1065
|
-
"reported_processor": reported_processor,
|
|
1066
|
-
}),
|
|
1067
|
-
)),
|
|
1068
|
-
_ => None,
|
|
1069
|
-
};
|
|
1317
|
+
let payment = instances_for(&read, &payments.instance_prefix())
|
|
1318
|
+
.into_iter()
|
|
1319
|
+
.find(|(id, _)| *id == reference)
|
|
1320
|
+
.map(|(_, payment)| payment);
|
|
1321
|
+
let verb_and_facts = settlement(
|
|
1322
|
+
event_type,
|
|
1323
|
+
&object,
|
|
1324
|
+
payment.as_ref(),
|
|
1325
|
+
&reference_fact,
|
|
1326
|
+
&reported_processor,
|
|
1327
|
+
payments,
|
|
1328
|
+
);
|
|
1070
1329
|
|
|
1071
1330
|
if let Some((verb, facts)) = verb_and_facts {
|
|
1072
1331
|
// A refusal here (e.g. a redelivered webhook — Stripe's delivery
|
|
@@ -1076,7 +1335,7 @@ pub(crate) async fn webhook_route(
|
|
|
1076
1335
|
Err(e) => return respond(500, "text/plain", &format!("{e:#}")),
|
|
1077
1336
|
// Only the delivery that settles the payment sends the receipt;
|
|
1078
1337
|
// a redelivery is refused and stays quiet.
|
|
1079
|
-
Ok(settled) if settled.accepted &&
|
|
1338
|
+
Ok(settled) if settled.accepted && verb == payments.succeeded => {
|
|
1080
1339
|
super::registration_receipt::deliver_receipt(&reference, host, payments).await;
|
|
1081
1340
|
}
|
|
1082
1341
|
Ok(_) => {}
|
|
@@ -1091,6 +1350,8 @@ pub(crate) async fn webhook_route(
|
|
|
1091
1350
|
mod tests {
|
|
1092
1351
|
use super::*;
|
|
1093
1352
|
use crate::lambda_client;
|
|
1353
|
+
#[allow(unused_imports)]
|
|
1354
|
+
use crate::store::StoreFixtures;
|
|
1094
1355
|
use crate::web::tests::{provision_lineage, scratch_db};
|
|
1095
1356
|
|
|
1096
1357
|
fn checkout_config(era: i32) -> LineageConfig {
|
|
@@ -1098,6 +1359,21 @@ mod tests {
|
|
|
1098
1359
|
domain: "CheckoutFixture".to_string(),
|
|
1099
1360
|
era: Some(era),
|
|
1100
1361
|
mirrored: None,
|
|
1362
|
+
seal_every: None,
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
fn checkout_memory_config() -> LineageConfig {
|
|
1367
|
+
crate::dispatch_tests::tests::memory_config("CheckoutFixture")
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
// A request with no Stripe signature and no cookies.
|
|
1371
|
+
fn no_request() -> CheckoutRequest<'static> {
|
|
1372
|
+
static NO_COOKIES: std::sync::LazyLock<HashMap<String, String>> =
|
|
1373
|
+
std::sync::LazyLock::new(HashMap::new);
|
|
1374
|
+
CheckoutRequest {
|
|
1375
|
+
stripe_signature: "",
|
|
1376
|
+
cookies: &NO_COOKIES,
|
|
1101
1377
|
}
|
|
1102
1378
|
}
|
|
1103
1379
|
|
|
@@ -1106,7 +1382,7 @@ mod tests {
|
|
|
1106
1382
|
}
|
|
1107
1383
|
|
|
1108
1384
|
async fn schedule_event(
|
|
1109
|
-
client: &
|
|
1385
|
+
client: &Store,
|
|
1110
1386
|
wasm_path: &Path,
|
|
1111
1387
|
config: &LineageConfig,
|
|
1112
1388
|
slug: &str,
|
|
@@ -1304,7 +1580,7 @@ mod tests {
|
|
|
1304
1580
|
}
|
|
1305
1581
|
|
|
1306
1582
|
#[test]
|
|
1307
|
-
fn
|
|
1583
|
+
fn a_state_the_bluebook_does_not_declare_keeps_its_seat_even_when_it_is_archived() {
|
|
1308
1584
|
let payments = crate::commerce_ir::fixture_payments();
|
|
1309
1585
|
let mut read = read_with(3, &[("a", "yoga", "succeeded")]);
|
|
1310
1586
|
set_registration_status(&mut read, "a", "archived");
|
|
@@ -1610,15 +1886,8 @@ mod tests {
|
|
|
1610
1886
|
|
|
1611
1887
|
#[tokio::test]
|
|
1612
1888
|
async fn the_seat_routes_answer_from_a_real_read_and_404_an_unknown_event() {
|
|
1613
|
-
let client =
|
|
1614
|
-
|
|
1615
|
-
&*client.lock().await,
|
|
1616
|
-
"CheckoutFixture",
|
|
1617
|
-
1,
|
|
1618
|
-
&["Event", "Registration", "Payment"],
|
|
1619
|
-
)
|
|
1620
|
-
.await;
|
|
1621
|
-
let config = checkout_config(1);
|
|
1889
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
1890
|
+
let config = checkout_memory_config();
|
|
1622
1891
|
let wasm_path = checkout_wasm_path();
|
|
1623
1892
|
schedule_event(&client, &wasm_path, &config, "yoga", 4200).await;
|
|
1624
1893
|
let ir = crate::commerce_ir::fixture_ir();
|
|
@@ -1630,7 +1899,7 @@ mod tests {
|
|
|
1630
1899
|
"GET",
|
|
1631
1900
|
path,
|
|
1632
1901
|
"",
|
|
1633
|
-
|
|
1902
|
+
&no_request(),
|
|
1634
1903
|
Host::new(client, wasm_path, config, &lambda_client::NeverInvoker),
|
|
1635
1904
|
)
|
|
1636
1905
|
.await
|
|
@@ -1749,14 +2018,7 @@ mod tests {
|
|
|
1749
2018
|
|
|
1750
2019
|
#[tokio::test]
|
|
1751
2020
|
async fn registrations_route_refuses_a_body_missing_any_required_field() {
|
|
1752
|
-
let client =
|
|
1753
|
-
provision_lineage(
|
|
1754
|
-
&*client.lock().await,
|
|
1755
|
-
"CheckoutFixture",
|
|
1756
|
-
1,
|
|
1757
|
-
&["Event", "Registration", "Payment"],
|
|
1758
|
-
)
|
|
1759
|
-
.await;
|
|
2021
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
1760
2022
|
|
|
1761
2023
|
let response = registrations_route(
|
|
1762
2024
|
r#"{"event_slug":"yoga-aug"}"#,
|
|
@@ -1764,7 +2026,7 @@ mod tests {
|
|
|
1764
2026
|
Host::new(
|
|
1765
2027
|
&client,
|
|
1766
2028
|
&checkout_wasm_path(),
|
|
1767
|
-
&
|
|
2029
|
+
&checkout_memory_config(),
|
|
1768
2030
|
&lambda_client::NeverInvoker,
|
|
1769
2031
|
),
|
|
1770
2032
|
&crate::commerce_ir::fixture_payments(),
|
|
@@ -1780,15 +2042,8 @@ mod tests {
|
|
|
1780
2042
|
#[tokio::test]
|
|
1781
2043
|
async fn registrations_route_forwards_a_new_shaped_attendee_verbatim_even_against_an_old_shaped_fixture(
|
|
1782
2044
|
) {
|
|
1783
|
-
let client =
|
|
1784
|
-
|
|
1785
|
-
&*client.lock().await,
|
|
1786
|
-
"CheckoutFixture",
|
|
1787
|
-
1,
|
|
1788
|
-
&["Event", "Registration", "Payment"],
|
|
1789
|
-
)
|
|
1790
|
-
.await;
|
|
1791
|
-
let config = checkout_config(1);
|
|
2045
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
2046
|
+
let config = checkout_memory_config();
|
|
1792
2047
|
let wasm_path = checkout_wasm_path();
|
|
1793
2048
|
|
|
1794
2049
|
schedule_event(&client, &wasm_path, &config, "happy-event", 4200).await;
|
|
@@ -1836,9 +2091,9 @@ mod tests {
|
|
|
1836
2091
|
// (the fixture's own IR) shows the same call is answered when it does.
|
|
1837
2092
|
#[tokio::test]
|
|
1838
2093
|
async fn payments_routes_serve_nothing_without_a_payments_capability() {
|
|
1839
|
-
let client =
|
|
2094
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
1840
2095
|
let wasm_path = checkout_wasm_path();
|
|
1841
|
-
let config =
|
|
2096
|
+
let config = checkout_memory_config();
|
|
1842
2097
|
let no_payments = json!({"name": "Studio"});
|
|
1843
2098
|
|
|
1844
2099
|
for (method, path) in [
|
|
@@ -1856,7 +2111,7 @@ mod tests {
|
|
|
1856
2111
|
method,
|
|
1857
2112
|
path,
|
|
1858
2113
|
"not json",
|
|
1859
|
-
|
|
2114
|
+
&no_request(),
|
|
1860
2115
|
Host::new(&client, &wasm_path, &config, &lambda_client::NeverInvoker),
|
|
1861
2116
|
)
|
|
1862
2117
|
.await;
|
|
@@ -1873,7 +2128,7 @@ mod tests {
|
|
|
1873
2128
|
"POST",
|
|
1874
2129
|
"/registrations",
|
|
1875
2130
|
"not json",
|
|
1876
|
-
|
|
2131
|
+
&no_request(),
|
|
1877
2132
|
Host::new(&client, &wasm_path, &config, &lambda_client::NeverInvoker),
|
|
1878
2133
|
)
|
|
1879
2134
|
.await;
|
|
@@ -1885,14 +2140,7 @@ mod tests {
|
|
|
1885
2140
|
|
|
1886
2141
|
#[tokio::test]
|
|
1887
2142
|
async fn registrations_route_refuses_invalid_json_outright() {
|
|
1888
|
-
let client =
|
|
1889
|
-
provision_lineage(
|
|
1890
|
-
&*client.lock().await,
|
|
1891
|
-
"CheckoutFixture",
|
|
1892
|
-
1,
|
|
1893
|
-
&["Event", "Registration", "Payment"],
|
|
1894
|
-
)
|
|
1895
|
-
.await;
|
|
2143
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
1896
2144
|
|
|
1897
2145
|
let response = registrations_route(
|
|
1898
2146
|
"not json",
|
|
@@ -1900,7 +2148,7 @@ mod tests {
|
|
|
1900
2148
|
Host::new(
|
|
1901
2149
|
&client,
|
|
1902
2150
|
&checkout_wasm_path(),
|
|
1903
|
-
&
|
|
2151
|
+
&checkout_memory_config(),
|
|
1904
2152
|
&lambda_client::NeverInvoker,
|
|
1905
2153
|
),
|
|
1906
2154
|
&crate::commerce_ir::fixture_payments(),
|
|
@@ -1909,43 +2157,116 @@ mod tests {
|
|
|
1909
2157
|
assert_eq!(response["statusCode"], 400);
|
|
1910
2158
|
}
|
|
1911
2159
|
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
provision_lineage(
|
|
1916
|
-
&*client.lock().await,
|
|
1917
|
-
"CheckoutFixture",
|
|
1918
|
-
1,
|
|
1919
|
-
&["Event", "Registration", "Payment"],
|
|
1920
|
-
)
|
|
1921
|
-
.await;
|
|
2160
|
+
const EVENTS_SECRET: &str = "s3cret";
|
|
2161
|
+
const EVENTS_ADMIN: &str = "admin@example.com";
|
|
2162
|
+
const EVENTS_MEMBER: &str = "member@example.com";
|
|
1922
2163
|
|
|
1923
|
-
|
|
1924
|
-
|
|
2164
|
+
// A scratch database with the fixture's lineage and a membership table holding one Admin
|
|
2165
|
+
// and one Member, and the domain IR that names that membership.
|
|
2166
|
+
async fn events_db(name: &str) -> (Store, Value) {
|
|
2167
|
+
let client = scratch_db(name).await;
|
|
2168
|
+
{
|
|
2169
|
+
let guard = client.lock().await;
|
|
2170
|
+
provision_lineage(
|
|
2171
|
+
&guard,
|
|
2172
|
+
"CheckoutFixture",
|
|
2173
|
+
1,
|
|
2174
|
+
&["Event", "Registration", "Payment"],
|
|
2175
|
+
)
|
|
2176
|
+
.await;
|
|
2177
|
+
guard
|
|
2178
|
+
.batch_execute(
|
|
2179
|
+
"CREATE TABLE acme_member_head_snapshot_1 (id text PRIMARY KEY, ordinal bigint NOT NULL, state jsonb NOT NULL);
|
|
2180
|
+
CREATE VIEW acme_member_head AS SELECT id, state FROM acme_member_head_snapshot_1;",
|
|
2181
|
+
)
|
|
2182
|
+
.await
|
|
2183
|
+
.unwrap();
|
|
2184
|
+
for (email, role) in [(EVENTS_ADMIN, "Admin"), (EVENTS_MEMBER, "Member")] {
|
|
2185
|
+
let state = json!({"email": {"value": email}, "role": {"value": role}});
|
|
2186
|
+
guard
|
|
2187
|
+
.execute(
|
|
2188
|
+
"INSERT INTO acme_member_head_snapshot_1 (id, ordinal, state) VALUES ($1, 0, $2::jsonb)",
|
|
2189
|
+
&[&email, &state],
|
|
2190
|
+
)
|
|
2191
|
+
.await
|
|
2192
|
+
.unwrap();
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
let domain_ir = json!({
|
|
2196
|
+
"name": "Acme",
|
|
2197
|
+
"lineage": {"capable_aggregates": [{"name": "Member", "storage_name": "member"}]},
|
|
2198
|
+
"membership": {"provider": "Acme", "aggregate": "Acme::Member"},
|
|
2199
|
+
});
|
|
2200
|
+
(client, domain_ir)
|
|
2201
|
+
}
|
|
2202
|
+
|
|
2203
|
+
// The cookies of a signed-in `email`, or none.
|
|
2204
|
+
fn events_cookies(email: Option<&str>) -> HashMap<String, String> {
|
|
2205
|
+
email
|
|
2206
|
+
.map(|email| {
|
|
2207
|
+
(
|
|
2208
|
+
crate::auth::account_cookie_name(),
|
|
2209
|
+
crate::auth::account_token(EVENTS_SECRET, email, 60),
|
|
2210
|
+
)
|
|
2211
|
+
})
|
|
2212
|
+
.into_iter()
|
|
2213
|
+
.collect()
|
|
2214
|
+
}
|
|
2215
|
+
|
|
2216
|
+
// POST /events as `email` (none: no account cookie).
|
|
2217
|
+
async fn post_event(
|
|
2218
|
+
client: &Store,
|
|
2219
|
+
domain_ir: &Value,
|
|
2220
|
+
email: Option<&str>,
|
|
2221
|
+
body: &str,
|
|
2222
|
+
) -> Value {
|
|
2223
|
+
events_route(
|
|
2224
|
+
body,
|
|
2225
|
+
domain_ir,
|
|
2226
|
+
&events_cookies(email),
|
|
2227
|
+
EVENTS_SECRET,
|
|
1925
2228
|
Host::new(
|
|
1926
|
-
|
|
2229
|
+
client,
|
|
1927
2230
|
&checkout_wasm_path(),
|
|
1928
2231
|
&checkout_config(1),
|
|
1929
2232
|
&lambda_client::NeverInvoker,
|
|
1930
2233
|
),
|
|
1931
2234
|
)
|
|
1932
|
-
.await
|
|
1933
|
-
|
|
2235
|
+
.await
|
|
2236
|
+
}
|
|
2237
|
+
|
|
2238
|
+
fn event_keys(read: &Value) -> Vec<String> {
|
|
2239
|
+
read["instances"]
|
|
2240
|
+
.as_object()
|
|
2241
|
+
.unwrap()
|
|
2242
|
+
.keys()
|
|
2243
|
+
.filter(|k| k.starts_with("CheckoutFixture::Event#"))
|
|
2244
|
+
.cloned()
|
|
2245
|
+
.collect()
|
|
1934
2246
|
}
|
|
1935
2247
|
|
|
2248
|
+
// A guest, a forged cookie and a signed-in Member are all refused before anything is read
|
|
2249
|
+
// or written: scheduling (and so pricing) a bookable event is an Admin's or Owner's.
|
|
1936
2250
|
#[tokio::test]
|
|
1937
|
-
async fn
|
|
1938
|
-
let client =
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
"CheckoutFixture",
|
|
1942
|
-
1,
|
|
1943
|
-
&["Event", "Registration", "Payment"],
|
|
1944
|
-
)
|
|
1945
|
-
.await;
|
|
2251
|
+
async fn events_route_schedules_nothing_for_anyone_but_an_active_admin() {
|
|
2252
|
+
let (client, domain_ir) = events_db("hecks_host_web_test_events_auth").await;
|
|
2253
|
+
let body = json!({"slug": "squat", "name": "Squatted", "price_cents": 1, "capacity": 999})
|
|
2254
|
+
.to_string();
|
|
1946
2255
|
|
|
1947
|
-
let
|
|
1948
|
-
|
|
2256
|
+
let guest = post_event(&client, &domain_ir, None, &body).await;
|
|
2257
|
+
assert_eq!(guest["statusCode"], 401, "{guest:?}");
|
|
2258
|
+
let member = post_event(&client, &domain_ir, Some(EVENTS_MEMBER), &body).await;
|
|
2259
|
+
assert_eq!(member["statusCode"], 403, "{member:?}");
|
|
2260
|
+
let mut forged = HashMap::new();
|
|
2261
|
+
forged.insert(
|
|
2262
|
+
crate::auth::account_cookie_name(),
|
|
2263
|
+
crate::auth::account_token("another-secret", EVENTS_ADMIN, 60),
|
|
2264
|
+
);
|
|
2265
|
+
let forged = events_route(
|
|
2266
|
+
&body,
|
|
2267
|
+
&domain_ir,
|
|
2268
|
+
&forged,
|
|
2269
|
+
EVENTS_SECRET,
|
|
1949
2270
|
Host::new(
|
|
1950
2271
|
&client,
|
|
1951
2272
|
&checkout_wasm_path(),
|
|
@@ -1954,29 +2275,43 @@ mod tests {
|
|
|
1954
2275
|
),
|
|
1955
2276
|
)
|
|
1956
2277
|
.await;
|
|
2278
|
+
assert_eq!(forged["statusCode"], 401, "{forged:?}");
|
|
2279
|
+
|
|
2280
|
+
let read = dispatch::read(&client, &checkout_wasm_path())
|
|
2281
|
+
.await
|
|
2282
|
+
.unwrap();
|
|
2283
|
+
assert!(
|
|
2284
|
+
event_keys(&read).is_empty(),
|
|
2285
|
+
"a refused caller scheduled an event"
|
|
2286
|
+
);
|
|
2287
|
+
}
|
|
2288
|
+
|
|
2289
|
+
#[tokio::test]
|
|
2290
|
+
async fn events_route_refuses_invalid_json_outright() {
|
|
2291
|
+
let (client, domain_ir) = events_db("hecks_host_web_test_events_bad_json").await;
|
|
2292
|
+
let response = post_event(&client, &domain_ir, Some(EVENTS_ADMIN), "not json").await;
|
|
1957
2293
|
assert_eq!(response["statusCode"], 400);
|
|
1958
|
-
assert!(response["body"].as_str().unwrap().contains("missing name"));
|
|
1959
2294
|
}
|
|
1960
2295
|
|
|
1961
2296
|
#[tokio::test]
|
|
1962
|
-
async fn
|
|
1963
|
-
let client =
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
2297
|
+
async fn events_route_refuses_a_body_missing_any_required_field() {
|
|
2298
|
+
let (client, domain_ir) = events_db("hecks_host_web_test_events_missing_fields").await;
|
|
2299
|
+
let response = post_event(
|
|
2300
|
+
&client,
|
|
2301
|
+
&domain_ir,
|
|
2302
|
+
Some(EVENTS_ADMIN),
|
|
2303
|
+
r#"{"slug":"new-event"}"#,
|
|
1969
2304
|
)
|
|
1970
2305
|
.await;
|
|
1971
|
-
|
|
1972
|
-
|
|
2306
|
+
assert_eq!(response["statusCode"], 400);
|
|
2307
|
+
assert!(response["body"].as_str().unwrap().contains("missing name"));
|
|
2308
|
+
}
|
|
1973
2309
|
|
|
2310
|
+
#[tokio::test]
|
|
2311
|
+
async fn events_route_schedules_a_new_event_and_returns_201() {
|
|
2312
|
+
let (client, domain_ir) = events_db("hecks_host_web_test_events_new").await;
|
|
1974
2313
|
let body = json!({"slug": "mock-payments-event", "name": "Mock Payments Event", "price_cents": 4200, "capacity": 20}).to_string();
|
|
1975
|
-
let response =
|
|
1976
|
-
&body,
|
|
1977
|
-
Host::new(&client, &wasm_path, &config, &lambda_client::NeverInvoker),
|
|
1978
|
-
)
|
|
1979
|
-
.await;
|
|
2314
|
+
let response = post_event(&client, &domain_ir, Some(EVENTS_ADMIN), &body).await;
|
|
1980
2315
|
assert_eq!(response["statusCode"], 201, "{response:?}");
|
|
1981
2316
|
let response_body: Value =
|
|
1982
2317
|
serde_json::from_str(response["body"].as_str().unwrap()).unwrap();
|
|
@@ -1986,77 +2321,98 @@ mod tests {
|
|
|
1986
2321
|
assert_eq!(response_body["capacity"]["value"], 20);
|
|
1987
2322
|
assert_eq!(response_body["status"], "open");
|
|
1988
2323
|
|
|
1989
|
-
let read = dispatch::read(&client, &
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
"Event.Schedule should have committed for real
|
|
2324
|
+
let read = dispatch::read(&client, &checkout_wasm_path())
|
|
2325
|
+
.await
|
|
2326
|
+
.unwrap();
|
|
2327
|
+
assert_eq!(
|
|
2328
|
+
event_keys(&read),
|
|
2329
|
+
vec!["CheckoutFixture::Event#mock-payments-event".to_string()],
|
|
2330
|
+
"Event.Schedule should have committed for real"
|
|
1996
2331
|
);
|
|
1997
2332
|
}
|
|
1998
2333
|
|
|
1999
|
-
// A repeat call
|
|
2000
|
-
//
|
|
2334
|
+
// A repeat call with the same fields is a 200 answering the existing event; one with other
|
|
2335
|
+
// fields is a 409 and changes nothing, so an early call cannot fix a slug's price.
|
|
2001
2336
|
#[tokio::test]
|
|
2002
|
-
async fn
|
|
2003
|
-
let client =
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2337
|
+
async fn events_route_answers_a_matching_repeat_and_refuses_a_different_one() {
|
|
2338
|
+
let (client, domain_ir) = events_db("hecks_host_web_test_events_idempotent").await;
|
|
2339
|
+
let body = json!({"slug": "repeat-event", "name": "Repeat Event", "price_cents": 1000, "capacity": 5}).to_string();
|
|
2340
|
+
let first = post_event(&client, &domain_ir, Some(EVENTS_ADMIN), &body).await;
|
|
2341
|
+
assert_eq!(first["statusCode"], 201, "{first:?}");
|
|
2342
|
+
|
|
2343
|
+
let again = post_event(&client, &domain_ir, Some(EVENTS_ADMIN), &body).await;
|
|
2344
|
+
assert_eq!(again["statusCode"], 200, "{again:?}");
|
|
2345
|
+
let different = json!({"slug": "repeat-event", "name": "Different Name", "price_cents": 9999, "capacity": 1}).to_string();
|
|
2346
|
+
let refused = post_event(&client, &domain_ir, Some(EVENTS_ADMIN), &different).await;
|
|
2347
|
+
assert_eq!(refused["statusCode"], 409, "{refused:?}");
|
|
2348
|
+
|
|
2349
|
+
let read = dispatch::read(&client, &checkout_wasm_path())
|
|
2350
|
+
.await
|
|
2351
|
+
.unwrap();
|
|
2352
|
+
assert_eq!(
|
|
2353
|
+
event_keys(&read).len(),
|
|
2007
2354
|
1,
|
|
2008
|
-
|
|
2009
|
-
)
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2355
|
+
"exactly one Event, never a second dispatch"
|
|
2356
|
+
);
|
|
2357
|
+
let event = &read["instances"]["CheckoutFixture::Event#repeat-event"];
|
|
2358
|
+
assert_eq!(
|
|
2359
|
+
event["price"]["cents"], 1000,
|
|
2360
|
+
"the refused repeat changed the price"
|
|
2361
|
+
);
|
|
2362
|
+
}
|
|
2013
2363
|
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2364
|
+
// The registration id rides in the pay and confirmation URLs (and so in Referer headers), so
|
|
2365
|
+
// whoever holds it may read the registration back, but never the attendee's contact details.
|
|
2366
|
+
#[tokio::test]
|
|
2367
|
+
async fn the_registration_read_back_by_id_carries_no_email_or_phone() {
|
|
2368
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
2369
|
+
let (config, wasm_path) = (checkout_memory_config(), checkout_wasm_path());
|
|
2370
|
+
schedule_event(&client, &wasm_path, &config, "show-event", 4200).await;
|
|
2371
|
+
let body =
|
|
2372
|
+
json!({"event_slug": "show-event", "name": "Ada Lovelace", "email": "ada@example.com"});
|
|
2373
|
+
let registered = registrations_route(
|
|
2374
|
+
&body.to_string(),
|
|
2375
|
+
&payments::test_platform(),
|
|
2017
2376
|
Host::new(&client, &wasm_path, &config, &lambda_client::NeverInvoker),
|
|
2377
|
+
&crate::commerce_ir::fixture_payments(),
|
|
2018
2378
|
)
|
|
2019
2379
|
.await;
|
|
2020
|
-
|
|
2380
|
+
let registered: Value = serde_json::from_str(registered["body"].as_str().unwrap()).unwrap();
|
|
2381
|
+
let id = registered["registration_id"]
|
|
2382
|
+
.as_str()
|
|
2383
|
+
.expect("a registration id");
|
|
2021
2384
|
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
&
|
|
2027
|
-
|
|
2385
|
+
let shown = registration_show_route(
|
|
2386
|
+
id,
|
|
2387
|
+
&client,
|
|
2388
|
+
&wasm_path,
|
|
2389
|
+
&config,
|
|
2390
|
+
&crate::commerce_ir::fixture_payments(),
|
|
2028
2391
|
)
|
|
2029
2392
|
.await;
|
|
2030
|
-
|
|
2031
|
-
|
|
2393
|
+
let shown_body = shown["body"].as_str().unwrap();
|
|
2394
|
+
assert_eq!(shown["statusCode"], 200, "{shown:?}");
|
|
2395
|
+
assert!(!shown_body.contains("ada@example.com"), "{shown_body}");
|
|
2396
|
+
let shown: Value = serde_json::from_str(shown_body).unwrap();
|
|
2032
2397
|
assert_eq!(
|
|
2033
|
-
|
|
2034
|
-
|
|
2398
|
+
(
|
|
2399
|
+
shown["attendee"].get("email"),
|
|
2400
|
+
shown["attendee"].get("phone")
|
|
2401
|
+
),
|
|
2402
|
+
(None, None)
|
|
2035
2403
|
);
|
|
2036
|
-
assert_eq!(second_body["price"]["cents"], 1000);
|
|
2037
|
-
|
|
2038
|
-
let read = dispatch::read(&client, &wasm_path).await.unwrap();
|
|
2039
|
-
let instances = read["instances"].as_object().unwrap();
|
|
2040
2404
|
assert_eq!(
|
|
2041
|
-
|
|
2042
|
-
.
|
|
2043
|
-
.
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
"exactly one Event, never a second dispatch: {instances:?}"
|
|
2405
|
+
(
|
|
2406
|
+
shown["amount_cents"].as_i64(),
|
|
2407
|
+
shown["payment_status"].as_str()
|
|
2408
|
+
),
|
|
2409
|
+
(Some(4200), Some("pending"))
|
|
2047
2410
|
);
|
|
2048
2411
|
}
|
|
2049
2412
|
|
|
2050
2413
|
#[tokio::test]
|
|
2051
2414
|
async fn registrations_route_404s_an_unknown_event_slug() {
|
|
2052
|
-
let client =
|
|
2053
|
-
provision_lineage(
|
|
2054
|
-
&*client.lock().await,
|
|
2055
|
-
"CheckoutFixture",
|
|
2056
|
-
1,
|
|
2057
|
-
&["Event", "Registration", "Payment"],
|
|
2058
|
-
)
|
|
2059
|
-
.await;
|
|
2415
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
2060
2416
|
|
|
2061
2417
|
let body =
|
|
2062
2418
|
json!({"event_slug": "nope", "name": "Ada", "email": "ada@example.com"}).to_string();
|
|
@@ -2066,7 +2422,7 @@ mod tests {
|
|
|
2066
2422
|
Host::new(
|
|
2067
2423
|
&client,
|
|
2068
2424
|
&checkout_wasm_path(),
|
|
2069
|
-
&
|
|
2425
|
+
&checkout_memory_config(),
|
|
2070
2426
|
&lambda_client::NeverInvoker,
|
|
2071
2427
|
),
|
|
2072
2428
|
&crate::commerce_ir::fixture_payments(),
|
|
@@ -2077,15 +2433,8 @@ mod tests {
|
|
|
2077
2433
|
|
|
2078
2434
|
#[tokio::test]
|
|
2079
2435
|
async fn registrations_route_refuses_a_closed_event() {
|
|
2080
|
-
let client =
|
|
2081
|
-
|
|
2082
|
-
&*client.lock().await,
|
|
2083
|
-
"CheckoutFixture",
|
|
2084
|
-
1,
|
|
2085
|
-
&["Event", "Registration", "Payment"],
|
|
2086
|
-
)
|
|
2087
|
-
.await;
|
|
2088
|
-
let config = checkout_config(1);
|
|
2436
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
2437
|
+
let config = checkout_memory_config();
|
|
2089
2438
|
let wasm_path = checkout_wasm_path();
|
|
2090
2439
|
|
|
2091
2440
|
schedule_event(&client, &wasm_path, &config, "closed-event", 4200).await;
|
|
@@ -2119,7 +2468,7 @@ mod tests {
|
|
|
2119
2468
|
// Schedules `slug` starting at `starts_at` with the optional cutoff set
|
|
2120
2469
|
// (or absent), through the real Event.Schedule command.
|
|
2121
2470
|
async fn schedule_timed_event(
|
|
2122
|
-
client: &
|
|
2471
|
+
client: &Store,
|
|
2123
2472
|
wasm_path: &Path,
|
|
2124
2473
|
config: &LineageConfig,
|
|
2125
2474
|
slug: &str,
|
|
@@ -2152,15 +2501,8 @@ mod tests {
|
|
|
2152
2501
|
#[tokio::test]
|
|
2153
2502
|
async fn registrations_route_refuses_a_session_inside_its_registration_cutoff_and_writes_nothing(
|
|
2154
2503
|
) {
|
|
2155
|
-
let client =
|
|
2156
|
-
|
|
2157
|
-
&*client.lock().await,
|
|
2158
|
-
"CheckoutFixture",
|
|
2159
|
-
1,
|
|
2160
|
-
&["Event", "Registration", "Payment"],
|
|
2161
|
-
)
|
|
2162
|
-
.await;
|
|
2163
|
-
let config = checkout_config(1);
|
|
2504
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
2505
|
+
let config = checkout_memory_config();
|
|
2164
2506
|
let wasm_path = checkout_wasm_path();
|
|
2165
2507
|
|
|
2166
2508
|
// Starts in 5 hours with a 6 hour cutoff: registration closed an hour ago.
|
|
@@ -2204,15 +2546,8 @@ mod tests {
|
|
|
2204
2546
|
|
|
2205
2547
|
#[tokio::test]
|
|
2206
2548
|
async fn registrations_route_accepts_a_session_with_no_cutoff_even_when_it_has_a_start() {
|
|
2207
|
-
let client =
|
|
2208
|
-
|
|
2209
|
-
&*client.lock().await,
|
|
2210
|
-
"CheckoutFixture",
|
|
2211
|
-
1,
|
|
2212
|
-
&["Event", "Registration", "Payment"],
|
|
2213
|
-
)
|
|
2214
|
-
.await;
|
|
2215
|
-
let config = checkout_config(1);
|
|
2549
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
2550
|
+
let config = checkout_memory_config();
|
|
2216
2551
|
let wasm_path = checkout_wasm_path();
|
|
2217
2552
|
|
|
2218
2553
|
// A start in the past and no cutoff field: nothing to enforce.
|
|
@@ -2320,15 +2655,8 @@ mod tests {
|
|
|
2320
2655
|
// A zero-price event: PositiveMoney's invariant refuses
|
|
2321
2656
|
// Payment.Initiate before Registration.Request is ever reached,
|
|
2322
2657
|
// proving the refusal is the real domain rule.
|
|
2323
|
-
let client =
|
|
2324
|
-
|
|
2325
|
-
&*client.lock().await,
|
|
2326
|
-
"CheckoutFixture",
|
|
2327
|
-
1,
|
|
2328
|
-
&["Event", "Registration", "Payment"],
|
|
2329
|
-
)
|
|
2330
|
-
.await;
|
|
2331
|
-
let config = checkout_config(1);
|
|
2658
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
2659
|
+
let config = checkout_memory_config();
|
|
2332
2660
|
let wasm_path = checkout_wasm_path();
|
|
2333
2661
|
|
|
2334
2662
|
schedule_event(&client, &wasm_path, &config, "free-event", 0).await;
|
|
@@ -2361,15 +2689,8 @@ mod tests {
|
|
|
2361
2689
|
#[tokio::test]
|
|
2362
2690
|
async fn registrations_route_runs_the_whole_dispatch_chain_and_returns_a_real_mock_checkout_url(
|
|
2363
2691
|
) {
|
|
2364
|
-
let client =
|
|
2365
|
-
|
|
2366
|
-
&*client.lock().await,
|
|
2367
|
-
"CheckoutFixture",
|
|
2368
|
-
1,
|
|
2369
|
-
&["Event", "Registration", "Payment"],
|
|
2370
|
-
)
|
|
2371
|
-
.await;
|
|
2372
|
-
let config = checkout_config(1);
|
|
2692
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
2693
|
+
let config = checkout_memory_config();
|
|
2373
2694
|
let wasm_path = checkout_wasm_path();
|
|
2374
2695
|
|
|
2375
2696
|
schedule_event(&client, &wasm_path, &config, "happy-event", 4200).await;
|
|
@@ -2437,15 +2758,8 @@ mod tests {
|
|
|
2437
2758
|
// 404ing every guest right after a successful, already-charged registration.
|
|
2438
2759
|
#[tokio::test]
|
|
2439
2760
|
async fn registrations_route_redirects_to_the_caller_s_own_return_to_not_the_event_slug() {
|
|
2440
|
-
let client =
|
|
2441
|
-
|
|
2442
|
-
&*client.lock().await,
|
|
2443
|
-
"CheckoutFixture",
|
|
2444
|
-
1,
|
|
2445
|
-
&["Event", "Registration", "Payment"],
|
|
2446
|
-
)
|
|
2447
|
-
.await;
|
|
2448
|
-
let config = checkout_config(1);
|
|
2761
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
2762
|
+
let config = checkout_memory_config();
|
|
2449
2763
|
let wasm_path = checkout_wasm_path();
|
|
2450
2764
|
|
|
2451
2765
|
schedule_event(&client, &wasm_path, &config, "happy-event", 4200).await;
|
|
@@ -2479,15 +2793,8 @@ mod tests {
|
|
|
2479
2793
|
// redirect; falls back to "/" exactly as if none had been sent.
|
|
2480
2794
|
#[tokio::test]
|
|
2481
2795
|
async fn registrations_route_refuses_an_absolute_or_protocol_relative_return_to() {
|
|
2482
|
-
let client =
|
|
2483
|
-
|
|
2484
|
-
&*client.lock().await,
|
|
2485
|
-
"CheckoutFixture",
|
|
2486
|
-
1,
|
|
2487
|
-
&["Event", "Registration", "Payment"],
|
|
2488
|
-
)
|
|
2489
|
-
.await;
|
|
2490
|
-
let config = checkout_config(1);
|
|
2796
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
2797
|
+
let config = checkout_memory_config();
|
|
2491
2798
|
let wasm_path = checkout_wasm_path();
|
|
2492
2799
|
|
|
2493
2800
|
schedule_event(&client, &wasm_path, &config, "happy-event", 4200).await;
|
|
@@ -2531,15 +2838,8 @@ mod tests {
|
|
|
2531
2838
|
// The full loop, mock both ends: registrations_route's own
|
|
2532
2839
|
// checkout_url, then a webhook signed against the same mock secret
|
|
2533
2840
|
// webhook_route falls back to while STRIPE_WEBHOOK_SECRET is unset.
|
|
2534
|
-
let client =
|
|
2535
|
-
|
|
2536
|
-
&*client.lock().await,
|
|
2537
|
-
"CheckoutFixture",
|
|
2538
|
-
1,
|
|
2539
|
-
&["Event", "Registration", "Payment"],
|
|
2540
|
-
)
|
|
2541
|
-
.await;
|
|
2542
|
-
let config = checkout_config(1);
|
|
2841
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
2842
|
+
let config = checkout_memory_config();
|
|
2543
2843
|
let wasm_path = checkout_wasm_path();
|
|
2544
2844
|
|
|
2545
2845
|
schedule_event(&client, &wasm_path, &config, "mock-loop-event", 4200).await;
|
|
@@ -2589,14 +2889,7 @@ mod tests {
|
|
|
2589
2889
|
|
|
2590
2890
|
#[tokio::test]
|
|
2591
2891
|
async fn webhook_route_rejects_a_bad_signature_before_touching_the_domain_at_all() {
|
|
2592
|
-
let client =
|
|
2593
|
-
provision_lineage(
|
|
2594
|
-
&*client.lock().await,
|
|
2595
|
-
"CheckoutFixture",
|
|
2596
|
-
1,
|
|
2597
|
-
&["Event", "Registration", "Payment"],
|
|
2598
|
-
)
|
|
2599
|
-
.await;
|
|
2892
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
2600
2893
|
|
|
2601
2894
|
let payload =
|
|
2602
2895
|
json!({"type": "checkout.session.completed", "data": {"object": {}}}).to_string();
|
|
@@ -2609,7 +2902,7 @@ mod tests {
|
|
|
2609
2902
|
Host::new(
|
|
2610
2903
|
&client,
|
|
2611
2904
|
&checkout_wasm_path(),
|
|
2612
|
-
&
|
|
2905
|
+
&checkout_memory_config(),
|
|
2613
2906
|
&lambda_client::NeverInvoker,
|
|
2614
2907
|
),
|
|
2615
2908
|
&crate::commerce_ir::fixture_payments(),
|
|
@@ -2620,15 +2913,8 @@ mod tests {
|
|
|
2620
2913
|
|
|
2621
2914
|
#[tokio::test]
|
|
2622
2915
|
async fn webhook_route_settles_a_payment_on_checkout_session_completed() {
|
|
2623
|
-
let client =
|
|
2624
|
-
|
|
2625
|
-
&*client.lock().await,
|
|
2626
|
-
"CheckoutFixture",
|
|
2627
|
-
1,
|
|
2628
|
-
&["Event", "Registration", "Payment"],
|
|
2629
|
-
)
|
|
2630
|
-
.await;
|
|
2631
|
-
let config = checkout_config(1);
|
|
2916
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
2917
|
+
let config = checkout_memory_config();
|
|
2632
2918
|
let wasm_path = checkout_wasm_path();
|
|
2633
2919
|
|
|
2634
2920
|
schedule_event(&client, &wasm_path, &config, "webhook-event", 4200).await;
|
|
@@ -2649,8 +2935,12 @@ mod tests {
|
|
|
2649
2935
|
let secret = "whsec_test_completed";
|
|
2650
2936
|
let payload = json!({
|
|
2651
2937
|
"type": "checkout.session.completed",
|
|
2652
|
-
"data": {"object": {
|
|
2653
|
-
|
|
2938
|
+
"data": {"object": {
|
|
2939
|
+
"metadata": {"registration_id": "REG-WEBHOOK-1"}, "payment_intent": "pi_test_abc",
|
|
2940
|
+
"payment_status": "paid", "amount_total": 4200, "currency": "usd",
|
|
2941
|
+
}},
|
|
2942
|
+
})
|
|
2943
|
+
.to_string();
|
|
2654
2944
|
let now = now_secs();
|
|
2655
2945
|
let header = sign_stripe_header(secret, now, &payload);
|
|
2656
2946
|
|
|
@@ -2683,9 +2973,9 @@ mod tests {
|
|
|
2683
2973
|
assert_eq!(redelivered["statusCode"], 200, "a redelivered webhook must not surface the resulting refusal as an error: {redelivered:?}");
|
|
2684
2974
|
}
|
|
2685
2975
|
|
|
2686
|
-
|
|
2687
|
-
async fn
|
|
2688
|
-
let client = scratch_db(
|
|
2976
|
+
// A scratch fixture with a scheduled event and a pending 4200-cent Stripe Payment `reference`.
|
|
2977
|
+
async fn stripe_payment_db(name: &str, reference: &str) -> Store {
|
|
2978
|
+
let client = scratch_db(name).await;
|
|
2689
2979
|
provision_lineage(
|
|
2690
2980
|
&*client.lock().await,
|
|
2691
2981
|
"CheckoutFixture",
|
|
@@ -2693,7 +2983,103 @@ mod tests {
|
|
|
2693
2983
|
&["Event", "Registration", "Payment"],
|
|
2694
2984
|
)
|
|
2695
2985
|
.await;
|
|
2696
|
-
let config = checkout_config(1);
|
|
2986
|
+
let (config, wasm_path) = (checkout_config(1), checkout_wasm_path());
|
|
2987
|
+
schedule_event(&client, &wasm_path, &config, "webhook-event", 4200).await;
|
|
2988
|
+
let initiate = dispatch::handle(
|
|
2989
|
+
Host::new(&client, &wasm_path, &config, &lambda_client::NeverInvoker),
|
|
2990
|
+
"Payments::Payment.Initiate",
|
|
2991
|
+
json!({
|
|
2992
|
+
"reference": {"value": reference}, "processor": {"value": "stripe"},
|
|
2993
|
+
"payment_type": {"value": "card"}, "amount": {"cents": 4200},
|
|
2994
|
+
"client": {"name": "Ada Lovelace", "email": "ada@example.com"},
|
|
2995
|
+
}),
|
|
2996
|
+
None,
|
|
2997
|
+
)
|
|
2998
|
+
.await
|
|
2999
|
+
.unwrap();
|
|
3000
|
+
assert!(initiate.accepted, "{:?}", initiate.result);
|
|
3001
|
+
client
|
|
3002
|
+
}
|
|
3003
|
+
|
|
3004
|
+
// Delivers one signed Checkout Session event for `reference` and answers the Payment's status.
|
|
3005
|
+
async fn deliver_session_event(
|
|
3006
|
+
client: &Store,
|
|
3007
|
+
reference: &str,
|
|
3008
|
+
event_type: &str,
|
|
3009
|
+
session: Value,
|
|
3010
|
+
) -> Value {
|
|
3011
|
+
let secret = "whsec_test_session";
|
|
3012
|
+
let mut object = session;
|
|
3013
|
+
object["metadata"] = json!({"registration_id": reference});
|
|
3014
|
+
let payload = json!({"type": event_type, "data": {"object": object}}).to_string();
|
|
3015
|
+
let header = sign_stripe_header(secret, now_secs(), &payload);
|
|
3016
|
+
let (config, wasm_path) = (checkout_config(1), checkout_wasm_path());
|
|
3017
|
+
let response = webhook_route(
|
|
3018
|
+
&payload,
|
|
3019
|
+
&header,
|
|
3020
|
+
&payments::test_platform_with_secret(secret),
|
|
3021
|
+
Host::new(client, &wasm_path, &config, &lambda_client::NeverInvoker),
|
|
3022
|
+
&crate::commerce_ir::fixture_payments(),
|
|
3023
|
+
)
|
|
3024
|
+
.await;
|
|
3025
|
+
assert_eq!(response["statusCode"], 200, "{response:?}");
|
|
3026
|
+
let read = dispatch::read(client, &wasm_path).await.unwrap();
|
|
3027
|
+
read["instances"][format!("Payments::Payment#{reference}")]["status"].clone()
|
|
3028
|
+
}
|
|
3029
|
+
|
|
3030
|
+
// A completed session settles the Payment only when Stripe says it is paid, for the
|
|
3031
|
+
// Payment's amount, in its currency; a delayed method settles on its own later event.
|
|
3032
|
+
#[tokio::test]
|
|
3033
|
+
async fn webhook_route_settles_only_a_session_paid_in_full() {
|
|
3034
|
+
let reference = "REG-WEBHOOK-PAID";
|
|
3035
|
+
let client = stripe_payment_db("hecks_host_web_test_webhook_paid_in_full", reference).await;
|
|
3036
|
+
let completed = "checkout.session.completed";
|
|
3037
|
+
for (session, why) in [
|
|
3038
|
+
(
|
|
3039
|
+
json!({"payment_status": "unpaid", "amount_total": 4200, "currency": "usd"}),
|
|
3040
|
+
"a delayed method, not yet paid",
|
|
3041
|
+
),
|
|
3042
|
+
(
|
|
3043
|
+
json!({"payment_status": "paid", "amount_total": 100, "currency": "usd"}),
|
|
3044
|
+
"another amount",
|
|
3045
|
+
),
|
|
3046
|
+
(
|
|
3047
|
+
json!({"payment_status": "paid", "amount_total": 4200, "currency": "eur"}),
|
|
3048
|
+
"another currency",
|
|
3049
|
+
),
|
|
3050
|
+
(json!({"id": "cs_bare"}), "no payment facts at all"),
|
|
3051
|
+
] {
|
|
3052
|
+
let status = deliver_session_event(&client, reference, completed, session).await;
|
|
3053
|
+
assert_eq!(status, "pending", "{why} must not settle the payment");
|
|
3054
|
+
}
|
|
3055
|
+
|
|
3056
|
+
let paid = json!({"payment_status": "paid", "amount_total": 4200, "currency": "usd"});
|
|
3057
|
+
let status = deliver_session_event(
|
|
3058
|
+
&client,
|
|
3059
|
+
reference,
|
|
3060
|
+
"checkout.session.async_payment_succeeded",
|
|
3061
|
+
paid,
|
|
3062
|
+
)
|
|
3063
|
+
.await;
|
|
3064
|
+
assert_eq!(status, "succeeded", "the delayed payment settled");
|
|
3065
|
+
}
|
|
3066
|
+
|
|
3067
|
+
#[tokio::test]
|
|
3068
|
+
async fn webhook_route_fails_a_payment_whose_delayed_payment_failed() {
|
|
3069
|
+
let reference = "REG-WEBHOOK-ASYNC-FAIL";
|
|
3070
|
+
let client = stripe_payment_db("hecks_host_web_test_webhook_async_failed", reference).await;
|
|
3071
|
+
let unpaid = json!({"payment_status": "unpaid", "amount_total": 4200, "currency": "usd"});
|
|
3072
|
+
let failed = "checkout.session.async_payment_failed";
|
|
3073
|
+
assert_eq!(
|
|
3074
|
+
deliver_session_event(&client, reference, failed, unpaid).await,
|
|
3075
|
+
"failed"
|
|
3076
|
+
);
|
|
3077
|
+
}
|
|
3078
|
+
|
|
3079
|
+
#[tokio::test]
|
|
3080
|
+
async fn webhook_route_declines_a_payment_on_checkout_session_expired() {
|
|
3081
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
3082
|
+
let config = checkout_memory_config();
|
|
2697
3083
|
let wasm_path = checkout_wasm_path();
|
|
2698
3084
|
|
|
2699
3085
|
schedule_event(&client, &wasm_path, &config, "webhook-event-2", 4200).await;
|
|
@@ -2740,14 +3126,7 @@ mod tests {
|
|
|
2740
3126
|
|
|
2741
3127
|
#[tokio::test]
|
|
2742
3128
|
async fn webhook_route_ignores_an_event_type_it_does_not_handle_and_still_answers_200() {
|
|
2743
|
-
let client =
|
|
2744
|
-
provision_lineage(
|
|
2745
|
-
&*client.lock().await,
|
|
2746
|
-
"CheckoutFixture",
|
|
2747
|
-
1,
|
|
2748
|
-
&["Event", "Registration", "Payment"],
|
|
2749
|
-
)
|
|
2750
|
-
.await;
|
|
3129
|
+
let client = crate::dispatch_tests::tests::memory_store();
|
|
2751
3130
|
|
|
2752
3131
|
let secret = "whsec_test_unhandled";
|
|
2753
3132
|
let payload = json!({"type": "charge.refunded", "data": {"object": {"metadata": {"registration_id": "whatever"}}}}).to_string();
|
|
@@ -2761,7 +3140,7 @@ mod tests {
|
|
|
2761
3140
|
Host::new(
|
|
2762
3141
|
&client,
|
|
2763
3142
|
&checkout_wasm_path(),
|
|
2764
|
-
&
|
|
3143
|
+
&checkout_memory_config(),
|
|
2765
3144
|
&lambda_client::NeverInvoker,
|
|
2766
3145
|
),
|
|
2767
3146
|
&crate::commerce_ir::fixture_payments(),
|