hecks 3.4.2 → 3.6.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/hecksagon/mock_stripe_payment_adapter.rb +1 -1
- data/lib/hecks/adapters/driven/claude_code.rb +11 -7
- data/lib/hecks/adapters/driven/d1/connection.rb +90 -0
- data/lib/hecks/adapters/driven/d1.rb +48 -314
- data/lib/hecks/adapters/driven/folder.rb +20 -10
- data/lib/hecks/adapters/driven/google_authentication.rb +18 -4
- data/lib/hecks/adapters/driven/governance_authorization.rb +2 -2
- data/lib/hecks/adapters/driven/heki/journal.rb +11 -10
- data/lib/hecks/adapters/driven/heki/saga_store.rb +4 -6
- data/lib/hecks/adapters/driven/heki/sagas.rb +55 -0
- data/lib/hecks/adapters/driven/heki.rb +21 -66
- data/lib/hecks/adapters/driven/in_memory_ordering.rb +37 -12
- data/lib/hecks/adapters/driven/lambda/client.rb +1 -1
- data/lib/hecks/adapters/driven/lambda.rb +1 -8
- data/lib/hecks/adapters/driven/memory/outbox_rows.rb +76 -0
- data/lib/hecks/adapters/driven/memory/shared_elements/values.rb +117 -0
- data/lib/hecks/adapters/driven/memory/shared_elements.rb +10 -97
- data/lib/hecks/adapters/driven/memory.rb +3 -65
- data/lib/hecks/adapters/driven/postgres/codec.rb +29 -26
- data/lib/hecks/adapters/driven/postgres/ddl.rb +50 -0
- data/lib/hecks/adapters/driven/postgres/dialect.rb +93 -0
- data/lib/hecks/adapters/driven/postgres/events.rb +57 -0
- data/lib/hecks/adapters/driven/postgres/journal.rb +127 -0
- data/lib/hecks/adapters/driven/postgres/outbox.rb +39 -31
- data/lib/hecks/adapters/driven/postgres/repository.rb +190 -0
- data/lib/hecks/adapters/driven/postgres/sagas.rb +72 -0
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +13 -41
- data/lib/hecks/adapters/driven/postgres.rb +61 -528
- data/lib/hecks/adapters/driven/prism.rb +1 -1
- data/lib/hecks/adapters/driven/sql_query_builder.rb +45 -53
- data/lib/hecks/adapters/driven/sql_value_members.rb +57 -0
- data/lib/hecks/adapters/driven/sqlite/codec.rb +32 -29
- data/lib/hecks/adapters/driven/sqlite/ddl.rb +68 -0
- data/lib/hecks/adapters/driven/sqlite/dialect.rb +55 -0
- data/lib/hecks/adapters/driven/sqlite/events.rb +61 -0
- data/lib/hecks/adapters/driven/sqlite/journal.rb +125 -0
- data/lib/hecks/adapters/driven/sqlite/outbox.rb +98 -0
- data/lib/hecks/adapters/driven/sqlite/projection.rb +82 -63
- data/lib/hecks/adapters/driven/sqlite/repository.rb +146 -0
- data/lib/hecks/adapters/driven/sqlite/sagas.rb +69 -0
- data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +8 -55
- data/lib/hecks/adapters/driven/sqlite.rb +36 -513
- data/lib/hecks/adapters/driven/tenant_provisioner.rb +13 -7
- data/lib/hecks/adapters/driving/github_webhook.rb +11 -8
- data/lib/hecks/behaviors/dsl.rb +17 -12
- data/lib/hecks/behaviors/expectations/boot.rb +81 -0
- data/lib/hecks/behaviors/expectations/checks.rb +178 -0
- data/lib/hecks/behaviors/expectations/dispatching.rb +93 -0
- data/lib/hecks/behaviors/expectations/qualify.rb +81 -0
- data/lib/hecks/behaviors/expectations.rb +39 -355
- data/lib/hecks/behaviors/rspec.rb +12 -12
- data/lib/hecks/behaviors/runner.rb +20 -11
- data/lib/hecks/bench/cli.rb +16 -13
- data/lib/hecks/bench/environment.rb +1 -1
- data/lib/hecks/bench/report.rb +11 -7
- data/lib/hecks/bench/ruby_runner.rb +13 -8
- data/lib/hecks/bench/rust_runner.rb +19 -11
- data/lib/hecks/bench/suite.rb +48 -20
- data/lib/hecks/bench/workload.rb +42 -31
- data/lib/hecks/bluebook/aggregate.rb +15 -21
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +18 -21
- data/lib/hecks/bluebook/assembly/build.rb +12 -7
- data/lib/hecks/bluebook/assembly/contracts/read_models.rb +70 -0
- data/lib/hecks/bluebook/assembly/contracts/rules.rb +84 -0
- data/lib/hecks/bluebook/assembly/contracts/sagas.rb +109 -0
- data/lib/hecks/bluebook/assembly/contracts/structure.rb +91 -0
- data/lib/hecks/bluebook/assembly/contracts.rb +9 -319
- data/lib/hecks/bluebook/assembly/marks.rb +9 -8
- data/lib/hecks/bluebook/attribute.rb +13 -10
- data/lib/hecks/bluebook/behaviour/aggregate.rb +10 -3
- data/lib/hecks/bluebook/behaviour/read_model.rb +26 -13
- data/lib/hecks/bluebook/chapter.rb +22 -14
- data/lib/hecks/bluebook/command.rb +14 -18
- data/lib/hecks/bluebook/domain_port.rb +11 -8
- data/lib/hecks/bluebook/dsl/aggregate_builder/correction_sealing.rb +78 -0
- data/lib/hecks/bluebook/dsl/aggregate_builder/draining.rb +74 -0
- data/lib/hecks/bluebook/dsl/aggregate_builder/query_field_sealing.rb +105 -0
- data/lib/hecks/bluebook/dsl/aggregate_builder/query_sealing.rb +121 -0
- data/lib/hecks/bluebook/dsl/aggregate_builder/relationships.rb +128 -0
- data/lib/hecks/bluebook/dsl/aggregate_builder/rules.rb +84 -0
- data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +61 -249
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +51 -285
- data/lib/hecks/bluebook/dsl/attribute_collector/identity_resolution.rb +113 -0
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +58 -117
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +24 -19
- data/lib/hecks/bluebook/dsl/bluebook_builder/pending_givens.rb +109 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/correlation_keys.rb +105 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/event_shapes.rb +126 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/hop_tails.rb +79 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/projected_fields.rb +76 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/provisions.rb +65 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/query_hops.rb +123 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/references.rb +112 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/with_projections.rb +126 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +34 -595
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +18 -107
- data/lib/hecks/bluebook/dsl/command_builder/implicit_attributes.rb +132 -0
- data/lib/hecks/bluebook/dsl/command_builder/mutations.rb +190 -0
- data/lib/hecks/bluebook/dsl/command_builder/owner.rb +22 -0
- data/lib/hecks/bluebook/dsl/command_builder/rules.rb +57 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +60 -360
- data/lib/hecks/bluebook/dsl/domain_port_builder.rb +19 -13
- data/lib/hecks/bluebook/dsl/entity_builder/rules.rb +96 -0
- data/lib/hecks/bluebook/dsl/entity_builder/scope.rb +25 -0
- data/lib/hecks/bluebook/dsl/entity_builder/sealing.rb +94 -0
- data/lib/hecks/bluebook/dsl/entity_builder.rb +35 -169
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +53 -24
- data/lib/hecks/bluebook/dsl/hecksagon_builder/chapter_scope.rb +133 -0
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +3 -97
- data/lib/hecks/bluebook/dsl/identity_declaration.rb +73 -73
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +7 -3
- data/lib/hecks/bluebook/dsl/need_word.rb +1 -1
- data/lib/hecks/bluebook/dsl/port_operation_builder.rb +34 -29
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +57 -41
- data/lib/hecks/bluebook/dsl/query_builder.rb +12 -15
- data/lib/hecks/bluebook/dsl/read_model_builder/sealing.rb +116 -0
- data/lib/hecks/bluebook/dsl/read_model_builder.rb +25 -102
- data/lib/hecks/bluebook/dsl/rule_reference.rb +26 -12
- data/lib/hecks/bluebook/dsl/translation_builder.rb +24 -14
- data/lib/hecks/bluebook/dsl/value_object_builder.rb +29 -19
- data/lib/hecks/bluebook/dsl/word_gate.rb +34 -27
- data/lib/hecks/bluebook/entity.rb +13 -17
- data/lib/hecks/bluebook/expression/ast_json/emitters.rb +93 -0
- data/lib/hecks/bluebook/expression/ast_json/emitters.rb-e +88 -0
- data/lib/hecks/bluebook/expression/ast_json.rb +49 -76
- data/lib/hecks/bluebook/expression/ast_reader.rb +95 -28
- data/lib/hecks/bluebook/expression/canonical_form.rb +6 -26
- data/lib/hecks/bluebook/expression/evaluator/parser.rb +62 -0
- data/lib/hecks/bluebook/expression/evaluator/scanning.rb +122 -0
- data/lib/hecks/bluebook/expression/evaluator.rb +11 -111
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +28 -44
- data/lib/hecks/bluebook/expression/resolver/lookups.rb +77 -0
- data/lib/hecks/bluebook/expression/resolver/operations.rb +78 -0
- data/lib/hecks/bluebook/expression/resolver/parsing.rb +110 -0
- data/lib/hecks/bluebook/expression/resolver/scanning.rb +139 -0
- data/lib/hecks/bluebook/expression/resolver/values.rb +115 -0
- data/lib/hecks/bluebook/expression/resolver.rb +16 -414
- data/lib/hecks/bluebook/{hexagon.rb → hecksagon.rb} +22 -14
- data/lib/hecks/bluebook/keyword_fields.rb +42 -0
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +7 -6
- data/lib/hecks/bluebook/meta_validator/judge/cells.rb +99 -0
- data/lib/hecks/bluebook/meta_validator/judge/dispatching.rb +111 -0
- data/lib/hecks/bluebook/meta_validator/judge/identity.rb +108 -0
- data/lib/hecks/bluebook/meta_validator/judge/walking.rb +141 -0
- data/lib/hecks/bluebook/meta_validator/judge.rb +31 -376
- data/lib/hecks/bluebook/meta_validator/modes.rb +137 -0
- data/lib/hecks/bluebook/meta_validator/plan/category.rb +44 -0
- data/lib/hecks/bluebook/meta_validator/plan/verbs.rb +73 -0
- data/lib/hecks/bluebook/meta_validator/plan.rb +38 -122
- data/lib/hecks/bluebook/meta_validator/readings/fields.rb +100 -0
- data/lib/hecks/bluebook/meta_validator/readings.rb +10 -95
- data/lib/hecks/bluebook/meta_validator/reconstruction/heads.rb +89 -0
- data/lib/hecks/bluebook/meta_validator/reconstruction/reading.rb +96 -0
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +25 -151
- data/lib/hecks/bluebook/meta_validator/shapes/helpers.rb +83 -0
- data/lib/hecks/bluebook/meta_validator/shapes.rb +8 -75
- data/lib/hecks/bluebook/meta_validator/syntax_boot/disk_cache.rb +77 -0
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +31 -95
- data/lib/hecks/bluebook/meta_validator/translation_judge/rules.rb +74 -0
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +15 -65
- data/lib/hecks/bluebook/meta_validator/verdict_cache/tagging.rb +63 -0
- data/lib/hecks/bluebook/meta_validator/verdict_cache.rb +22 -43
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +8 -4
- data/lib/hecks/bluebook/meta_validator.rb +59 -175
- data/lib/hecks/bluebook/model_check/lifecycle_checks.rb +122 -0
- data/lib/hecks/bluebook/model_check/policy_checks.rb +129 -0
- data/lib/hecks/bluebook/model_check/saga_checks.rb +134 -0
- data/lib/hecks/bluebook/model_check/verbs.rb +69 -0
- data/lib/hecks/bluebook/model_check.rb +73 -413
- data/lib/hecks/bluebook/pattern_subset/refusals.rb +54 -0
- data/lib/hecks/bluebook/pattern_subset/scan.rb +58 -0
- data/lib/hecks/bluebook/pattern_subset.rb +93 -134
- data/lib/hecks/bluebook/process_manager.rb +10 -9
- data/lib/hecks/bluebook/project_discovery.rb +10 -7
- data/lib/hecks/bluebook/project_register.rb +42 -41
- data/lib/hecks/bluebook/query.rb +19 -12
- data/lib/hecks/bluebook/read_model.rb +41 -39
- data/lib/hecks/bluebook/smoke_test.rb +51 -36
- data/lib/hecks/bluebook/synthesizer.rb +13 -5
- data/lib/hecks/bluebook/translation.rb +12 -12
- data/lib/hecks/bluebook.rb +1 -1
- data/lib/hecks/chapters.rb +32 -16
- data/lib/hecks/cli/behaviors.rb +22 -15
- data/lib/hecks/cli/check_era.rb +2 -2
- data/lib/hecks/cli/command_table.rb +72 -0
- data/lib/hecks/cli/console.rb +10 -7
- data/lib/hecks/cli/deploy_template_diff.rb +22 -9
- data/lib/hecks/cli/document.rb +14 -10
- data/lib/hecks/cli/domain_stub.rb +1 -1
- data/lib/hecks/cli/domain_writer.rb +1 -1
- data/lib/hecks/cli/expression_projection.rb +8 -6
- data/lib/hecks/cli/follow.rb +10 -4
- data/lib/hecks/cli/interview_aggregate.rb +132 -0
- data/lib/hecks/cli/interview_draft.rb +16 -200
- data/lib/hecks/cli/interview_record.rb +130 -0
- data/lib/hecks/cli/interview_run.rb +19 -8
- data/lib/hecks/cli/interview_session/agent_state.rb +70 -0
- data/lib/hecks/cli/interview_session/catalog.rb +76 -0
- data/lib/hecks/cli/interview_session/manual_findings.rb +48 -0
- data/lib/hecks/cli/interview_session/proposals.rb +90 -0
- data/lib/hecks/cli/interview_session.rb +8 -205
- data/lib/hecks/cli/interview_shape.rb +13 -6
- data/lib/hecks/cli/ir.rb +8 -11
- data/lib/hecks/cli/launcher_words.rb +168 -0
- data/lib/hecks/cli/model_check/examination.rb +93 -0
- data/lib/hecks/cli/model_check/sources.rb +57 -0
- data/lib/hecks/cli/model_check.rb +28 -134
- data/lib/hecks/cli/project_cli/launcher_source.rb +177 -0
- data/lib/hecks/cli/project_cli/templates.rb +106 -0
- data/lib/hecks/cli/project_cli.rb +57 -236
- data/lib/hecks/cli/project_diagrams.rb +26 -4
- data/lib/hecks/cli/project_glossary.rb +19 -9
- data/lib/hecks/cli/refresh_rspec_runtime_baseline.rb +29 -13
- data/lib/hecks/cli/release.rb +29 -22
- data/lib/hecks/cli/release_gem.rb +12 -6
- data/lib/hecks/cli/rspec_io_parallel_files.rb +87 -30
- data/lib/hecks/cli/rspec_shard_files.rb +24 -9
- data/lib/hecks/cli/run.rb +25 -44
- data/lib/hecks/cli/run_expectations.rb +63 -0
- data/lib/hecks/cli/seed_semantics_corpus.rb +37 -17
- data/lib/hecks/cli/smoke_http/checks.rb +66 -0
- data/lib/hecks/cli/smoke_http/settings.rb +63 -0
- data/lib/hecks/cli/smoke_http/transport.rb +45 -0
- data/lib/hecks/cli/smoke_http.rb +8 -142
- data/lib/hecks/cli/smoke_test.rb +18 -4
- data/lib/hecks/cli/stores.rb +7 -4
- data/lib/hecks/cli/stress_concurrency_specs/reporting.rb +44 -0
- data/lib/hecks/cli/stress_concurrency_specs/usage.rb +28 -0
- data/lib/hecks/cli/stress_concurrency_specs.rb +82 -80
- data/lib/hecks/cli.rb +32 -208
- data/lib/hecks/codemod/runner.rb +92 -0
- data/lib/hecks/codemod/sweep.rb +94 -0
- data/lib/hecks/codemod.rb +22 -165
- data/lib/hecks/corpus/routes.rb +34 -0
- data/lib/hecks/corpus/rust.rb +193 -0
- data/lib/hecks/corpus/sources.rb +46 -0
- data/lib/hecks/corpus.rb +28 -265
- data/lib/hecks/deploy/bluebook/deploy.bluebook +1510 -3
- data/lib/hecks/deploy/bluebook/deploy.hecksagon +57 -0
- data/lib/hecks/deploy/oidc.json +225 -0
- data/lib/hecks/doc/reference/coverage.rb +70 -0
- data/lib/hecks/doc/reference/harvester.rb +55 -0
- data/lib/hecks/doc/reference/readme.rb +89 -0
- data/lib/hecks/doc/reference/rendering.rb +149 -0
- data/lib/hecks/doc/reference.rb +14 -273
- data/lib/hecks/doors/cli_door/nesting.rb +34 -0
- data/lib/hecks/doors/cli_door/shorthand.rb +85 -0
- data/lib/hecks/doors/cli_door.rb +23 -95
- data/lib/hecks/doors/cli_runner/answers.rb +138 -0
- data/lib/hecks/doors/cli_runner/resolution.rb +146 -0
- data/lib/hecks/doors/cli_runner/settling.rb +115 -0
- data/lib/hecks/doors/cli_runner/streaming.rb +90 -0
- data/lib/hecks/doors/cli_runner/suggestions.rb +43 -0
- data/lib/hecks/doors/cli_runner.rb +12 -336
- data/lib/hecks/doors/command_request.rb +42 -31
- data/lib/hecks/doors/handle.rb +32 -30
- data/lib/hecks/doors/launcher_options.rb +62 -7
- data/lib/hecks/doors/mcp_door/properties.rb +47 -0
- data/lib/hecks/doors/mcp_door/tool_calls.rb +113 -0
- data/lib/hecks/doors/mcp_door/tool_definitions/auditing.rb +51 -0
- data/lib/hecks/doors/mcp_door/tool_definitions/calling.rb +69 -0
- data/lib/hecks/doors/mcp_door/tool_definitions/reading.rb +97 -0
- data/lib/hecks/doors/mcp_door/tool_definitions.rb +15 -0
- data/lib/hecks/doors/mcp_door.rb +55 -301
- data/lib/hecks/doors/mcp_door_scope/argument_policy.rb +92 -0
- data/lib/hecks/doors/mcp_door_scope/env_problems.rb +55 -0
- data/lib/hecks/doors/mcp_door_scope/presenter.rb +78 -0
- data/lib/hecks/doors/mcp_door_scope.rb +16 -172
- data/lib/hecks/doors/ruby_door/aggregate_door.rb +1 -1
- data/lib/hecks/doors/ruby_door/chapter.rb +33 -16
- data/lib/hecks/doors/ruby_door.rb +14 -11
- data/lib/hecks/doors/usage_cache.rb +14 -8
- data/lib/hecks/doors.rb +10 -4
- data/lib/hecks/embryonaut_bluebook/manifest.rb +11 -3
- data/lib/hecks/embryonaut_bluebook/registry/changelog.rb +26 -0
- data/lib/hecks/embryonaut_bluebook/registry/versions.rb +27 -0
- data/lib/hecks/embryonaut_bluebook/registry.rb +27 -37
- data/lib/hecks/embryonaut_bluebook/vendor/acceptance.rb +37 -0
- data/lib/hecks/embryonaut_bluebook/vendor.rb +22 -36
- data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +9 -6
- data/lib/hecks/embryonaut_bluebook.rb +16 -11
- data/lib/hecks/engine_agreement.rb +24 -17
- data/lib/hecks/forms/app/commands.rb +98 -0
- data/lib/hecks/forms/app/queries.rb +62 -0
- data/lib/hecks/forms/app/records.rb +67 -0
- data/lib/hecks/forms/app/responses.rb +46 -0
- data/lib/hecks/forms/app.rb +33 -221
- data/lib/hecks/forms/banking_presentation.rb +5 -0
- data/lib/hecks/forms/command_form_renderer.rb +55 -14
- data/lib/hecks/forms/field_controls.rb +95 -0
- data/lib/hecks/forms/field_renderer.rb +34 -88
- data/lib/hecks/forms/field_shape.rb +9 -34
- data/lib/hecks/forms/html.rb +1 -1
- data/lib/hecks/forms/index_renderer.rb +14 -9
- data/lib/hecks/forms/page.rb +2 -106
- data/lib/hecks/forms/page_assets.rb +88 -0
- data/lib/hecks/forms/page_script.rb +28 -0
- data/lib/hecks/forms/params.rb +17 -8
- data/lib/hecks/forms/query_form_renderer.rb +11 -7
- data/lib/hecks/forms/record_renderer.rb +28 -19
- data/lib/hecks/forms/reference_options.rb +1 -1
- data/lib/hecks/forms/text_shape.rb +40 -0
- data/lib/hecks/fqn.rb +64 -32
- data/lib/hecks/framework.rb +10 -3
- data/lib/hecks/freezer.rb +10 -1
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions/fragments.rb +61 -0
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions/productions.rb +217 -0
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +5 -194
- data/lib/hecks/fuzzing/combination_miner.rb +23 -12
- data/lib/hecks/fuzzing/concurrent_dispatch/racing.rb +64 -0
- data/lib/hecks/fuzzing/concurrent_dispatch/world_copy.rb +66 -0
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +31 -107
- data/lib/hecks/fuzzing/coverage_campaign.rb +7 -7
- data/lib/hecks/fuzzing/differential/wire_comparison.rb +74 -0
- data/lib/hecks/fuzzing/differential.rb +59 -84
- data/lib/hecks/fuzzing/domain_generator/block_rendering.rb +70 -0
- data/lib/hecks/fuzzing/domain_generator/builder/attribute_shapes.rb +105 -0
- data/lib/hecks/fuzzing/domain_generator/builder/shapes.rb +97 -0
- data/lib/hecks/fuzzing/domain_generator/builder/wiring.rb +128 -0
- data/lib/hecks/fuzzing/domain_generator/builder.rb +105 -0
- data/lib/hecks/fuzzing/domain_generator/pruning.rb +90 -0
- data/lib/hecks/fuzzing/domain_generator/removals.rb +62 -0
- data/lib/hecks/fuzzing/domain_generator/rendering.rb +94 -0
- data/lib/hecks/fuzzing/domain_generator/tokens.rb +38 -0
- data/lib/hecks/fuzzing/domain_generator.rb +7 -555
- data/lib/hecks/fuzzing/era_boundary.rb +34 -24
- data/lib/hecks/fuzzing/form_census.rb +18 -8
- data/lib/hecks/fuzzing/generated_domain_check.rb +23 -11
- data/lib/hecks/fuzzing/isolated_boot/copying.rb +62 -0
- data/lib/hecks/fuzzing/isolated_boot/postgres_scratch.rb +133 -0
- data/lib/hecks/fuzzing/isolated_boot/worlds.rb +102 -0
- data/lib/hecks/fuzzing/isolated_boot.rb +25 -252
- data/lib/hecks/fuzzing/persistence_parity.rb +5 -5
- data/lib/hecks/fuzzing/properties/aggregation_recompute.rb +121 -0
- data/lib/hecks/fuzzing/properties/catalog.rb +138 -0
- data/lib/hecks/fuzzing/properties/corrections.rb +23 -20
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +64 -185
- data/lib/hecks/fuzzing/properties/group_by_recompute.rb +69 -0
- data/lib/hecks/fuzzing/properties/guards.rb +76 -108
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +66 -227
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +46 -35
- data/lib/hecks/fuzzing/properties/mutation_recompute.rb +162 -0
- data/lib/hecks/fuzzing/properties/outbox.rb +41 -24
- data/lib/hecks/fuzzing/properties/piece_invariants.rb +61 -0
- data/lib/hecks/fuzzing/properties/policy_wiring.rb +140 -0
- data/lib/hecks/fuzzing/properties/query_rows.rb +67 -0
- data/lib/hecks/fuzzing/properties/querying.rb +69 -90
- data/lib/hecks/fuzzing/properties/references.rb +100 -0
- data/lib/hecks/fuzzing/properties/tenant_scope.rb +84 -0
- data/lib/hecks/fuzzing/properties.rb +6 -119
- data/lib/hecks/fuzzing/qa_settings.rb +23 -17
- data/lib/hecks/fuzzing/replay/fan_out.rb +78 -0
- data/lib/hecks/fuzzing/replay/filters.rb +72 -0
- data/lib/hecks/fuzzing/replay/guard_check.rb +88 -0
- data/lib/hecks/fuzzing/replay/mutation_trace.rb +117 -0
- data/lib/hecks/fuzzing/replay/observation.rb +60 -0
- data/lib/hecks/fuzzing/replay/read_only_steps.rb +84 -0
- data/lib/hecks/fuzzing/replay/session.rb +151 -0
- data/lib/hecks/fuzzing/replay.rb +35 -442
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +3 -4
- data/lib/hecks/fuzzing/self_consistency/saga_redelivery.rb +133 -0
- data/lib/hecks/fuzzing/self_consistency/sagas.rb +93 -0
- data/lib/hecks/fuzzing/self_consistency/value_objects.rb +87 -0
- data/lib/hecks/fuzzing/self_consistency.rb +8 -213
- data/lib/hecks/fuzzing/sequence_generator/adversary/argument_mutations.rb +116 -0
- data/lib/hecks/fuzzing/sequence_generator/adversary/caller_draw.rb +68 -0
- data/lib/hecks/fuzzing/sequence_generator/adversary/identity_mutations.rb +62 -0
- data/lib/hecks/fuzzing/sequence_generator/adversary/precedence_mutations.rb +126 -0
- data/lib/hecks/fuzzing/sequence_generator/adversary.rb +23 -283
- data/lib/hecks/fuzzing/sequence_generator/argument_drawing.rb +78 -0
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +69 -53
- data/lib/hecks/fuzzing/sequence_generator/identity_shaping.rb +85 -0
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +20 -16
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +12 -6
- data/lib/hecks/fuzzing/sequence_generator/prefixing.rb +45 -0
- data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +19 -8
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +43 -144
- data/lib/hecks/fuzzing/sequence_generator.rb +65 -63
- data/lib/hecks/fuzzing/shrinker.rb +33 -29
- data/lib/hecks/fuzzing/target_capabilities.rb +10 -4
- data/lib/hecks/fuzzing/value_generator.rb +27 -17
- data/lib/hecks/gate/stages.yml +10 -0
- data/lib/hecks/grammar/evolve/arguments.rb +90 -0
- data/lib/hecks/grammar/evolve/keywords.rb +81 -0
- data/lib/hecks/grammar/evolve/seeds.rb +172 -0
- data/lib/hecks/grammar/evolve.rb +22 -263
- data/lib/hecks/grammar/operators.rb +111 -0
- data/lib/hecks/grammar.rb +53 -126
- data/lib/hecks/hecks/adapters/bluebook_report.rb +91 -0
- data/lib/hecks/hecks/adapters/codebase/codemods.rb +1 -1
- data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +23 -9
- data/lib/hecks/hecks/adapters/codebase/language/edits.rb +75 -0
- data/lib/hecks/hecks/adapters/codebase/language.rb +30 -72
- data/lib/hecks/hecks/adapters/codebase/promotion/candidates.rb +54 -0
- data/lib/hecks/hecks/adapters/codebase/promotion/gate.rb +50 -0
- data/lib/hecks/hecks/adapters/codebase/promotion/move.rb +70 -0
- data/lib/hecks/hecks/adapters/codebase/promotion/standing.rb +88 -0
- data/lib/hecks/hecks/adapters/codebase/promotion/watch.rb +83 -0
- data/lib/hecks/hecks/adapters/codebase/promotion.rb +115 -0
- data/lib/hecks/hecks/adapters/codebase/publishing.rb +31 -12
- data/lib/hecks/hecks/adapters/codebase/regeneration.rb +43 -6
- data/lib/hecks/hecks/adapters/codebase/release_facts.rb +16 -5
- data/lib/hecks/hecks/adapters/codebase/source_tree.rb +9 -1
- data/lib/hecks/hecks/adapters/codebase/sqlite_fixture.rb +1 -1
- data/lib/hecks/hecks/adapters/codebase/style.rb +1 -1
- data/lib/hecks/hecks/adapters/codebase/test_runner.rb +11 -5
- data/lib/hecks/hecks/adapters/codebase/test_suite.rb +27 -8
- data/lib/hecks/hecks/adapters/console_capture.rb +21 -17
- data/lib/hecks/hecks/adapters/cost_explorer.rb +11 -6
- data/lib/hecks/hecks/adapters/deploy_plans.rb +49 -0
- data/lib/hecks/hecks/adapters/deploy_toolchain/answers.rb +141 -0
- data/lib/hecks/hecks/adapters/deploy_toolchain/scripts.rb +95 -0
- data/lib/hecks/hecks/adapters/deploy_toolchain/statuses.rb +74 -0
- data/lib/hecks/hecks/adapters/deploy_toolchain.rb +122 -59
- data/lib/hecks/hecks/adapters/finding_github.rb +2 -2
- data/lib/hecks/hecks/adapters/first_admin.rb +22 -8
- data/lib/hecks/hecks/adapters/git.rb +18 -5
- data/lib/hecks/hecks/adapters/git_refs.rb +144 -0
- data/lib/hecks/hecks/adapters/github_rulesets.rb +126 -0
- data/lib/hecks/hecks/adapters/host_http.rb +16 -6
- data/lib/hecks/hecks/adapters/in_process_boot.rb +9 -5
- data/lib/hecks/hecks/adapters/in_process_operations/tailing.rb +61 -0
- data/lib/hecks/hecks/adapters/in_process_operations.rb +39 -37
- data/lib/hecks/hecks/adapters/journal_store/changes.rb +21 -15
- data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +29 -12
- data/lib/hecks/hecks/adapters/journal_store/readings/attestation.rb +52 -0
- data/lib/hecks/hecks/adapters/journal_store/readings/scaffolding.rb +52 -0
- data/lib/hecks/hecks/adapters/journal_store/readings.rb +5 -62
- data/lib/hecks/hecks/adapters/local_files.rb +27 -10
- data/lib/hecks/hecks/adapters/pg_admin/ownership.rb +115 -0
- data/lib/hecks/hecks/adapters/pg_admin.rb +14 -87
- data/lib/hecks/hecks/adapters/process_pool.rb +54 -22
- data/lib/hecks/hecks/adapters/rust_toolchain.rb +12 -4
- data/lib/hecks/hecks/adapters/site_toolchain.rb +19 -10
- data/lib/hecks/hecks/adapters/terminal.rb +13 -9
- data/lib/hecks/hecks/codebase.bluebook +322 -5
- data/lib/hecks/hecks/custodian.bluebook +12 -2
- data/lib/hecks/hecks/hecks.hecksagon +73 -0
- data/lib/hecks/hecks/hecks.world +15 -3
- data/lib/hecks/kernel_capabilities/templates.rb +92 -0
- data/lib/hecks/kernel_capabilities.rb +18 -85
- data/lib/hecks/language/bluebook/vocabulary.bluebook +43 -1
- data/lib/hecks/literal/item_splitter.rb +50 -0
- data/lib/hecks/literal.rb +29 -38
- data/lib/hecks/mcp_stdio_guard.rb +8 -8
- data/lib/hecks/naming.rb +9 -3
- data/lib/hecks/persistence_legacy_fixture/postgres_stores.rb +81 -0
- data/lib/hecks/persistence_legacy_fixture/regenerate.rb +26 -66
- data/lib/hecks/persistence_legacy_fixture.rb +13 -10
- data/lib/hecks/ports/access_control.rb +13 -10
- data/lib/hecks/ports/agent/answers.rb +2 -2
- data/lib/hecks/ports/agent.rb +13 -10
- data/lib/hecks/ports/authentication.rb +13 -10
- data/lib/hecks/ports/authorization.rb +13 -10
- data/lib/hecks/ports/clock.rb +13 -10
- data/lib/hecks/ports/extraction.rb +13 -12
- data/lib/hecks/ports/identity_assignment.rb +13 -10
- data/lib/hecks/ports/identity_generation.rb +13 -10
- data/lib/hecks/ports/identity_resolution.rb +13 -10
- data/lib/hecks/ports/key_vault.rb +13 -10
- data/lib/hecks/ports/persistence/append_only.rb +5 -5
- data/lib/hecks/ports/persistence/binding_policy.rb +33 -9
- data/lib/hecks/ports/persistence/codec_boundary.rb +22 -11
- data/lib/hecks/ports/persistence/constants.rb +10 -0
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +18 -16
- data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +27 -18
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +52 -23
- data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +14 -8
- data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +17 -6
- data/lib/hecks/ports/persistence/plugins/era/lineage/coverage.rb +58 -0
- data/lib/hecks/ports/persistence/plugins/era/lineage/rewrite.rb +130 -0
- data/lib/hecks/ports/persistence/plugins/era/lineage/rules.rb +25 -0
- data/lib/hecks/ports/persistence/plugins/era/lineage.rb +20 -180
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/boot.rb +41 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/class_methods.rb +105 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/dialect.rb +137 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/events.rb +25 -28
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/head_writes.rb +62 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/journal.rb +128 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/base_sql.rb +74 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/chain_sql.rb +169 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/domain_rename.rb +91 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_integrity.rb +99 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +0 -73
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +55 -39
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +51 -222
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/merge_writes.rb +120 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +85 -60
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +97 -181
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +19 -19
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/sql_templates.rb +88 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +77 -118
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +3 -117
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_sql.rb +116 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +3 -1
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/context.rb +38 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +43 -25
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +62 -38
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +21 -16
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +66 -86
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/refusals.rb +75 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +27 -9
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/query_phases.rb +63 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/sagas.rb +78 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +28 -482
- data/lib/hecks/ports/persistence/plugins/era/translation/approval_file.rb +40 -12
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +22 -15
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +39 -19
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +16 -16
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +48 -25
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +60 -99
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/path_diff.rb +57 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +21 -11
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +13 -4
- data/lib/hecks/ports/persistence/postgres_dump/connection.rb +4 -2
- data/lib/hecks/ports/persistence/postgres_dump.rb +13 -7
- data/lib/hecks/ports/persistence/repository_factory.rb +35 -11
- data/lib/hecks/ports/persistence/state_codec.rb +10 -0
- data/lib/hecks/ports/persistence.rb +1 -10
- data/lib/hecks/ports/projection.rb +34 -21
- data/lib/hecks/ports/query/in_memory.rb +16 -8
- data/lib/hecks/projection_files/expression_tables.rb +64 -0
- data/lib/hecks/projection_files/texts.rb +67 -0
- data/lib/hecks/projection_files.rb +19 -103
- data/lib/hecks/projections/bootstrap_table.rb +43 -29
- data/lib/hecks/projections/deploy/bastion_lines.rb +32 -0
- data/lib/hecks/projections/deploy/box/access.rb +73 -0
- data/lib/hecks/projections/deploy/box/caddy.rb +87 -0
- data/lib/hecks/projections/deploy/box/compose.rb +70 -0
- data/lib/hecks/projections/deploy/box/hosting.rb +16 -108
- data/lib/hecks/projections/deploy/box/hosting_parts.rb +97 -0
- data/lib/hecks/projections/deploy/box/hosting_settings.rb +1 -1
- data/lib/hecks/projections/deploy/box/roll_recipe.rb +62 -0
- data/lib/hecks/projections/deploy/box/roll_scripts.rb +135 -0
- data/lib/hecks/projections/deploy/box/settings/checks.rb +38 -0
- data/lib/hecks/projections/deploy/box/settings/containers.rb +123 -0
- data/lib/hecks/projections/deploy/box/settings/origin.rb +56 -0
- data/lib/hecks/projections/deploy/box/settings/patterns.rb +43 -0
- data/lib/hecks/projections/deploy/box/settings/types.rb +72 -0
- data/lib/hecks/projections/deploy/box/settings.rb +58 -263
- data/lib/hecks/projections/deploy/box/stack_yaml.rb +107 -0
- data/lib/hecks/projections/deploy/box/templates/MIGRATION.md.tmpl +39 -0
- data/lib/hecks/projections/deploy/box/templates/Makefile.tmpl +24 -0
- data/lib/hecks/projections/deploy/box/templates/deploy-box.sh.tmpl +51 -4
- data/lib/hecks/projections/deploy/box/templates/deploy-service.services-roll.part +4 -3
- data/lib/hecks/projections/deploy/box/templates/deploy-service.sh.tmpl +16 -4
- data/lib/hecks/projections/deploy/box/templates/deploy-service.taskdef-roll.part +8 -7
- data/lib/hecks/projections/deploy/box/templates/deploy-service.taskdef.part +1 -1
- data/lib/hecks/projections/deploy/box/templates/deploy-usage-services.tmpl +4 -0
- data/lib/hecks/projections/deploy/box/templates/deploy-usage-taskdef.tmpl +5 -0
- data/lib/hecks/projections/deploy/box/templates/ecr-repository.yaml.tmpl +9 -0
- data/lib/hecks/projections/deploy/box/templates/hosting.mk.tmpl +6 -3
- data/lib/hecks/projections/deploy/box/templates/mode-summary-services.tmpl +2 -0
- data/lib/hecks/projections/deploy/box/templates/mode-summary-taskdef.tmpl +4 -0
- data/lib/hecks/projections/deploy/box/templates/restore-to-rds.sh.tmpl +8 -3
- data/lib/hecks/projections/deploy/box/templates/services-block.tmpl +9 -0
- data/lib/hecks/projections/deploy/box/templates/tunnel-egress.yaml.tmpl +11 -0
- data/lib/hecks/projections/deploy/box/templates/verify-copy.sh.tmpl +2 -2
- data/lib/hecks/projections/deploy/box/templates/writable-secrets.yaml.tmpl +7 -0
- data/lib/hecks/projections/deploy/box.rb +37 -503
- data/lib/hecks/projections/deploy/fargate/assembly.rb +13 -142
- data/lib/hecks/projections/deploy/fargate/cdn/behaviors.rb +76 -0
- data/lib/hecks/projections/deploy/fargate/cdn/lines.rb +112 -0
- data/lib/hecks/projections/deploy/fargate/cdn/options.rb +85 -0
- data/lib/hecks/projections/deploy/fargate/cdn.rb +23 -215
- data/lib/hecks/projections/deploy/fargate/check.rb +16 -6
- data/lib/hecks/projections/deploy/fargate/containers/definition_lines.rb +61 -0
- data/lib/hecks/projections/deploy/fargate/containers/reading.rb +86 -0
- data/lib/hecks/projections/deploy/fargate/containers/rendering.rb +132 -0
- data/lib/hecks/projections/deploy/fargate/containers/routing.rb +93 -0
- data/lib/hecks/projections/deploy/fargate/containers.rb +10 -286
- data/lib/hecks/projections/deploy/fargate/extras/reading.rb +90 -0
- data/lib/hecks/projections/deploy/fargate/extras/rendering.rb +81 -0
- data/lib/hecks/projections/deploy/fargate/extras.rb +9 -158
- data/lib/hecks/projections/deploy/fargate/monitoring/alarms.rb +115 -0
- data/lib/hecks/projections/deploy/fargate/monitoring/reading.rb +84 -0
- data/lib/hecks/projections/deploy/fargate/monitoring/topic.rb +59 -0
- data/lib/hecks/projections/deploy/fargate/monitoring/warmer.rb +90 -0
- data/lib/hecks/projections/deploy/fargate/monitoring/warmer_roles.rb +76 -0
- data/lib/hecks/projections/deploy/fargate/monitoring.rb +14 -348
- data/lib/hecks/projections/deploy/fargate/sections.rb +115 -0
- data/lib/hecks/projections/deploy/fargate/settings/ids.rb +55 -0
- data/lib/hecks/projections/deploy/fargate/settings/tuning.rb +77 -0
- data/lib/hecks/projections/deploy/fargate/settings.rb +17 -104
- data/lib/hecks/projections/deploy/fargate/stack/blocks.rb +91 -0
- data/lib/hecks/projections/deploy/fargate/stack/readers.rb +87 -0
- data/lib/hecks/projections/deploy/fargate/stack/recipes.rb +106 -0
- data/lib/hecks/projections/deploy/fargate/stack.rb +146 -0
- data/lib/hecks/projections/deploy/fargate/task_sections.rb +56 -0
- data/lib/hecks/projections/deploy/fargate/yaml.rb +1 -1
- data/lib/hecks/projections/deploy/fargate.rb +51 -756
- data/lib/hecks/projections/deploy/lambda/pii.rb +49 -0
- data/lib/hecks/projections/deploy/lambda/stack/blocks.rb +118 -0
- data/lib/hecks/projections/deploy/lambda/stack/checks.rb +64 -0
- data/lib/hecks/projections/deploy/lambda/stack/deploy_chain.rb +119 -0
- data/lib/hecks/projections/deploy/lambda/stack/readers.rb +62 -0
- data/lib/hecks/projections/deploy/lambda/stack/reading.rb +170 -0
- data/lib/hecks/projections/deploy/lambda/stack/reading_web.rb +53 -0
- data/lib/hecks/projections/deploy/lambda/stack/recipes.rb +112 -0
- data/lib/hecks/projections/deploy/lambda/stack/web.rb +57 -0
- data/lib/hecks/projections/deploy/lambda/stack.rb +54 -0
- data/lib/hecks/projections/deploy/lambda.rb +77 -1885
- data/lib/hecks/projections/deploy/preview/access_yaml.rb +8 -74
- data/lib/hecks/projections/deploy/preview/containers.rb +18 -7
- data/lib/hecks/projections/deploy/preview/routing_yaml.rb +15 -87
- data/lib/hecks/projections/deploy/preview/settings.rb +7 -4
- data/lib/hecks/projections/deploy/preview/task_yaml.rb +42 -106
- data/lib/hecks/projections/deploy/preview/template.rb +11 -106
- data/lib/hecks/projections/deploy/preview/yaml_text.rb +1 -1
- data/lib/hecks/projections/deploy/scripts/hosting.mk.tmpl +1 -1
- data/lib/hecks/projections/deploy/scripts/settings.rb +14 -6
- data/lib/hecks/projections/deploy/scripts.rb +11 -9
- data/lib/hecks/projections/deploy/shared/rows.rb +48 -0
- data/lib/hecks/projections/deploy/shared.rb +89 -449
- data/lib/hecks/projections/deploy/smoke.rb +15 -10
- data/lib/hecks/projections/deploy/template_diff/comparer.rb +21 -147
- data/lib/hecks/projections/deploy/template_diff/normalizer.rb +60 -0
- data/lib/hecks/projections/deploy/template_diff/value_diff.rb +136 -0
- data/lib/hecks/projections/deploy/template_diff.rb +8 -3
- data/lib/hecks/projections/deploy/templates/fargate/Dockerfile.tmpl +28 -0
- data/lib/hecks/projections/deploy/templates/fargate/Makefile.tmpl +63 -0
- data/lib/hecks/projections/deploy/templates/fargate/always_params.tmpl +4 -0
- data/lib/hecks/projections/deploy/templates/fargate/deploy_plain.tmpl +1 -0
- data/lib/hecks/projections/deploy/templates/fargate/deploy_shared.tmpl +11 -0
- data/lib/hecks/projections/deploy/templates/fargate/mint_era_own.tmpl +44 -0
- data/lib/hecks/projections/deploy/templates/fargate/mint_era_shared.tmpl +8 -0
- data/lib/hecks/projections/deploy/templates/fargate/missing_owner.tmpl +9 -0
- data/lib/hecks/projections/deploy/templates/fargate/oauth_params.tmpl +7 -0
- data/lib/hecks/projections/deploy/templates/fargate/oauth_task_env.tmpl +4 -0
- data/lib/hecks/projections/deploy/templates/fargate/oauth_task_policy.tmpl +7 -0
- data/lib/hecks/projections/deploy/templates/fargate/owning_params.tmpl +33 -0
- data/lib/hecks/projections/deploy/templates/fargate/template.yaml.tmpl +281 -0
- data/lib/hecks/projections/deploy/templates/lambda/Makefile.tmpl +218 -0
- data/lib/hecks/projections/deploy/templates/lambda/aurora_depends.tmpl +18 -0
- data/lib/hecks/projections/deploy/templates/lambda/build_dispatch_none.tmpl +10 -0
- data/lib/hecks/projections/deploy/templates/lambda/build_pg.tmpl +15 -0
- data/lib/hecks/projections/deploy/templates/lambda/build_plain.tmpl +2 -0
- data/lib/hecks/projections/deploy/templates/lambda/build_web.tmpl +11 -0
- data/lib/hecks/projections/deploy/templates/lambda/env_blind_guard.tmpl +4 -0
- data/lib/hecks/projections/deploy/templates/lambda/mint_era_own.tmpl +122 -0
- data/lib/hecks/projections/deploy/templates/lambda/mint_era_shared.tmpl +47 -0
- data/lib/hecks/projections/deploy/templates/lambda/missing_owner.tmpl +9 -0
- data/lib/hecks/projections/deploy/templates/lambda/nat_comment_oauth.tmpl +14 -0
- data/lib/hecks/projections/deploy/templates/lambda/nat_comment_plain.tmpl +3 -0
- data/lib/hecks/projections/deploy/templates/lambda/oauth_note.tmpl +8 -0
- data/lib/hecks/projections/deploy/templates/lambda/params_oauth.tmpl +13 -0
- data/lib/hecks/projections/deploy/templates/lambda/params_shared.tmpl +33 -0
- data/lib/hecks/projections/deploy/templates/lambda/pg_native.tmpl +71 -0
- data/lib/hecks/projections/deploy/templates/lambda/pii_oac.tmpl +8 -0
- data/lib/hecks/projections/deploy/templates/lambda/pii_permission.tmpl +8 -0
- data/lib/hecks/projections/deploy/templates/lambda/pii_resources.tmpl +116 -0
- data/lib/hecks/projections/deploy/templates/lambda/predeploy_bridge.tmpl +30 -0
- data/lib/hecks/projections/deploy/templates/lambda/predeploy_bridge_oauth.tmpl +12 -0
- data/lib/hecks/projections/deploy/templates/lambda/predeploy_bridge_plain.tmpl +7 -0
- data/lib/hecks/projections/deploy/templates/lambda/rename_schema_own.tmpl +93 -0
- data/lib/hecks/projections/deploy/templates/lambda/rename_schema_shared.tmpl +7 -0
- data/lib/hecks/projections/deploy/templates/lambda/rust_oauth_env.tmpl +17 -0
- data/lib/hecks/projections/deploy/templates/lambda/rust_oauth_policy.tmpl +16 -0
- data/lib/hecks/projections/deploy/templates/lambda/rust_session_secret.tmpl +13 -0
- data/lib/hecks/projections/deploy/templates/lambda/samconfig.toml.tmpl +12 -0
- data/lib/hecks/projections/deploy/templates/lambda/shared_note.tmpl +6 -0
- data/lib/hecks/projections/deploy/templates/lambda/sync_oauth.tmpl +23 -0
- data/lib/hecks/projections/deploy/templates/lambda/template.yaml.tmpl +187 -0
- data/lib/hecks/projections/deploy/templates/lambda/translation_own.tmpl +46 -0
- data/lib/hecks/projections/deploy/templates/lambda/translation_shared.tmpl +2 -0
- data/lib/hecks/projections/deploy/templates/lambda/web_function.tmpl +207 -0
- data/lib/hecks/projections/deploy/templates/lambda/web_google_oauth_env.tmpl +12 -0
- data/lib/hecks/projections/deploy/templates/lambda/web_no_oauth_env.tmpl +7 -0
- data/lib/hecks/projections/deploy/templates/lambda/web_oauth_policy.tmpl +4 -0
- data/lib/hecks/projections/deploy/templates/lambda/webhook_secret_resource.tmpl +20 -0
- data/lib/hecks/projections/deploy/templates/preview/alb.tmpl +8 -0
- data/lib/hecks/projections/deploy/templates/preview/alb_security_group.tmpl +11 -0
- data/lib/hecks/projections/deploy/templates/preview/assume_role.tmpl +6 -0
- data/lib/hecks/projections/deploy/templates/preview/base_parameters.tmpl +24 -0
- data/lib/hecks/projections/deploy/templates/preview/cluster.tmpl +4 -0
- data/lib/hecks/projections/deploy/templates/preview/container_secret.tmpl +9 -0
- data/lib/hecks/projections/deploy/templates/preview/db_init_script.sh.tmpl +23 -0
- data/lib/hecks/projections/deploy/templates/preview/db_init_secrets.tmpl +5 -0
- data/lib/hecks/projections/deploy/templates/preview/db_init_task.tmpl +39 -0
- data/lib/hecks/projections/deploy/templates/preview/desired_count.tmpl +5 -0
- data/lib/hecks/projections/deploy/templates/preview/distribution.tmpl +24 -0
- data/lib/hecks/projections/deploy/templates/preview/execution_role.tmpl +16 -0
- data/lib/hecks/projections/deploy/templates/preview/header.tmpl +16 -0
- data/lib/hecks/projections/deploy/templates/preview/ingress.tmpl +8 -0
- data/lib/hecks/projections/deploy/templates/preview/listener.tmpl +9 -0
- data/lib/hecks/projections/deploy/templates/preview/listener_rule.tmpl +11 -0
- data/lib/hecks/projections/deploy/templates/preview/log_group.tmpl +5 -0
- data/lib/hecks/projections/deploy/templates/preview/log_options.tmpl +5 -0
- data/lib/hecks/projections/deploy/templates/preview/outputs.tmpl +14 -0
- data/lib/hecks/projections/deploy/templates/preview/service.tmpl +17 -0
- data/lib/hecks/projections/deploy/templates/preview/session_secret.tmpl +11 -0
- data/lib/hecks/projections/deploy/templates/preview/target_group.tmpl +9 -0
- data/lib/hecks/projections/deploy/templates/preview/task_definition.tmpl +15 -0
- data/lib/hecks/projections/deploy/templates/preview/task_role.tmpl +22 -0
- data/lib/hecks/projections/deploy/templates/shared/aurora_db.tmpl +52 -0
- data/lib/hecks/projections/deploy/templates/shared/bastion.tmpl +74 -0
- data/lib/hecks/projections/deploy/templates/shared/bastion_own_public.tmpl +41 -0
- data/lib/hecks/projections/deploy/templates/shared/bastion_reuse_public.tmpl +10 -0
- data/lib/hecks/projections/deploy/templates/shared/nat_gateway.tmpl +102 -0
- data/lib/hecks/projections/deploy/templates/shared/oauth_egress.tmpl +17 -0
- data/lib/hecks/projections/deploy/templates/shared/plain_db.tmpl +16 -0
- data/lib/hecks/projections/deploy/templates/shared/vpc_and_database.tmpl +67 -0
- data/lib/hecks/projections/deploy/text_template.rb +35 -0
- data/lib/hecks/projections/diagrams/dispatch.rb +114 -0
- data/lib/hecks/projections/diagrams/statecharts.rb +59 -0
- data/lib/hecks/projections/diagrams/structure.rb +114 -0
- data/lib/hecks/projections/diagrams.rb +33 -256
- data/lib/hecks/projections/glossary/entries.rb +140 -0
- data/lib/hecks/projections/glossary/html/page.rb +96 -0
- data/lib/hecks/projections/glossary/html/parser.rb +66 -0
- data/lib/hecks/projections/glossary/html/sections.rb +78 -0
- data/lib/hecks/projections/glossary/html.rb +7 -179
- data/lib/hecks/projections/glossary/index.rb +45 -0
- data/lib/hecks/projections/glossary/markdown.rb +22 -11
- data/lib/hecks/projections/glossary/mermaid.rb +44 -31
- data/lib/hecks/projections/glossary/sensitivity.rb +7 -4
- data/lib/hecks/projections/glossary/sentences/value_objects.rb +77 -0
- data/lib/hecks/projections/glossary/sentences.rb +42 -81
- data/lib/hecks/projections/glossary/slugs.rb +33 -0
- data/lib/hecks/projections/glossary.rb +22 -190
- data/lib/hecks/projections/model.rb +20 -14
- data/lib/hecks/projections/rust_vocabulary/arguments/support.rb +33 -0
- data/lib/hecks/projections/rust_vocabulary/arguments.rb +171 -0
- data/lib/hecks/projections/rust_vocabulary/enum_body.rb +114 -0
- data/lib/hecks/projections/rust_vocabulary/tests.rb +144 -0
- data/lib/hecks/projections/rust_vocabulary.rb +24 -293
- data/lib/hecks/projections/site/admin.rb +146 -0
- data/lib/hecks/projections/site/admin_cms/templates/membership.rb +115 -0
- data/lib/hecks/projections/site/admin_cms/templates/session_strategy.rb +90 -0
- data/lib/hecks/projections/site/admin_cms/templates/sso.rb +101 -0
- data/lib/hecks/projections/site/admin_cms/templates/sso_tail.rb +54 -0
- data/lib/hecks/projections/site/admin_cms/templates/users.rb +83 -0
- data/lib/hecks/projections/site/admin_cms/templates.rb +33 -0
- data/lib/hecks/projections/site/admin_cms.rb +78 -0
- data/lib/hecks/projections/site/edge/behaviours.rb +10 -6
- data/lib/hecks/projections/site/edge/checks.rb +30 -80
- data/lib/hecks/projections/site/edge/findings.rb +28 -0
- data/lib/hecks/projections/site/edge/route_checks.rb +110 -0
- data/lib/hecks/projections/site/edge/row_reader.rb +52 -0
- data/lib/hecks/projections/site/edge/rules.rb +28 -26
- data/lib/hecks/projections/site/edge.rb +20 -31
- data/lib/hecks/projections/site/live_edge.rb +9 -7
- data/lib/hecks/projections/site/payload/fields/definitions.rb +90 -0
- data/lib/hecks/projections/site/payload/fields/readers.rb +69 -0
- data/lib/hecks/projections/site/payload/fields.rb +137 -0
- data/lib/hecks/projections/site/payload/lifecycle/text.rb +84 -0
- data/lib/hecks/projections/site/payload/lifecycle/text_tail.rb +106 -0
- data/lib/hecks/projections/site/payload/lifecycle.rb +33 -0
- data/lib/hecks/projections/site/payload/model.rb +128 -0
- data/lib/hecks/projections/site/payload/specs/wire.rb +69 -0
- data/lib/hecks/projections/site/payload/specs.rb +135 -0
- data/lib/hecks/projections/site/payload_driver.rb +95 -0
- data/lib/hecks/projections/site/root_rows.rb +67 -0
- data/lib/hecks/projections/site/routes_ts/helpers.rb +79 -0
- data/lib/hecks/projections/site/routes_ts/listings.rb +75 -0
- data/lib/hecks/projections/site/routes_ts/navigation.rb +79 -0
- data/lib/hecks/projections/site/routes_ts.rb +27 -175
- data/lib/hecks/projections/site/site_admin/access.rb +104 -0
- data/lib/hecks/projections/site/site_admin/session.rb +127 -0
- data/lib/hecks/projections/site/site_admin.rb +85 -0
- data/lib/hecks/projections/site/site_cdn.rb +12 -7
- data/lib/hecks/projections/site/site_host/dockerfile.rb +75 -0
- data/lib/hecks/projections/site/site_host/templates.rb +109 -0
- data/lib/hecks/projections/site/site_host.rb +58 -0
- data/lib/hecks/projections/site/site_root/workflow.rb +65 -0
- data/lib/hecks/projections/site/site_root.rb +128 -0
- data/lib/hecks/projections/site/table/checks.rb +28 -57
- data/lib/hecks/projections/site/table/link_builder.rb +14 -5
- data/lib/hecks/projections/site/table/navigation_checks.rb +75 -0
- data/lib/hecks/projections/site/table/row_builder.rb +31 -53
- data/lib/hecks/projections/site/table/row_defaults.rb +65 -0
- data/lib/hecks/projections/site/table.rb +9 -5
- data/lib/hecks/projections/vocabulary.rb +34 -31
- data/lib/hecks/projector/cli_audience.rb +42 -0
- data/lib/hecks/projector/cli_projector/claims.rb +149 -0
- data/lib/hecks/projector/cli_projector/command_help.rb +65 -0
- data/lib/hecks/projector/cli_projector/command_specs.rb +133 -0
- data/lib/hecks/projector/cli_projector/listing.rb +100 -0
- data/lib/hecks/projector/cli_projector/option_specs.rb +116 -0
- data/lib/hecks/projector/cli_projector/query_specs.rb +67 -0
- data/lib/hecks/projector/cli_projector/usage.rb +101 -0
- data/lib/hecks/projector/cli_projector.rb +15 -532
- data/lib/hecks/projector/docs_projector/attributes.rb +78 -0
- data/lib/hecks/projector/docs_projector/behaviour.rb +127 -0
- data/lib/hecks/projector/docs_projector/closing.rb +40 -0
- data/lib/hecks/projector/docs_projector.rb +58 -192
- data/lib/hecks/projector/exporter/bindings.rb +174 -0
- data/lib/hecks/projector/exporter/translations.rb +127 -0
- data/lib/hecks/projector/exporter.rb +8 -279
- data/lib/hecks/projector/narrate_projector/commands.rb +108 -0
- data/lib/hecks/projector/narrate_projector/reactions.rb +33 -0
- data/lib/hecks/projector/narrate_projector.rb +60 -160
- data/lib/hecks/projector.rb +22 -13
- data/lib/hecks/quality_control/adapters/agent_profile.rb +25 -16
- data/lib/hecks/quality_control/adapters/github_checks.rb +42 -6
- data/lib/hecks/quality_control/adapters/github_ci_webhook.rb +1 -1
- data/lib/hecks/quality_control/adapters/github_issues.rb +22 -10
- data/lib/hecks/quality_control/cli/qa_discover_external_domains/parsing.rb +54 -0
- data/lib/hecks/quality_control/cli/qa_discover_external_domains/reporting.rb +44 -0
- data/lib/hecks/quality_control/cli/qa_discover_external_domains/scanning.rb +119 -0
- data/lib/hecks/quality_control/cli/qa_discover_external_domains.rb +28 -155
- data/lib/hecks/quality_control/cli/qa_domain_novelty/verdict.rb +76 -0
- data/lib/hecks/quality_control/cli/qa_domain_novelty.rb +33 -66
- data/lib/hecks/quality_control/cli/qa_generated_domains/arguments.rb +62 -0
- data/lib/hecks/quality_control/cli/qa_generated_domains/blueprints.rb +45 -0
- data/lib/hecks/quality_control/cli/qa_generated_domains/evaluation.rb +107 -0
- data/lib/hecks/quality_control/cli/qa_generated_domains/promotion.rb +107 -0
- data/lib/hecks/quality_control/cli/qa_generated_domains/reporting.rb +97 -0
- data/lib/hecks/quality_control/cli/qa_generated_domains/shrinking.rb +70 -0
- data/lib/hecks/quality_control/cli/qa_generated_domains.rb +43 -327
- data/lib/hecks/quality_control/cli/qa_log_bug/arguments.rb +55 -0
- data/lib/hecks/quality_control/cli/qa_log_bug/proof.rb +65 -0
- data/lib/hecks/quality_control/cli/qa_log_bug.rb +18 -81
- data/lib/hecks/quality_control/cli/qa_mine_combinations/arguments.rb +54 -0
- data/lib/hecks/quality_control/cli/qa_mine_combinations/booting.rb +96 -0
- data/lib/hecks/quality_control/cli/qa_mine_combinations.rb +45 -109
- data/lib/hecks/quality_control/cli/qa_open_pr/arguments.rb +55 -0
- data/lib/hecks/quality_control/cli/qa_open_pr/recording.rb +79 -0
- data/lib/hecks/quality_control/cli/qa_open_pr/rules.rb +122 -0
- data/lib/hecks/quality_control/cli/qa_open_pr.rb +41 -200
- data/lib/hecks/quality_control/cli/qa_postgres_migrate/copying.rb +45 -0
- data/lib/hecks/quality_control/cli/qa_postgres_migrate/reporting.rb +33 -0
- data/lib/hecks/quality_control/cli/qa_postgres_migrate.rb +37 -63
- data/lib/hecks/quality_control/cli/qa_postgres_role/ownership.rb +57 -0
- data/lib/hecks/quality_control/cli/qa_postgres_role.rb +66 -71
- data/lib/hecks/quality_control/cli/qa_pr_check/checking.rb +118 -0
- data/lib/hecks/quality_control/cli/qa_pr_check/reporting.rb +54 -0
- data/lib/hecks/quality_control/cli/qa_pr_check.rb +28 -145
- data/lib/hecks/quality_control/cli/qa_seed_angles/seed.rb +80 -0
- data/lib/hecks/quality_control/cli/qa_seed_angles.rb +13 -86
- data/lib/hecks/quality_control/cli/qa_sweep/all_mode/children.rb +80 -0
- data/lib/hecks/quality_control/cli/qa_sweep/all_mode/report.rb +125 -0
- data/lib/hecks/quality_control/cli/qa_sweep/all_mode.rb +63 -193
- data/lib/hecks/quality_control/cli/qa_sweep/checks/boundary.rb +92 -0
- data/lib/hecks/quality_control/cli/qa_sweep/checks/engines.rb +92 -0
- data/lib/hecks/quality_control/cli/qa_sweep/checks/seeds.rb +86 -0
- data/lib/hecks/quality_control/cli/qa_sweep/checks/shrinking.rb +69 -0
- data/lib/hecks/quality_control/cli/qa_sweep/checks.rb +10 -248
- data/lib/hecks/quality_control/cli/qa_sweep/conclusion.rb +60 -0
- data/lib/hecks/quality_control/cli/qa_sweep/depth.rb +61 -0
- data/lib/hecks/quality_control/cli/qa_sweep/dials.rb +26 -13
- data/lib/hecks/quality_control/cli/qa_sweep/finding_report/shrunk.rb +42 -0
- data/lib/hecks/quality_control/cli/qa_sweep/finding_report.rb +40 -41
- data/lib/hecks/quality_control/cli/qa_sweep/parsing/validation.rb +70 -0
- data/lib/hecks/quality_control/cli/qa_sweep/parsing.rb +35 -65
- data/lib/hecks/quality_control/cli/qa_sweep/release_mode.rb +41 -22
- data/lib/hecks/quality_control/cli/qa_sweep/scratch.rb +67 -0
- data/lib/hecks/quality_control/cli/qa_sweep/seat.rb +94 -0
- data/lib/hecks/quality_control/cli/qa_sweep/seed_loop.rb +149 -0
- data/lib/hecks/quality_control/cli/qa_sweep/target_setup.rb +115 -0
- data/lib/hecks/quality_control/cli/qa_sweep.rb +22 -445
- data/lib/hecks/quality_control/cli/qa_tick/output.rb +107 -0
- data/lib/hecks/quality_control/cli/qa_tick/preflight.rb +95 -0
- data/lib/hecks/quality_control/cli/qa_tick.rb +42 -175
- data/lib/hecks/query_ir/formatting.rb +86 -0
- data/lib/hecks/query_ir/rules.rb +132 -0
- data/lib/hecks/query_ir/touchpoints.rb +104 -0
- data/lib/hecks/query_ir.rb +33 -281
- data/lib/hecks/query_ir_mcp/tools.rb +68 -0
- data/lib/hecks/query_ir_mcp.rb +27 -71
- data/lib/hecks/query_specification/common/comparison.rb +25 -5
- data/lib/hecks/query_specification/common/dsl.rb +1 -1
- data/lib/hecks/query_specification/common/null_policy.rb +9 -6
- data/lib/hecks/query_specification/common/options.rb +21 -14
- data/lib/hecks/query_specification/field_path.rb +5 -2
- data/lib/hecks/query_specification/hop_path.rb +15 -18
- data/lib/hecks/release/lane.rb +22 -0
- data/lib/hecks/release/runner/clean_tree.rb +2 -2
- data/lib/hecks/release/runner/commands.rb +1 -1
- data/lib/hecks/release/runner/options.rb +82 -0
- data/lib/hecks/release/runner/preflight.rb +12 -7
- data/lib/hecks/release/runner/publishing.rb +86 -0
- data/lib/hecks/release/runner/tagger.rb +8 -3
- data/lib/hecks/release/runner.rb +40 -156
- data/lib/hecks/rendering.rb +13 -9
- data/lib/hecks/router/door.rb +37 -0
- data/lib/hecks/router/namespace_installer.rb +45 -83
- data/lib/hecks/router/options_proxy.rb +44 -0
- data/lib/hecks/runtime/adapter_lookup.rb +45 -24
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +16 -8
- data/lib/hecks/runtime/command_interpreter/delegation.rb +116 -0
- data/lib/hecks/runtime/command_interpreter/enforcement.rb +38 -0
- data/lib/hecks/runtime/command_interpreter/hydration.rb +139 -0
- data/lib/hecks/runtime/command_interpreter/list_mutations.rb +98 -0
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +67 -114
- data/lib/hecks/runtime/command_interpreter/persisting.rb +96 -0
- data/lib/hecks/runtime/command_interpreter.rb +57 -352
- data/lib/hecks/runtime/command_rules/admissibility.rb +64 -147
- data/lib/hecks/runtime/command_rules/arithmetic.rb +13 -72
- data/lib/hecks/runtime/command_rules/authorization.rb +9 -9
- data/lib/hecks/runtime/command_rules/emission.rb +13 -14
- data/lib/hecks/runtime/command_rules/guard_state.rb +49 -0
- data/lib/hecks/runtime/command_rules/invariants.rb +84 -0
- data/lib/hecks/runtime/command_rules/operands.rb +88 -0
- data/lib/hecks/runtime/command_rules/references.rb +59 -57
- data/lib/hecks/runtime/command_rules/tenant_boundary.rb +69 -0
- data/lib/hecks/runtime/dependency_planning/analyzer.rb +90 -0
- data/lib/hecks/runtime/dependency_planning/expression_reads.rb +73 -0
- data/lib/hecks/runtime/dependency_planning/mutation_analysis.rb +89 -0
- data/lib/hecks/runtime/dependency_planning/rule_analysis.rb +82 -0
- data/lib/hecks/runtime/dependency_planning.rb +3 -250
- data/lib/hecks/runtime/dispatcher/queries.rb +62 -0
- data/lib/hecks/runtime/dispatcher/result.rb +55 -0
- data/lib/hecks/runtime/dispatcher/routing.rb +107 -0
- data/lib/hecks/runtime/dispatcher.rb +64 -209
- data/lib/hecks/runtime/entity_element/location.rb +124 -0
- data/lib/hecks/runtime/entity_element/mutations.rb +150 -0
- data/lib/hecks/runtime/entity_element.rb +5 -177
- data/lib/hecks/runtime/entity_interpreter/enforcement.rb +51 -0
- data/lib/hecks/runtime/entity_interpreter/locating.rb +62 -0
- data/lib/hecks/runtime/entity_interpreter/resolution.rb +42 -0
- data/lib/hecks/runtime/entity_interpreter/saving.rb +49 -0
- data/lib/hecks/runtime/entity_interpreter.rb +45 -164
- data/lib/hecks/runtime/identity.rb +15 -9
- data/lib/hecks/runtime/instance.rb +11 -7
- data/lib/hecks/runtime/interpreting.rb +16 -8
- data/lib/hecks/runtime/invocation.rb +3 -155
- data/lib/hecks/runtime/invocation_builder.rb +132 -0
- data/lib/hecks/runtime/invocation_facts.rb +87 -0
- data/lib/hecks/runtime/loader/boot_steps.rb +96 -0
- data/lib/hecks/runtime/loader/described.rb +27 -0
- data/lib/hecks/runtime/loader.rb +27 -114
- data/lib/hecks/runtime/outbox/consumer_runner.rb +40 -0
- data/lib/hecks/runtime/outbox/fanout.rb +82 -0
- data/lib/hecks/runtime/outbox/relay.rb +149 -0
- data/lib/hecks/runtime/outbox.rb +3 -214
- data/lib/hecks/runtime/policy_interpreter/arguments.rb +67 -0
- data/lib/hecks/runtime/policy_interpreter/fan_out.rb +96 -0
- data/lib/hecks/runtime/policy_interpreter.rb +22 -137
- data/lib/hecks/runtime/port_operation_interpreter.rb +18 -17
- data/lib/hecks/runtime/query_interpreter/arguments.rb +51 -0
- data/lib/hecks/runtime/query_interpreter/entity_rows.rb +82 -0
- data/lib/hecks/runtime/query_interpreter/outside_answer.rb +89 -0
- data/lib/hecks/runtime/query_interpreter.rb +43 -191
- data/lib/hecks/runtime/reaction_invocation/identities.rb +92 -0
- data/lib/hecks/runtime/reaction_invocation/target_resolution.rb +88 -0
- data/lib/hecks/runtime/reaction_invocation.rb +66 -183
- data/lib/hecks/runtime/reaction_outcome.rb +7 -3
- data/lib/hecks/runtime/read_model_interpreter/head_ordering.rb +49 -0
- data/lib/hecks/runtime/read_model_interpreter/reductions.rb +123 -0
- data/lib/hecks/runtime/read_model_interpreter/shaping.rb +100 -0
- data/lib/hecks/runtime/read_model_interpreter.rb +71 -214
- data/lib/hecks/runtime/reference_hop.rb +11 -11
- data/lib/hecks/runtime/refusal_wording.rb +11 -8
- data/lib/hecks/runtime/registry/chapter_verification.rb +84 -0
- data/lib/hecks/runtime/registry/declarations.rb +17 -0
- data/lib/hecks/runtime/registry/durability_warnings.rb +71 -0
- data/lib/hecks/runtime/registry/hecksagon_rules.rb +124 -0
- data/lib/hecks/runtime/registry/merging.rb +49 -0
- data/lib/hecks/runtime/registry/providers.rb +139 -0
- data/lib/hecks/runtime/registry/query_verification.rb +144 -0
- data/lib/hecks/runtime/registry/read_repository.rb +61 -0
- data/lib/hecks/runtime/registry/runtime_state.rb +27 -0
- data/lib/hecks/runtime/registry/saga_persistence.rb +12 -8
- data/lib/hecks/runtime/registry/verification.rb +45 -389
- data/lib/hecks/runtime/registry/world_defaults.rb +3 -3
- data/lib/hecks/runtime/registry.rb +58 -296
- data/lib/hecks/runtime/remote_dispatcher.rb +47 -31
- data/lib/hecks/runtime/saga_interpreter/compensation.rb +90 -0
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +19 -10
- data/lib/hecks/runtime/saga_interpreter/delivery.rb +147 -0
- data/lib/hecks/runtime/saga_interpreter/lifecycle.rb +63 -0
- data/lib/hecks/runtime/saga_interpreter/transitions.rb +112 -0
- data/lib/hecks/runtime/saga_interpreter.rb +41 -320
- data/lib/hecks/runtime/tenant_check.rb +14 -9
- data/lib/hecks/runtime/value/admission.rb +28 -19
- data/lib/hecks/runtime/value/coercion.rb +55 -404
- data/lib/hecks/runtime/value/entity_list_coercion.rb +27 -29
- data/lib/hecks/runtime/value/field_checks.rb +57 -100
- data/lib/hecks/runtime/value/flags.rb +65 -0
- data/lib/hecks/runtime/value/identifiers.rb +64 -0
- data/lib/hecks/runtime/value/references.rb +195 -0
- data/lib/hecks/runtime/value/shape_checks.rb +61 -0
- data/lib/hecks/runtime/value/validation.rb +125 -0
- data/lib/hecks/runtime/value.rb +18 -6
- data/lib/hecks/rust_build/conformance/surface.rb +75 -0
- data/lib/hecks/rust_build/conformance.rb +27 -59
- data/lib/hecks/rust_build/conformance_fuzz.rb +26 -15
- data/lib/hecks/rust_build/coverage.rb +32 -104
- data/lib/hecks/rust_build/coverage_parts/expected.rb +68 -0
- data/lib/hecks/rust_build/coverage_parts/printer.rb +75 -0
- data/lib/hecks/rust_build/host.rb +23 -13
- data/lib/hecks/rust_build/kernel_input.rb +19 -12
- data/lib/hecks/rust_build/native_build.rb +19 -15
- data/lib/hecks/rust_build/project_rust/domain_loader.rb +75 -0
- data/lib/hecks/rust_build/project_rust/root_mod/notes.rb +66 -0
- data/lib/hecks/rust_build/project_rust/root_mod.rb +22 -55
- data/lib/hecks/rust_build/project_rust/target_ir.rb +74 -0
- data/lib/hecks/rust_build/project_rust.rb +21 -89
- data/lib/hecks/rust_build/wasm.rb +11 -4
- data/lib/hecks/rust_build/wasm_browser.rb +7 -7
- data/lib/hecks/rust_build/write_if_changed.rb +3 -6
- data/lib/hecks/rust_build.rb +7 -3
- data/lib/hecks/site/bluebook/site.bluebook +7 -1
- data/lib/hecks/storehouse/audit.rb +106 -0
- data/lib/hecks/storehouse/callers.rb +73 -0
- data/lib/hecks/storehouse/dispatching.rb +149 -0
- data/lib/hecks/storehouse/introspection.rb +145 -0
- data/lib/hecks/storehouse/querying.rb +78 -0
- data/lib/hecks/storehouse.rb +43 -451
- data/lib/hecks/tickets/bluebook/tickets.bluebook +29 -0
- data/lib/hecks/tools/argument_gate_matrix/dispatching.rb +69 -0
- data/lib/hecks/tools/argument_gate_matrix/rows.rb +121 -0
- data/lib/hecks/tools/argument_gate_matrix/violations.rb +108 -0
- data/lib/hecks/tools/argument_gate_matrix.rb +43 -212
- data/lib/hecks/tools/ci_gate_decision.rb +21 -14
- data/lib/hecks/tools/ci_gates.rb +40 -26
- data/lib/hecks/tools/comment_style/baseline.rb +41 -0
- data/lib/hecks/tools/comment_style/caps_words.rb +104 -0
- data/lib/hecks/tools/comment_style/cli.rb +121 -0
- data/lib/hecks/tools/comment_style/dictionary.rb +60 -0
- data/lib/hecks/tools/comment_style/fixing.rb +119 -0
- data/lib/hecks/tools/comment_style/long_blocks.rb +51 -0
- data/lib/hecks/tools/comment_style/masking.rb +94 -0
- data/lib/hecks/tools/comment_style/patterns.rb +61 -0
- data/lib/hecks/tools/comment_style/run.rb +161 -0
- data/lib/hecks/tools/comment_style/signature.rb +59 -0
- data/lib/hecks/tools/comment_style/source_file.rb +105 -0
- data/lib/hecks/tools/comment_style/structure_checks.rb +113 -0
- data/lib/hecks/tools/comment_style/text_checks.rb +67 -0
- data/lib/hecks/tools/comment_style/vocabulary.rb +55 -0
- data/lib/hecks/tools/comment_style/walker.rb +136 -0
- data/lib/hecks/tools/comment_style.rb +17 -1000
- data/lib/hecks/tools/corpus_report.rb +26 -16
- data/lib/hecks/tools/deploy_recipe/targets.rb +61 -0
- data/lib/hecks/tools/deploy_recipe/worlds.rb +114 -0
- data/lib/hecks/tools/deploy_recipe.rb +60 -174
- data/lib/hecks/tools/deploy_recipe_lint/checks.rb +78 -0
- data/lib/hecks/tools/deploy_recipe_lint/fixtures.rb +88 -0
- data/lib/hecks/tools/deploy_recipe_lint/makefile.rb +84 -0
- data/lib/hecks/tools/deploy_recipe_lint.rb +29 -192
- data/lib/hecks/tools/drop_implicit_append_fields.rb +20 -12
- data/lib/hecks/tools/era_projection_backfill.rb +50 -33
- data/lib/hecks/tools/era_reattest/reporting.rb +55 -0
- data/lib/hecks/tools/era_reattest.rb +32 -43
- data/lib/hecks/tools/evolve_run/arguments.rb +49 -0
- data/lib/hecks/tools/evolve_run/words.rb +60 -0
- data/lib/hecks/tools/evolve_run.rb +43 -90
- data/lib/hecks/tools/fuzz_sweep/findings.rb +106 -0
- data/lib/hecks/tools/fuzz_sweep/options.rb +69 -0
- data/lib/hecks/tools/fuzz_sweep/pool.rb +74 -0
- data/lib/hecks/tools/fuzz_sweep/reporting.rb +88 -0
- data/lib/hecks/tools/fuzz_sweep.rb +75 -273
- data/lib/hecks/tools/gate.rb +31 -16
- data/lib/hecks/tools/heki_compaction.rb +63 -42
- data/lib/hecks/tools/hoist_local_givens/rewriting.rb +119 -0
- data/lib/hecks/tools/hoist_local_givens.rb +89 -157
- data/lib/hecks/tools/journal_compaction.rb +40 -31
- data/lib/hecks/tools/lanes/files.rb +82 -0
- data/lib/hecks/tools/lanes/live.rb +41 -0
- data/lib/hecks/tools/lanes/rows.rb +45 -0
- data/lib/hecks/tools/lanes/ruleset.rb +44 -0
- data/lib/hecks/tools/lanes/watch_workflow.rb +82 -0
- data/lib/hecks/tools/lanes/workflow.rb +79 -0
- data/lib/hecks/tools/lanes.rb +71 -0
- data/lib/hecks/tools/oidc_manifests.rb +10 -9
- data/lib/hecks/tools/query_ir_run.rb +7 -3
- data/lib/hecks/tools/regeneration_run.rb +40 -26
- data/lib/hecks/tools/rust_comment_style/caps_words.rb +98 -0
- data/lib/hecks/tools/rust_comment_style/fixing.rb +102 -0
- data/lib/hecks/tools/rust_comment_style/masking.rb +85 -0
- data/lib/hecks/tools/rust_comment_style/run.rb +94 -0
- data/lib/hecks/tools/rust_comment_style/source_file.rb +71 -0
- data/lib/hecks/tools/rust_comment_style/structure.rb +79 -0
- data/lib/hecks/tools/rust_comment_style/text_checks.rb +63 -0
- data/lib/hecks/tools/rust_comment_style/tokenizer.rb +102 -0
- data/lib/hecks/tools/rust_comment_style.rb +38 -535
- data/lib/hecks/tools/sequence_script.rb +20 -14
- data/lib/hecks/tools/site_routes/cli.rb +70 -0
- data/lib/hecks/tools/site_routes/root_files.rb +59 -0
- data/lib/hecks/tools/site_routes/templates.rb +77 -0
- data/lib/hecks/tools/site_routes.rb +102 -108
- data/lib/hecks/tools/tail_merge.rb +45 -37
- data/lib/hecks/tools/tenant_provisioning.rb +45 -31
- data/lib/hecks/tools/tools_doc.rb +42 -19
- data/lib/hecks/tools/translation_audit/domain_loading.rb +71 -0
- data/lib/hecks/tools/translation_audit/edges.rb +71 -0
- data/lib/hecks/tools/translation_audit/verdicts.rb +107 -0
- data/lib/hecks/tools/translation_audit.rb +30 -161
- data/lib/hecks/tools/translation_scaffold/reporting.rb +40 -0
- data/lib/hecks/tools/translation_scaffold.rb +77 -60
- data/lib/hecks/tools.rb +1 -0
- data/lib/hecks/vendoring.rb +37 -11
- data/lib/hecks/version.rb +1 -1
- data/lib/hecks/vocabulary.rb +16 -1
- data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +7 -9
- data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +8 -6
- data/rust/.cargo/mutants.toml +8 -0
- data/rust/host/Cargo.toml +5 -0
- data/rust/host/HECKS_RELEASE +1 -1
- data/rust/host/src/auth.rs +32 -0
- data/rust/host/src/web.rs +2 -3
- data/rust/src/kernel/dispatch.rs +4 -0
- data/rust/src/kernel/dispatch_guard_tests.rs +506 -0
- data/rust/src/kernel/orchestrate.rs +4 -0
- data/rust/src/kernel/orchestrate_guard_tests.rs +708 -0
- metadata +607 -3
- /data/lib/hecks/bluebook/behaviour/{hexagon.rb → hecksagon.rb} +0 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
module Hecks
|
|
2
|
+
module Fuzzing
|
|
3
|
+
module Properties
|
|
4
|
+
# Tenant-scoping property over a replayed history: no stored record references a record
|
|
5
|
+
# carrying a different tenant value.
|
|
6
|
+
module TenantScope
|
|
7
|
+
# One stored record under inspection: where it lives, its state, and its own tenant.
|
|
8
|
+
Record = Struct.new(:bluebooks, :instances, :key, :domain_name, :state, :field, :tenant) do
|
|
9
|
+
# The aggregate called `name` in the record's own domain, or nil.
|
|
10
|
+
def aggregate_named(name) = bluebooks[domain_name]&.aggregate(name)
|
|
11
|
+
|
|
12
|
+
# The key of the stored record `id` of `target` in the record's own domain.
|
|
13
|
+
def target_key(target, id) = "#{domain_name}::#{target.name}##{id}"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Checks that no stored record references a record carrying a different tenant value.
|
|
17
|
+
#
|
|
18
|
+
# Commands cannot declare `authorize`, so nothing refuses a cross-tenant write.
|
|
19
|
+
# Tenants compare via Query::InMemory.comparable: value objects with different
|
|
20
|
+
# declared names are unequal under Value#== even for the same tenant.
|
|
21
|
+
def commands_respect_tenant_scope(history)
|
|
22
|
+
bluebooks = history.fetch(:bluebooks)
|
|
23
|
+
instances = history.fetch(:instances)
|
|
24
|
+
offenders = instances.flat_map { |key, state| tenant_offenders(bluebooks, instances, key, state) }
|
|
25
|
+
offenders.empty? || offenders.join("; ")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# One message per reference of the stored record `key` that crosses a tenant.
|
|
29
|
+
def tenant_offenders(bluebooks, instances, key, state)
|
|
30
|
+
domain_name = key.split("::").first
|
|
31
|
+
aggregate = aggregate_for_key(bluebooks, key)
|
|
32
|
+
return [] unless aggregate
|
|
33
|
+
|
|
34
|
+
field = tenant_field_for(aggregate)
|
|
35
|
+
return [] unless field && state.key?(field)
|
|
36
|
+
|
|
37
|
+
record = Record.new(bluebooks, instances, key, domain_name, state, field,
|
|
38
|
+
Ports::Query::InMemory.comparable(state[field]))
|
|
39
|
+
aggregate.attributes.filter_map { |attribute| cross_tenant_offense(record, attribute) }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# The aggregate a stored-record key `Domain::Aggregate#id` belongs to, or nil.
|
|
43
|
+
def aggregate_for_key(bluebooks, key)
|
|
44
|
+
bluebooks[key.split("::").first]&.aggregate(key.split("::").last.split("#").first)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# The message for one reference whose target carries a different tenant, or nil.
|
|
48
|
+
def cross_tenant_offense(record, attribute)
|
|
49
|
+
return unless attribute.type.is_a?(Bluebook::Reference)
|
|
50
|
+
|
|
51
|
+
target = record.aggregate_named(attribute.type.target_name)
|
|
52
|
+
target_id = record.state[attribute.name]
|
|
53
|
+
return unless target && target_id
|
|
54
|
+
|
|
55
|
+
target_field, target_tenant = referenced_tenant(record, target, target_id)
|
|
56
|
+
return if target_field.nil? || target_tenant == record.tenant
|
|
57
|
+
|
|
58
|
+
cross_tenant_message(record, "#{attribute.name}: #{target_id.inspect}",
|
|
59
|
+
record.target_key(target, target_id), target_field, target_tenant)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def cross_tenant_message(record, reference, target_key, target_field, target_tenant)
|
|
63
|
+
"#{record.key} (#{record.field}: #{record.tenant.inspect}) references #{reference}, " \
|
|
64
|
+
"but #{target_key} carries #{target_field}: #{target_tenant.inspect} — a cross-tenant write nothing refused"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# The tenant field and value of the stored record `target_id` names, or nil.
|
|
68
|
+
def referenced_tenant(record, target, target_id)
|
|
69
|
+
target_field = tenant_field_for(target)
|
|
70
|
+
target_state = record.instances[record.target_key(target, target_id)]
|
|
71
|
+
return unless target_field && target_state&.key?(target_field)
|
|
72
|
+
|
|
73
|
+
[target_field, Ports::Query::InMemory.comparable(target_state[target_field])]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# The field named by `authorize ..., tenant:` on any of the aggregate's queries, or nil.
|
|
77
|
+
def tenant_field_for(aggregate)
|
|
78
|
+
authorization = aggregate.queries.filter_map(&:authorization).find(&:tenant)
|
|
79
|
+
authorization&.tenant&.to_sym
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -11,6 +11,9 @@ require_relative "properties/dispatch_and_mutations"
|
|
|
11
11
|
require_relative "properties/invariants_and_aggregation"
|
|
12
12
|
require_relative "properties/corrections"
|
|
13
13
|
require_relative "properties/outbox"
|
|
14
|
+
require_relative "properties/policy_wiring"
|
|
15
|
+
require_relative "properties/references"
|
|
16
|
+
require_relative "properties/catalog"
|
|
14
17
|
|
|
15
18
|
module Hecks
|
|
16
19
|
module Fuzzing
|
|
@@ -27,110 +30,11 @@ module Hecks
|
|
|
27
30
|
extend InvariantsAndAggregation
|
|
28
31
|
extend Corrections
|
|
29
32
|
extend Outbox
|
|
33
|
+
extend PolicyWiring
|
|
34
|
+
extend References
|
|
30
35
|
|
|
31
36
|
module_function
|
|
32
37
|
|
|
33
|
-
# Which language feature each property is answerable for — exhaustive of
|
|
34
|
-
# what would go unchecked without it, not of everything its body touches.
|
|
35
|
-
FEATURE_COVERAGE = {
|
|
36
|
-
lifecycle_values_are_declared: %w[Aggregate#state_field Aggregate#state_start Aggregate#transitions
|
|
37
|
-
Entity#state_field Entity#state_start Entity#transitions],
|
|
38
|
-
saga_advances_follow_declared_handlers: %w[Handler#from_state Handler#to_state Handler#event_type],
|
|
39
|
-
query_answers_match_reference: %w[Query#wheres Query#order_field Query#order_way Query#limit],
|
|
40
|
-
paging_offset_partitions_correctly: %w[Query#options],
|
|
41
|
-
authorize_scopes_or_refuses: %w[Query#options],
|
|
42
|
-
guard_refusals_are_declared: %w[Command#givens Command#ensures Command#needs],
|
|
43
|
-
lifecycle_guard_and_given_violations_are_refused: %w[Command#from Aggregate#preconditions Entity#preconditions],
|
|
44
|
-
# Dispatch#command_name/with_spec aren't claimable feature names — the
|
|
45
|
-
# coverage walk only reaches one level of entity nesting and Dispatch
|
|
46
|
-
# sits two deep — but this property still checks the real behavior
|
|
47
|
-
# (dispatch_args) those names would have covered.
|
|
48
|
-
dispatch_binding_fidelity: %w[Handler#dispatches Policy#with_spec],
|
|
49
|
-
mutations_match_recompute: %w[Command#mutations],
|
|
50
|
-
sagas_rehydrate_cleanly: %w[ProcessManager#states ProcessManager#correlates_by
|
|
51
|
-
ProcessManager#starts_on ProcessManager#ends_on],
|
|
52
|
-
fanout_dispatches_once_per_matching_row: %w[Policy#for_each Policy#where],
|
|
53
|
-
aggregation_matches_recompute: %w[ReadModel#count ReadModel#median_field ReadModel#sum_field
|
|
54
|
-
ReadModel#avg_field ReadModel#min_field ReadModel#max_field
|
|
55
|
-
ReadModel#percentile_field ReadModel#percentile_at
|
|
56
|
-
ReadModel#any_field ReadModel#all_field],
|
|
57
|
-
stored_records_satisfy_declared_invariants: %w[Aggregate#invariants Entity#invariants],
|
|
58
|
-
group_by_matches_recompute: %w[ReadModel#group_by],
|
|
59
|
-
# A runtime door, not a grammar construct — `Dispatcher#dry_run?` is not
|
|
60
|
-
# a word a bluebook declares. Listed empty rather than omitted, so every
|
|
61
|
-
# property still names what it is answerable for.
|
|
62
|
-
dry_runs_leave_no_trace: [],
|
|
63
|
-
# Another runtime door, not a grammar construct — same reasoning as
|
|
64
|
-
# dry_runs_leave_no_trace above.
|
|
65
|
-
outbox_rows_match_reactions: [],
|
|
66
|
-
# Reads command.mutations for :corrects ops — the same list
|
|
67
|
-
# mutations_match_recompute reads, for a different question.
|
|
68
|
-
corrections_reference_an_emitted_event: %w[Command#mutations],
|
|
69
|
-
# No feature string exists for what this reads: an argument's own
|
|
70
|
-
# `relationship` (Argument is a value object, outside the meta-domain
|
|
71
|
-
# walk). Its declaration side, `Query#options`, is already claimed by
|
|
72
|
-
# authorize_scopes_or_refuses.
|
|
73
|
-
commands_respect_tenant_scope: []
|
|
74
|
-
}.freeze
|
|
75
|
-
|
|
76
|
-
# Features a replay could never observe violated, because construction
|
|
77
|
-
# makes the violation impossible to produce — not untested, but
|
|
78
|
-
# unfalsifiable. Each entry names the runtime path that guarantees it;
|
|
79
|
-
# add one only after reading and confirming that path (mirrors the
|
|
80
|
-
# discipline spec/fuzzing/meta_domain_coverage_spec.rb's KNOWN_GAPS demands
|
|
81
|
-
# in the other direction).
|
|
82
|
-
GUARANTEED_BY_CONSTRUCTION = {
|
|
83
|
-
"Aggregate#attributes" => "every field's pattern/closed-set/type passes through Value.build's one coercion " \
|
|
84
|
-
"door (value/coercion.rb#check_patterns, value/admission.rb) before it can exist " \
|
|
85
|
-
"— a stored value that violated its own declared shape was never producible to " \
|
|
86
|
-
"begin with",
|
|
87
|
-
"Aggregate#value_objects" => "the shape being coerced above — same door, same guarantee",
|
|
88
|
-
# S17, ADR 0026 — saga_advances_follow_declared_handlers already walks
|
|
89
|
-
# this list to find event_type/from_state/to_state; same door, same guarantee.
|
|
90
|
-
"ProcessManager#handlers" => "saga_advances_follow_declared_handlers already walks this list to find " \
|
|
91
|
-
"event_type/from_state/to_state — same door, same guarantee",
|
|
92
|
-
"Aggregate#identified_by" => "CommandInterpreter's data-driven dispatch order refuses AlreadyExists " \
|
|
93
|
-
"(command_interpreter.rb, command.creates?) for every creating command uniformly, " \
|
|
94
|
-
"before a duplicate id can ever be stored — collision is refused at the door, not " \
|
|
95
|
-
"produced and later caught",
|
|
96
|
-
"Entity#identified_by" => "EntityElement.check_entity_collision (runtime/entity_element.rb, moved there " \
|
|
97
|
-
"BUG#145 so both call sites share it) checks Array(current) against every part " \
|
|
98
|
-
"of the entity's own identity before an append can land — MutationApplier#" \
|
|
99
|
-
"entity_element's aggregate-owned call (Workspace.boards, on both branches " \
|
|
100
|
-
"identity arrives by: caller-supplied, or composite) AND EntityElement#" \
|
|
101
|
-
"appended_to_element's entity-owned, nested-one-hop-further call (Board.cards — " \
|
|
102
|
-
"unconditional, no auto-mint branch exists at that depth) — the same " \
|
|
103
|
-
"AlreadyExists refusal Aggregate#identified_by gets above, one or two levels " \
|
|
104
|
-
"down. Auto-minted (aggregate-owned) entities never reach the check " \
|
|
105
|
-
"(current.size + 1 can't repeat unless something remove:s from the list between " \
|
|
106
|
-
"mints, which no real domain does today — see the comment on #entity_element " \
|
|
107
|
-
"itself)",
|
|
108
|
-
"Command#attributes" => "command arguments are coerced through the SAME Value.build door as any other " \
|
|
109
|
-
"attribute — an accepted dispatch's own args already passed pattern/admits/invariant checks",
|
|
110
|
-
"Command#emits" => "CommandRules::Emission#emit iterates command.emits ITSELF to construct every " \
|
|
111
|
-
"announced Event (command_rules/emission.rb) — there is no other path to emit, so " \
|
|
112
|
-
"a command can never announce a name its own declaration doesn't list",
|
|
113
|
-
"Query#attributes" => "query arguments are coerced through the same Value.build door — same guarantee as " \
|
|
114
|
-
"Command#attributes",
|
|
115
|
-
"Query#returns" => "every row a port answers is built as the returned value object by Value.build " \
|
|
116
|
-
"(QueryInterpreter#shaped) before it enters the domain — an answer of any other " \
|
|
117
|
-
"shape is refused, so none can be accepted",
|
|
118
|
-
"Entity#attributes" => "same coercion door, one level in — an entity's own attributes are Value-typed exactly " \
|
|
119
|
-
"the way an aggregate's are",
|
|
120
|
-
"ValueObject#attributes" => "the shape Value.build enforces IS this declaration — the guarantee and the " \
|
|
121
|
-
"feature are the same fact seen from two sides",
|
|
122
|
-
"ValueObject#invariants" => "run inside the SAME coercion call (coercion.rb, before construction returns) " \
|
|
123
|
-
"that pattern-checks a VO's fields — a VO whose invariant did not hold could not " \
|
|
124
|
-
"finish being built",
|
|
125
|
-
"ValueObject#rows" => "closed-set membership is checked in value/admission.rb, the second half of the same " \
|
|
126
|
-
"one construction door",
|
|
127
|
-
# S17, ADR 0026 — Member is a genuine entity, so this reads Member#pairs,
|
|
128
|
-
# not Member#shape. ValueObject#members is the same fact ValueObject#rows
|
|
129
|
-
# counts, seen from the other side.
|
|
130
|
-
"ValueObject#members" => "the members list IS what ValueObject#rows counts — same door, same guarantee",
|
|
131
|
-
"Member#pairs" => "one level into ValueObject#rows — same door"
|
|
132
|
-
}.freeze
|
|
133
|
-
|
|
134
38
|
# Runs the standard property battery over one replayed history — all but
|
|
135
39
|
# determinism, which replays twice itself and so is checked separately.
|
|
136
40
|
#
|
|
@@ -138,24 +42,7 @@ module Hecks
|
|
|
138
42
|
# @return [Hash{Symbol => true, String}] each property name mapped to `true`
|
|
139
43
|
# (passed) or a message string naming what broke
|
|
140
44
|
def check(history)
|
|
141
|
-
{
|
|
142
|
-
saga_advances_follow_declared_handlers: saga_advances_follow_declared_handlers(history),
|
|
143
|
-
query_answers_match_reference: query_answers_match_reference(history),
|
|
144
|
-
guard_refusals_are_declared: guard_refusals_are_declared(history),
|
|
145
|
-
sagas_rehydrate_cleanly: sagas_rehydrate_cleanly(history),
|
|
146
|
-
fanout_dispatches_once_per_matching_row: fanout_dispatches_once_per_matching_row(history),
|
|
147
|
-
aggregation_matches_recompute: aggregation_matches_recompute(history),
|
|
148
|
-
stored_records_satisfy_declared_invariants: stored_records_satisfy_declared_invariants(history),
|
|
149
|
-
group_by_matches_recompute: group_by_matches_recompute(history),
|
|
150
|
-
paging_offset_partitions_correctly: paging_offset_partitions_correctly(history),
|
|
151
|
-
lifecycle_guard_and_given_violations_are_refused: lifecycle_guard_and_given_violations_are_refused(history),
|
|
152
|
-
authorize_scopes_or_refuses: authorize_scopes_or_refuses(history),
|
|
153
|
-
commands_respect_tenant_scope: commands_respect_tenant_scope(history),
|
|
154
|
-
dispatch_binding_fidelity: dispatch_binding_fidelity(history),
|
|
155
|
-
mutations_match_recompute: mutations_match_recompute(history),
|
|
156
|
-
dry_runs_leave_no_trace: dry_runs_leave_no_trace(history),
|
|
157
|
-
corrections_reference_an_emitted_event: corrections_reference_an_emitted_event(history),
|
|
158
|
-
outbox_rows_match_reactions: outbox_rows_match_reactions(history) }
|
|
45
|
+
PROPERTY_NAMES.to_h { |name| [name, public_send(name, history)] }
|
|
159
46
|
end
|
|
160
47
|
end
|
|
161
48
|
end
|
|
@@ -55,25 +55,10 @@ module Hecks
|
|
|
55
55
|
# @raise [ArgumentError] if `raw` is missing a required key, declares an unknown
|
|
56
56
|
# key, or gives a value the wrong type for its dial
|
|
57
57
|
def initialize(raw, path)
|
|
58
|
-
|
|
59
|
-
raise ArgumentError, "#{path} is missing #{missing.sort.join(', ')}" if missing.any?
|
|
60
|
-
|
|
61
|
-
extra = raw.keys - EXPECTED_TYPES.keys
|
|
62
|
-
if extra.any?
|
|
63
|
-
raise ArgumentError,
|
|
64
|
-
"#{path} declares unknown key(s) #{extra.sort.join(', ')} — " \
|
|
65
|
-
"no QaDial row of the Vocabulary chapter declares them"
|
|
66
|
-
end
|
|
67
|
-
|
|
58
|
+
check_keys!(raw, path)
|
|
68
59
|
EXPECTED_TYPES.each do |key, expected|
|
|
69
60
|
value = raw.fetch(key)
|
|
70
|
-
|
|
71
|
-
unless expected_classes.any? { |klass| value.is_a?(klass) }
|
|
72
|
-
raise ArgumentError,
|
|
73
|
-
"#{path}: #{key} must be a #{expected_classes.map(&:name).join(' or ')}, " \
|
|
74
|
-
"got #{value.class} (#{value.inspect})"
|
|
75
|
-
end
|
|
76
|
-
|
|
61
|
+
check_type!(path, key, expected, value)
|
|
77
62
|
instance_variable_set(:"@#{key}", value)
|
|
78
63
|
end
|
|
79
64
|
|
|
@@ -83,6 +68,27 @@ module Hecks
|
|
|
83
68
|
|
|
84
69
|
private
|
|
85
70
|
|
|
71
|
+
def check_keys!(raw, path)
|
|
72
|
+
missing = EXPECTED_TYPES.keys - raw.keys
|
|
73
|
+
raise ArgumentError, "#{path} is missing #{missing.sort.join(", ")}" if missing.any?
|
|
74
|
+
|
|
75
|
+
extra = raw.keys - EXPECTED_TYPES.keys
|
|
76
|
+
return unless extra.any?
|
|
77
|
+
|
|
78
|
+
raise ArgumentError,
|
|
79
|
+
"#{path} declares unknown key(s) #{extra.sort.join(", ")} — " \
|
|
80
|
+
"no QaDial row of the Vocabulary chapter declares them"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def check_type!(path, key, expected, value)
|
|
84
|
+
expected_classes = Array(expected)
|
|
85
|
+
return if expected_classes.any? { |klass| value.is_a?(klass) }
|
|
86
|
+
|
|
87
|
+
raise ArgumentError,
|
|
88
|
+
"#{path}: #{key} must be a #{expected_classes.map(&:name).join(" or ")}, " \
|
|
89
|
+
"got #{value.class} (#{value.inspect})"
|
|
90
|
+
end
|
|
91
|
+
|
|
86
92
|
# YAML cannot spell a Symbol value, and IsolatedBoot case-matches adapters by symbol.
|
|
87
93
|
def symbolize_adapter_parity_pairs!(path)
|
|
88
94
|
@adapter_parity_pairs = @adapter_parity_pairs.to_h do |mode, pair|
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
module Hecks
|
|
2
|
+
module Fuzzing
|
|
3
|
+
module Replay
|
|
4
|
+
# Independent recomputation of what each `for_each` policy should have fanned out over.
|
|
5
|
+
module FanOut
|
|
6
|
+
# What one event's fan-out findings are computed against.
|
|
7
|
+
Context = Struct.new(:runtime, :snapshot, :reactions_since)
|
|
8
|
+
|
|
9
|
+
# One finding per (event, for_each policy) pair, independent of
|
|
10
|
+
# `PolicyInterpreter#deliver_for_each`, answered via `Ports::Query::InMemory`
|
|
11
|
+
# directly rather than `QueryInterpreter`, so this stays blind to nothing the
|
|
12
|
+
# fan-out feature adds. `expected_row_ids` is `nil` when `where` did not hold.
|
|
13
|
+
def fan_out_findings(runtime, snapshot, announced, reactions_since)
|
|
14
|
+
context = Context.new(runtime, snapshot, reactions_since)
|
|
15
|
+
announced.each_with_object([]) do |event, findings|
|
|
16
|
+
# `event.aggregate` is domain-qualified ("Banking::Account"); split the same
|
|
17
|
+
# two ways `PolicyInterpreter#policies_for` does.
|
|
18
|
+
domain = event.aggregate.to_s.split("::").first
|
|
19
|
+
bluebook = runtime.registry.bluebook(domain)
|
|
20
|
+
next unless bluebook
|
|
21
|
+
|
|
22
|
+
fanning_policies(bluebook, event).each do |policy|
|
|
23
|
+
findings << fan_out_finding(context, policy, event, domain)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# The bluebook's `for_each` policies that react to `event`.
|
|
29
|
+
def fanning_policies(bluebook, event)
|
|
30
|
+
emitting = Naming.demodulise(event.aggregate)
|
|
31
|
+
bluebook.policies.select do |policy|
|
|
32
|
+
policy.fans_out? && policy.event_name == event.name &&
|
|
33
|
+
(policy.event_qualifier.nil? || policy.event_qualifier == emitting)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Builds one fan-out finding, comparing one `for_each` policy's independently
|
|
38
|
+
# recomputed expected rows against what actually reacted for one event.
|
|
39
|
+
def fan_out_finding(context, policy, event, domain)
|
|
40
|
+
payload = event.payload.transform_keys(&:to_sym)
|
|
41
|
+
held = policy.where.to_s.empty? || Bluebook::Expression::Evaluator.call(policy.where, {}, payload)
|
|
42
|
+
expected = held ? expected_fan_out_rows(context.runtime, context.snapshot, policy, domain, payload) : nil
|
|
43
|
+
|
|
44
|
+
{ policy: policy.name, on: event.name, expected_row_ids: expected,
|
|
45
|
+
actual_row_ids: reacted_rows(context.reactions_since, policy, event) }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# The rows the reaction log shows `policy` dispatching to for `event`.
|
|
49
|
+
def reacted_rows(reactions_since, policy, event)
|
|
50
|
+
reactions_since.select { |r| r[:policy] == policy.name && r[:on] == event.name }
|
|
51
|
+
.filter_map { |r| r[:for_row] }
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# `policy.for_each`'s declared query, answered against the pre-dispatch snapshot
|
|
55
|
+
# (the real fan-out's query runs before its own dispatched commands can mutate
|
|
56
|
+
# anything it would match, so this must read the same "before" state). A `Symbol`
|
|
57
|
+
# where-value binds to the triggering event's own payload; a literal is as declared.
|
|
58
|
+
def expected_fan_out_rows(runtime, snapshot, policy, domain, payload)
|
|
59
|
+
query_domain, aggregate_name, query_name = policy.for_each_route(domain)
|
|
60
|
+
query = for_each_query(runtime, query_domain, aggregate_name, query_name)
|
|
61
|
+
return [] unless query
|
|
62
|
+
|
|
63
|
+
rows = snapshot[[query_domain, aggregate_name]] || {}
|
|
64
|
+
matched = rows.select do |_id, state|
|
|
65
|
+
query.wheres.all? { |clause| clause_holds?(clause, state, payload) }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
matched.keys.map(&:to_s).sort
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# The declared query a `for_each` policy names, or nil.
|
|
72
|
+
def for_each_query(runtime, query_domain, aggregate_name, query_name)
|
|
73
|
+
runtime.registry.bluebook(query_domain)&.aggregate(aggregate_name)&.query(query_name)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
require_relative "../../query_specification/common/comparators"
|
|
2
|
+
require_relative "../../query_specification/common/where_clause"
|
|
3
|
+
require_relative "../../query_specification/field_path"
|
|
4
|
+
require_relative "../../ports/query/in_memory"
|
|
5
|
+
|
|
6
|
+
module Hecks
|
|
7
|
+
module Fuzzing
|
|
8
|
+
module Replay
|
|
9
|
+
# Answers the ad hoc `{aggregate:, field:, op:, value:}` filter steps that bypass the
|
|
10
|
+
# declared query DSL.
|
|
11
|
+
module Filters
|
|
12
|
+
# Mirrors QuerySpecification::Common::COMPARATORS, not the Rust
|
|
13
|
+
# kernel's own comparator enum, which is missing `none_in_state` and has drifted.
|
|
14
|
+
FILTER_COMPARATORS = Hecks::QuerySpecification::Common::COMPARATORS.map(&:to_s).freeze
|
|
15
|
+
|
|
16
|
+
# Answers one ad hoc filter step, the mirror image of kernel/cli.rs's own
|
|
17
|
+
# `run_filter`, calling the same production `Ports::Query::InMemory` rather than
|
|
18
|
+
# re-deriving comparator behavior by hand. Sorted by id ascending regardless,
|
|
19
|
+
# since an ad hoc filter declares no order of its own.
|
|
20
|
+
#
|
|
21
|
+
# @raise [Bluebook::Expression::EvaluationError] if `op` or `"aggregate"` is unknown
|
|
22
|
+
def run_filter(runtime, filter)
|
|
23
|
+
check_comparator!(filter["op"].to_s)
|
|
24
|
+
|
|
25
|
+
domain_name, aggregate = filter_aggregate(runtime, filter["aggregate"].to_s)
|
|
26
|
+
clause = filter_clause(filter)
|
|
27
|
+
records = runtime.registry.repository(domain_name, aggregate).all
|
|
28
|
+
|
|
29
|
+
rows_by_id(records.select { |record| clause_holds?(clause, record, {}) })
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# A malformed ad-hoc ask is a fault (C8.3), not a bare RuntimeError.
|
|
33
|
+
def check_comparator!(comparator)
|
|
34
|
+
return if FILTER_COMPARATORS.include?(comparator)
|
|
35
|
+
|
|
36
|
+
raise Bluebook::Expression::EvaluationError, "unknown query comparator #{comparator.inspect}"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def filter_clause(filter)
|
|
40
|
+
QuerySpecification::Common::WhereClause.new(field: filter["field"].to_s, op: filter["op"].to_s, value: filter["value"])
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# The records as `{id:, **state}` rows, sorted by id ascending.
|
|
44
|
+
def rows_by_id(records)
|
|
45
|
+
records.sort_by { |record| record.id.to_s }.map { |record| { id: record.id }.merge(record.state) }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# The domain name and aggregate a filter's `"Domain::Aggregate"` reference names.
|
|
49
|
+
#
|
|
50
|
+
# @raise [Bluebook::Expression::EvaluationError] if no such aggregate is loaded
|
|
51
|
+
def filter_aggregate(runtime, aggregate_ref)
|
|
52
|
+
domain_name, aggregate_name = aggregate_ref.split("::", 2)
|
|
53
|
+
aggregate = runtime.registry.bluebook(domain_name)&.aggregate(aggregate_name)
|
|
54
|
+
raise Bluebook::Expression::EvaluationError, "unknown aggregate #{aggregate_ref.inspect}" unless aggregate
|
|
55
|
+
|
|
56
|
+
[domain_name, aggregate]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Whether `subject`'s value at the clause's field satisfies the clause, `args` binding
|
|
60
|
+
# any Symbol value.
|
|
61
|
+
def clause_holds?(clause, subject, args)
|
|
62
|
+
held = Ports::Query::InMemory.comparable(QuerySpecification::FieldPath.dig(subject, clause.field))
|
|
63
|
+
Ports::Query::InMemory.holds?(clause, held, args)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Builds the `refusals` entry's own "verb" column for a refused ad hoc filter,
|
|
67
|
+
# which carries no real verb to report.
|
|
68
|
+
def filter_label(filter) = "filter #{filter["aggregate"]}.#{filter["field"]} #{filter["op"]}"
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
module Hecks
|
|
2
|
+
module Fuzzing
|
|
3
|
+
module Replay
|
|
4
|
+
# Replays a step's guard read-only, before the real dispatch can mutate anything, so the
|
|
5
|
+
# outcome can be compared with what the dispatch actually did.
|
|
6
|
+
module GuardCheck
|
|
7
|
+
# The command a guard check is about, and where it lives.
|
|
8
|
+
Target = Struct.new(:domain, :aggregate_name, :command_name, :aggregate, :command)
|
|
9
|
+
|
|
10
|
+
module_function
|
|
11
|
+
|
|
12
|
+
# Resolves the record (if any) this step's guard should be checked against, and
|
|
13
|
+
# replays enforce_givens then admissible_transition, in that order, to mirror
|
|
14
|
+
# the real DISPATCH_ORDER. `nil` for anything out of scope.
|
|
15
|
+
def build(runtime, verb, args)
|
|
16
|
+
target = target_for(runtime, verb)
|
|
17
|
+
return nil unless target
|
|
18
|
+
|
|
19
|
+
id = Replay.identity_for(target.aggregate, target.command, args)
|
|
20
|
+
record = id && runtime.registry.repository(target.domain, target.aggregate).find(id)
|
|
21
|
+
return nil unless record
|
|
22
|
+
|
|
23
|
+
{ verb: verb, domain: target.domain, aggregate: target.aggregate_name, command: target.command_name,
|
|
24
|
+
id: id, **recomputation(runtime, target, record, args) }
|
|
25
|
+
rescue StandardError
|
|
26
|
+
nil
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# The aggregate-level command `verb` names, when it has a guard worth checking.
|
|
30
|
+
def target_for(runtime, verb)
|
|
31
|
+
domain_name, aggregate_name, command_name = Naming.split_verb(verb)
|
|
32
|
+
return nil unless command_name && !command_name.include?(".")
|
|
33
|
+
|
|
34
|
+
aggregate = runtime.registry.bluebook(domain_name)&.aggregate(aggregate_name)
|
|
35
|
+
command = aggregate&.command(command_name)
|
|
36
|
+
return nil unless checkable?(aggregate, command)
|
|
37
|
+
|
|
38
|
+
Target.new(domain_name, aggregate_name, command_name, aggregate, command)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def checkable?(aggregate, command)
|
|
42
|
+
aggregate && command && !command.creates? && guarded?(aggregate, command)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# A transition-only guard (no per-command `from:`/`given`, only an aggregate
|
|
46
|
+
# `lifecycle` block naming this command) still counts as something to check,
|
|
47
|
+
# now that `admissible_transition` is reproduced.
|
|
48
|
+
def guarded?(aggregate, command)
|
|
49
|
+
has_transition = aggregate.lifecycle&.transitions_for(command.hecks_name)&.any?
|
|
50
|
+
!(command.givens.empty? && !command.from && !has_transition)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# What an independent run of the guard says about the step.
|
|
54
|
+
#
|
|
55
|
+
# Real dispatch normalizes args (step_normalize_args) before it ever reaches
|
|
56
|
+
# enforce_givens, coercing a bare scalar like "white" into its command's declared
|
|
57
|
+
# value-object shape. Skipping that here would hand enforce_givens the raw fuzzed
|
|
58
|
+
# shape instead, and a `given` comparing a normalized field against it would walk a
|
|
59
|
+
# path a String happens to answer (a substring lookup) rather than the refusal real
|
|
60
|
+
# dispatch raises. `send` reaches the interpreter's own private coercion (the same
|
|
61
|
+
# idiom SelfConsistency#last_advancing_event uses for `saga_correlation`) rather than
|
|
62
|
+
# reimplementing it here.
|
|
63
|
+
def recomputation(runtime, target, record, args)
|
|
64
|
+
rules = Runtime::CommandRules.new(runtime.registry)
|
|
65
|
+
interpreter = Runtime::CommandInterpreter.new(runtime.registry, rules: rules)
|
|
66
|
+
normalized_args = interpreter.send(:normalize_args, target.aggregate, target.command, args)
|
|
67
|
+
kind = refusal_class_name(rules, target, record, normalized_args)
|
|
68
|
+
{ recomputed_refused: !kind.nil?, recomputed_kind: kind }
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# The class name of the guard refusal the independent run raises, or nil when it admits.
|
|
72
|
+
def refusal_class_name(rules, target, record, normalized_args)
|
|
73
|
+
rules.enforce_givens(record.dup, target.command, normalized_args, domain: target.domain, declaring: target.aggregate)
|
|
74
|
+
|
|
75
|
+
# A second, separate DISPATCH_ORDER step: the aggregate's own `lifecycle`
|
|
76
|
+
# transition guard is a wholly different method from enforce_givens' own
|
|
77
|
+
# per-command `from:` check, called only when enforce_givens didn't already refuse.
|
|
78
|
+
# It reads only the record's own lifecycle field and the command's declared
|
|
79
|
+
# transitions, never `args`, so it needs no normalized input of its own.
|
|
80
|
+
rules.admissible_transition(target.aggregate, target.command, record.dup)
|
|
81
|
+
nil
|
|
82
|
+
rescue *GUARD_REFUSAL_CLASSES => e
|
|
83
|
+
e.class.name
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
module Hecks
|
|
2
|
+
module Fuzzing
|
|
3
|
+
module Replay
|
|
4
|
+
# Snapshots the entity element a mutation step addresses before dispatch, and re-reads it
|
|
5
|
+
# after, so the mutation can be diffed against an independent recomputation.
|
|
6
|
+
module MutationTrace
|
|
7
|
+
# The entity command a trace is about, and where it lives.
|
|
8
|
+
Target = Struct.new(:domain, :aggregate_name, :command_name, :aggregate, :entity, :command)
|
|
9
|
+
|
|
10
|
+
# The element a mutation step addresses, found in its parent's `list_of` attribute.
|
|
11
|
+
Located = Struct.new(:parent_id, :list_attr, :wants, :element)
|
|
12
|
+
|
|
13
|
+
module_function
|
|
14
|
+
|
|
15
|
+
# Scoped to entity-dispatched commands only, the one place `append`/`remove`/
|
|
16
|
+
# `multiply`/`clamp` act on an entity's own attributes. `nil` for anything out of
|
|
17
|
+
# scope: an aggregate-level command, no mutations, or unresolvable identity args.
|
|
18
|
+
def build(runtime, verb, args)
|
|
19
|
+
target = target_for(runtime, verb)
|
|
20
|
+
return nil unless target
|
|
21
|
+
|
|
22
|
+
args = normalized_args(runtime, target, args)
|
|
23
|
+
located = locate_element(runtime, target, args)
|
|
24
|
+
return nil unless located
|
|
25
|
+
|
|
26
|
+
{ verb: verb, domain: target.domain, aggregate: target.aggregate_name, command: target.command_name,
|
|
27
|
+
parent_id: located.parent_id, list_attr: located.list_attr.name, element_wants: located.wants,
|
|
28
|
+
before: Runtime::Value.materialize(located.element), args: args }
|
|
29
|
+
rescue StandardError
|
|
30
|
+
nil
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# The entity command `verb` names, when it declares mutations.
|
|
34
|
+
def target_for(runtime, verb)
|
|
35
|
+
domain_name, aggregate_name, command_name = Naming.split_verb(verb)
|
|
36
|
+
return nil unless command_name&.include?(".")
|
|
37
|
+
|
|
38
|
+
aggregate = runtime.registry.bluebook(domain_name)&.aggregate(aggregate_name)
|
|
39
|
+
return nil unless aggregate
|
|
40
|
+
|
|
41
|
+
entity, command = entity_command(aggregate, command_name)
|
|
42
|
+
return nil unless mutates?(command)
|
|
43
|
+
|
|
44
|
+
Target.new(domain_name, aggregate_name, command_name, aggregate, entity, command)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def mutates?(command) = command&.mutations&.any?
|
|
48
|
+
|
|
49
|
+
# The entity and command a dotted `Entity.Command` path names under `aggregate`.
|
|
50
|
+
def entity_command(aggregate, command_name)
|
|
51
|
+
entity_name, entity_command_name = command_name.split(".", 2)
|
|
52
|
+
entity = aggregate.entities.find { |candidate| candidate.hecks_name == entity_name }
|
|
53
|
+
[entity, entity&.command(entity_command_name)]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Same idiom as GuardCheck: real dispatch normalizes args
|
|
57
|
+
# (step_normalize_args) before apply_mutations ever runs, coercing a declared
|
|
58
|
+
# payload attribute into its command's shape — a composite argument's own
|
|
59
|
+
# `Value.build` fills that shape's declared defaults along the way. Recomputing
|
|
60
|
+
# a mutation against the raw fuzzed args instead would disagree with real
|
|
61
|
+
# dispatch whenever a caller omitted a defaulted field, the same false-divergence
|
|
62
|
+
# shape GuardCheck guards against for the guard check.
|
|
63
|
+
def normalized_args(runtime, target, args)
|
|
64
|
+
interpreter = Runtime::CommandInterpreter.new(runtime.registry, rules: Runtime::CommandRules.new(runtime.registry))
|
|
65
|
+
interpreter.send(:normalize_args, target.aggregate, target.command, args)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Finds the stored element the step's identity args address, or nil.
|
|
69
|
+
def locate_element(runtime, target, args)
|
|
70
|
+
parent_id = Replay.identity_for(target.aggregate, target.command, args)
|
|
71
|
+
record = parent_id && runtime.registry.repository(target.domain, target.aggregate).find(parent_id)
|
|
72
|
+
list_attr = record && list_attribute(target)
|
|
73
|
+
wants = list_attr && element_wants(target, args)
|
|
74
|
+
element = wants && find_element(record.state[list_attr.name], wants)
|
|
75
|
+
element && Located.new(parent_id, list_attr, wants, element)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def list_attribute(target)
|
|
79
|
+
target.aggregate.attributes.find { |a| a.list? && a.type.to_s == target.entity.hecks_name }
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# The `[head, value]` identity pairs the args give for the entity, or nil when an
|
|
83
|
+
# identity argument is missing.
|
|
84
|
+
def element_wants(target, args)
|
|
85
|
+
target.entity.identity_paths.map do |path|
|
|
86
|
+
head = path.to_s.split(".").first.to_sym
|
|
87
|
+
raw = args[head]
|
|
88
|
+
return nil if raw.nil?
|
|
89
|
+
|
|
90
|
+
[head, Runtime::Value.for_attribute(target.aggregate, target.entity.attribute(head), raw)]
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def find_element(items, wants)
|
|
95
|
+
Array(items).find { |element| wants.all? { |head, want| element[head] == want } }
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Re-locates the same element by identity, not position, since a mutation could
|
|
99
|
+
# have changed the array's own length or order. `nil` if it vanished.
|
|
100
|
+
def read_after(runtime, trace)
|
|
101
|
+
record = parent_record(runtime, trace)
|
|
102
|
+
return nil unless record
|
|
103
|
+
|
|
104
|
+
element = find_element(record.state[trace[:list_attr]], trace[:element_wants])
|
|
105
|
+
element && Runtime::Value.materialize(element)
|
|
106
|
+
rescue StandardError
|
|
107
|
+
nil
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def parent_record(runtime, trace)
|
|
111
|
+
aggregate = runtime.registry.bluebook(trace[:domain])&.aggregate(trace[:aggregate])
|
|
112
|
+
aggregate && runtime.registry.repository(trace[:domain], aggregate).find(trace[:parent_id])
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|