hecks 1.2.0 → 1.4.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/lib/hecks/adapters/driven/claude_code.rb +7 -7
- data/lib/hecks/adapters/driven/d1.rb +187 -23
- data/lib/hecks/adapters/driven/folder.rb +10 -10
- data/lib/hecks/adapters/driven/google_authentication.rb +8 -8
- data/lib/hecks/adapters/driven/governance_authorization.rb +31 -13
- data/lib/hecks/adapters/driven/heki/journal.rb +60 -2
- data/lib/hecks/adapters/driven/heki/saga_store.rb +5 -5
- data/lib/hecks/adapters/driven/heki.rb +13 -7
- data/lib/hecks/adapters/driven/identity_registry.rb +2 -2
- data/lib/hecks/adapters/driven/in_memory_ordering.rb +3 -3
- data/lib/hecks/adapters/driven/lambda/client.rb +34 -9
- data/lib/hecks/adapters/driven/lambda.rb +39 -33
- data/lib/hecks/adapters/driven/local_storage.rb +17 -10
- data/lib/hecks/adapters/driven/memory.rb +205 -9
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +1 -1
- data/lib/hecks/adapters/driven/postgres/codec.rb +27 -11
- data/lib/hecks/adapters/driven/postgres/outbox.rb +40 -2
- data/lib/hecks/adapters/driven/postgres/reconnect.rb +23 -7
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +14 -14
- data/lib/hecks/adapters/driven/postgres.rb +175 -28
- data/lib/hecks/adapters/driven/postgres_era.adapter +5 -0
- data/lib/hecks/adapters/driven/prism.rb +4 -4
- data/lib/hecks/adapters/driven/sql_query_builder.rb +34 -22
- data/lib/hecks/adapters/driven/sqlite/codec.rb +38 -10
- data/lib/hecks/adapters/driven/sqlite/projection.rb +60 -32
- data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +12 -12
- data/lib/hecks/adapters/driven/sqlite.rb +181 -21
- data/lib/hecks/adapters/driven.rb +4 -4
- data/lib/hecks/adapters/driving/github_webhook.rb +145 -0
- data/lib/hecks/behaviors/dsl.rb +2 -2
- data/lib/hecks/behaviors/expectations.rb +51 -23
- data/lib/hecks/behaviors/ir.rb +1 -1
- data/lib/hecks/behaviors/rspec.rb +1 -1
- data/lib/hecks/behaviors/runner.rb +2 -2
- data/lib/hecks/behaviors.rb +1 -1
- data/lib/hecks/bluebook/aggregate.rb +13 -13
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +10 -10
- data/lib/hecks/bluebook/assembly/build.rb +1 -1
- data/lib/hecks/bluebook/assembly/contract.rb +39 -16
- data/lib/hecks/bluebook/assembly/contracts.rb +40 -38
- data/lib/hecks/bluebook/assembly/marks.rb +18 -18
- data/lib/hecks/bluebook/assembly/specializer.rb +19 -21
- data/lib/hecks/bluebook/assembly.rb +9 -9
- data/lib/hecks/bluebook/attribute.rb +9 -9
- data/lib/hecks/bluebook/behaviour/aggregate.rb +11 -11
- data/lib/hecks/bluebook/behaviour/attribute.rb +5 -5
- data/lib/hecks/bluebook/behaviour/chapter.rb +23 -5
- data/lib/hecks/bluebook/behaviour/command.rb +23 -23
- data/lib/hecks/bluebook/behaviour/domain_port.rb +27 -3
- data/lib/hecks/bluebook/behaviour/entity.rb +8 -8
- data/lib/hecks/bluebook/behaviour/hexagon.rb +4 -4
- data/lib/hecks/bluebook/behaviour/lifecycle.rb +5 -5
- data/lib/hecks/bluebook/behaviour/policy.rb +12 -12
- data/lib/hecks/bluebook/behaviour/process_manager.rb +7 -7
- data/lib/hecks/bluebook/behaviour/query.rb +1 -1
- data/lib/hecks/bluebook/behaviour/read_model.rb +8 -8
- data/lib/hecks/bluebook/behaviour/traits.rb +12 -12
- data/lib/hecks/bluebook/behaviour/value_object.rb +6 -6
- data/lib/hecks/bluebook/capabilities.rb +27 -0
- data/lib/hecks/bluebook/chapter.rb +28 -9
- data/lib/hecks/bluebook/command.rb +12 -12
- data/lib/hecks/bluebook/domain_port.rb +9 -9
- data/lib/hecks/bluebook/dsl/adapter_builder.rb +24 -0
- data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +49 -49
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +96 -96
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +41 -41
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +22 -2
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +111 -74
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +48 -30
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +116 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +103 -103
- data/lib/hecks/bluebook/dsl/const_shim.rb +46 -15
- data/lib/hecks/bluebook/dsl/domain_port_builder.rb +90 -25
- data/lib/hecks/bluebook/dsl/entity_builder.rb +56 -56
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +148 -132
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +89 -30
- data/lib/hecks/bluebook/dsl/identity_declaration.rb +17 -17
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +27 -4
- data/lib/hecks/bluebook/dsl/policy_builder.rb +30 -21
- data/lib/hecks/bluebook/dsl/port_builder.rb +38 -7
- data/lib/hecks/bluebook/dsl/port_operation_builder.rb +56 -22
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +35 -35
- data/lib/hecks/bluebook/dsl/query_builder.rb +5 -5
- data/lib/hecks/bluebook/dsl/read_model_builder.rb +34 -34
- data/lib/hecks/bluebook/dsl/rule_reference.rb +41 -39
- data/lib/hecks/bluebook/dsl/translation_builder.rb +9 -9
- data/lib/hecks/bluebook/dsl/value_object_builder.rb +16 -16
- data/lib/hecks/bluebook/dsl/word_gate.rb +59 -53
- data/lib/hecks/bluebook/dsl/world_builder.rb +51 -8
- data/lib/hecks/bluebook/entity.rb +11 -11
- data/lib/hecks/bluebook/expression/ast_json.rb +20 -20
- data/lib/hecks/bluebook/expression/ast_reader.rb +3 -3
- data/lib/hecks/bluebook/expression/canonical_form.rb +9 -9
- data/lib/hecks/bluebook/expression/evaluator.rb +18 -18
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +18 -18
- data/lib/hecks/bluebook/expression/resolver.rb +60 -62
- data/lib/hecks/bluebook/hexagon.rb +1 -1
- data/lib/hecks/bluebook/lifecycle.rb +1 -1
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -1
- data/lib/hecks/bluebook/meta_validator/judge.rb +122 -86
- data/lib/hecks/bluebook/meta_validator/plan.rb +39 -39
- data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -2
- data/lib/hecks/bluebook/meta_validator/readings.rb +43 -43
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +44 -37
- data/lib/hecks/bluebook/meta_validator/shapes.rb +25 -21
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +145 -31
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +6 -6
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +5 -5
- data/lib/hecks/bluebook/meta_validator.rb +70 -70
- data/lib/hecks/bluebook/model_check.rb +301 -84
- data/lib/hecks/bluebook/pattern_subset.rb +9 -9
- data/lib/hecks/bluebook/policy.rb +15 -13
- data/lib/hecks/bluebook/process_manager.rb +14 -14
- data/lib/hecks/bluebook/project_register.rb +6 -6
- data/lib/hecks/bluebook/query.rb +4 -4
- data/lib/hecks/bluebook/read_model.rb +14 -14
- data/lib/hecks/bluebook/reference.rb +8 -8
- data/lib/hecks/bluebook/smoke_test.rb +19 -19
- data/lib/hecks/bluebook/synthesizer.rb +12 -12
- data/lib/hecks/bluebook/translation.rb +4 -4
- data/lib/hecks/bluebook/value_object.rb +6 -6
- data/lib/hecks/bluebook.rb +2 -2
- data/lib/hecks/codemod/legacy_dispatch_args.rb +299 -0
- data/lib/hecks/codemod/legacy_dispatch_recorder.rb +186 -0
- data/lib/hecks/codemod.rb +36 -35
- data/lib/hecks/construct.rb +6 -6
- data/lib/hecks/corpus.rb +317 -0
- data/lib/hecks/deprecation.rb +95 -0
- data/lib/hecks/doc/reference.rb +19 -19
- data/lib/hecks/embryonaut_bluebook.rb +11 -11
- data/lib/hecks/facade/cli_door.rb +69 -10
- data/lib/hecks/facade/cli_runner.rb +105 -24
- data/lib/hecks/facade/command_request.rb +23 -0
- data/lib/hecks/facade/handle.rb +79 -32
- data/lib/hecks/facade/json_door.rb +106 -25
- data/lib/hecks/facade/surface/aggregate_door.rb +42 -27
- data/lib/hecks/facade/surface/chapter.rb +26 -17
- data/lib/hecks/facade/surface.rb +16 -3
- data/lib/hecks/facade.rb +15 -4
- data/lib/hecks/forms/app.rb +46 -30
- data/lib/hecks/forms/command_form_renderer.rb +70 -9
- data/lib/hecks/forms/field_renderer.rb +142 -6
- data/lib/hecks/forms/field_shape.rb +183 -20
- data/lib/hecks/forms/html.rb +51 -7
- data/lib/hecks/forms/index_renderer.rb +14 -2
- data/lib/hecks/forms/params.rb +120 -23
- data/lib/hecks/forms/port_argument.rb +2 -2
- data/lib/hecks/forms/query_form_renderer.rb +2 -2
- data/lib/hecks/forms/record_renderer.rb +2 -2
- data/lib/hecks/forms/record_table.rb +1 -1
- data/lib/hecks/forms/value_object_shape.rb +3 -3
- data/lib/hecks/forms.rb +24 -4
- data/lib/hecks/fqn.rb +1 -1
- data/lib/hecks/framework/bluebook/governance.bluebook +9 -0
- data/lib/hecks/framework.rb +48 -17
- data/lib/hecks/freezer.rb +11 -11
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +90 -90
- data/lib/hecks/fuzzing/combination_miner.rb +119 -0
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +361 -0
- data/lib/hecks/fuzzing/coverage_campaign.rb +118 -0
- data/lib/hecks/fuzzing/differential.rb +158 -0
- data/lib/hecks/fuzzing/domain_generator.rb +694 -0
- data/lib/hecks/fuzzing/era_boundary.rb +124 -0
- data/lib/hecks/fuzzing/form_census.rb +199 -0
- data/lib/hecks/fuzzing/generated_domain_check.rb +95 -0
- data/lib/hecks/fuzzing/invalid_value_generator.rb +6 -6
- data/lib/hecks/fuzzing/isolated_boot.rb +226 -38
- data/lib/hecks/fuzzing/nondeterministic.rb +67 -0
- data/lib/hecks/fuzzing/persistence_parity.rb +161 -0
- data/lib/hecks/fuzzing/properties/corrections.rb +100 -0
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +321 -41
- data/lib/hecks/fuzzing/properties/guards.rb +129 -26
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +32 -32
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +31 -11
- data/lib/hecks/fuzzing/properties/outbox.rb +142 -0
- data/lib/hecks/fuzzing/properties/querying.rb +17 -17
- data/lib/hecks/fuzzing/properties.rb +84 -39
- data/lib/hecks/fuzzing/qa_settings.rb +152 -0
- data/lib/hecks/fuzzing/replay.rb +224 -114
- data/lib/hecks/fuzzing/rotation_priority.rb +94 -0
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +113 -0
- data/lib/hecks/fuzzing/self_consistency.rb +676 -0
- data/lib/hecks/fuzzing/sequence_generator/adversary.rb +526 -0
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +101 -30
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +55 -8
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +31 -11
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +123 -32
- data/lib/hecks/fuzzing/sequence_generator.rb +152 -31
- data/lib/hecks/fuzzing/shrinker.rb +197 -0
- data/lib/hecks/fuzzing/structural_skips.rb +39 -0
- data/lib/hecks/fuzzing/sweep_depth.rb +53 -0
- data/lib/hecks/fuzzing/target_capabilities.rb +180 -0
- data/lib/hecks/fuzzing/value_generator.rb +66 -14
- data/lib/hecks/fuzzing.rb +11 -0
- data/lib/hecks/grammar/evolve.rb +10 -10
- data/lib/hecks/grammar.rb +7 -7
- data/lib/hecks/ir.rb +13 -13
- data/lib/hecks/language/bluebook/bluebook.bluebook +41 -0
- data/lib/hecks/language/bluebook/policy.bluebook +11 -1
- data/lib/hecks/language/bluebook/vocabulary.bluebook +365 -15
- data/lib/hecks/language/oidc.json +5 -0
- data/lib/hecks/literal.rb +9 -9
- data/lib/hecks/naming.rb +89 -21
- data/lib/hecks/ports/access_control.rb +58 -2
- data/lib/hecks/ports/agent/answers.rb +83 -6
- data/lib/hecks/ports/agent.rb +119 -35
- data/lib/hecks/ports/authentication.rb +44 -4
- data/lib/hecks/ports/authorization.rb +53 -11
- data/lib/hecks/ports/clock.rb +42 -23
- data/lib/hecks/ports/extraction.rb +16 -0
- data/lib/hecks/ports/identity_assignment.rb +24 -2
- data/lib/hecks/ports/identity_generation.rb +17 -3
- data/lib/hecks/ports/identity_resolution.rb +18 -1
- data/lib/hecks/ports/loading.rb +4 -0
- data/lib/hecks/ports/persistence/append_only.rb +172 -8
- data/lib/hecks/ports/persistence/binding_policy.rb +34 -0
- data/lib/hecks/ports/persistence/codec_boundary.rb +178 -0
- data/lib/hecks/ports/persistence/execution.rb +4 -0
- data/lib/hecks/ports/persistence/null_saga_store.rb +12 -1
- data/lib/hecks/ports/persistence/plugin.rb +42 -4
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +218 -25
- data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +77 -9
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +81 -24
- data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +29 -18
- data/lib/hecks/ports/persistence/plugins/era/lineage.rb +144 -60
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +103 -8
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +98 -23
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +282 -109
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +63 -25
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +160 -58
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +51 -28
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +28 -5
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +25 -12
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +129 -34
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +51 -6
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +44 -6
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +16 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +57 -4
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +25 -2
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +338 -83
- data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +68 -10
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +9 -3
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +9 -2
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +42 -8
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +16 -1
- data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +36 -5
- data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +23 -3
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +18 -19
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +5 -5
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -2
- data/lib/hecks/ports/persistence/plugins/era.rb +12 -2
- data/lib/hecks/ports/persistence/remote_runtime.rb +9 -2
- data/lib/hecks/ports/persistence/repository_factory.rb +29 -6
- data/lib/hecks/ports/persistence/state_codec.rb +319 -0
- data/lib/hecks/ports/persistence.rb +36 -1
- data/lib/hecks/ports/projection.rb +61 -7
- data/lib/hecks/ports/query/in_memory.rb +3 -3
- data/lib/hecks/ports/query/ordering.rb +6 -6
- data/lib/hecks/ports/query.rb +35 -0
- data/lib/hecks/projections/bootstrap_table.rb +112 -0
- data/lib/hecks/projections/diagrams.rb +75 -75
- data/lib/hecks/projections/glossary/html.rb +250 -0
- data/lib/hecks/projections/glossary/markdown.rb +105 -0
- data/lib/hecks/projections/glossary/mermaid.rb +110 -0
- data/lib/hecks/projections/glossary/page.css +271 -0
- data/lib/hecks/projections/glossary/page.js +72 -0
- data/lib/hecks/projections/glossary/sections.rb +17 -0
- data/lib/hecks/projections/glossary/sentences.rb +205 -0
- data/lib/hecks/projections/glossary.rb +214 -286
- data/lib/hecks/projections/ir.rb +1 -1
- data/lib/hecks/projections/model/deviations.rb +18 -17
- data/lib/hecks/projections/model.rb +25 -21
- data/lib/hecks/projections/oidc.rb +7 -7
- data/lib/hecks/projections/parser_table.rb +5 -5
- data/lib/hecks/projections/reference.rb +3 -3
- data/lib/hecks/projections/rust_vocabulary.rb +443 -0
- data/lib/hecks/projections/shape.rb +2 -2
- data/lib/hecks/projections/statements.rb +11 -11
- data/lib/hecks/projections/vocabulary.rb +9 -9
- data/lib/hecks/projections.rb +5 -3
- data/lib/hecks/projector/cli_projector.rb +29 -29
- data/lib/hecks/projector/docs_projector.rb +13 -13
- data/lib/hecks/projector/exporter.rb +42 -21
- data/lib/hecks/projector/ir_projector.rb +1 -1
- data/lib/hecks/projector/narrate_projector.rb +15 -22
- data/lib/hecks/projector/target.rb +13 -13
- data/lib/hecks/projector.rb +15 -15
- data/lib/hecks/query_ir.rb +47 -47
- data/lib/hecks/query_specification/common/comparators.rb +19 -3
- data/lib/hecks/query_specification/common/comparison.rb +132 -24
- data/lib/hecks/query_specification/common/dsl.rb +65 -9
- data/lib/hecks/query_specification/common/null_policy.rb +57 -13
- data/lib/hecks/query_specification/common/null_semantics.rb +4 -0
- data/lib/hecks/query_specification/common/options.rb +25 -0
- data/lib/hecks/query_specification/field_path.rb +69 -15
- data/lib/hecks/query_specification/hop_path.rb +57 -20
- data/lib/hecks/query_specification/read_model/specification.rb +4 -0
- data/lib/hecks/rendering.rb +3 -3
- data/lib/hecks/router/namespace_installer.rb +3 -3
- data/lib/hecks/router.rb +1 -1
- data/lib/hecks/runtime/aggregate_lock.rb +11 -11
- data/lib/hecks/runtime/boot_gates.rb +3 -3
- data/lib/hecks/runtime/caller.rb +8 -8
- data/lib/hecks/runtime/capability_graph.rb +2 -2
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +22 -25
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +64 -67
- data/lib/hecks/runtime/command_interpreter.rb +159 -102
- data/lib/hecks/runtime/command_rules/admissibility.rb +69 -69
- data/lib/hecks/runtime/command_rules/arithmetic.rb +137 -91
- data/lib/hecks/runtime/command_rules/authorization.rb +38 -17
- data/lib/hecks/runtime/command_rules/emission.rb +18 -1
- data/lib/hecks/runtime/command_rules/references.rb +94 -19
- data/lib/hecks/runtime/command_rules.rb +3 -0
- data/lib/hecks/runtime/dependency_planning.rb +11 -11
- data/lib/hecks/runtime/dispatcher.rb +283 -90
- data/lib/hecks/runtime/entity_element.rb +282 -46
- data/lib/hecks/runtime/entity_interpreter.rb +160 -69
- data/lib/hecks/runtime/errors.rb +19 -19
- data/lib/hecks/runtime/event.rb +6 -6
- data/lib/hecks/runtime/identity.rb +22 -22
- data/lib/hecks/runtime/instance.rb +39 -14
- data/lib/hecks/runtime/interpreting.rb +12 -12
- data/lib/hecks/runtime/invocation.rb +276 -0
- data/lib/hecks/runtime/loader.rb +14 -14
- data/lib/hecks/runtime/outbox.rb +23 -23
- data/lib/hecks/runtime/policy_interpreter.rb +54 -54
- data/lib/hecks/runtime/port_operation_interpreter.rb +22 -19
- data/lib/hecks/runtime/query_interpreter.rb +111 -56
- data/lib/hecks/runtime/reaction_invocation.rb +76 -9
- data/lib/hecks/runtime/read_model_interpreter.rb +40 -40
- data/lib/hecks/runtime/rebuild_sweep.rb +4 -4
- data/lib/hecks/runtime/reference_hop.rb +6 -6
- data/lib/hecks/runtime/refusal_wording.rb +92 -112
- data/lib/hecks/runtime/registry/saga_persistence.rb +21 -21
- data/lib/hecks/runtime/registry/verification.rb +36 -26
- data/lib/hecks/runtime/registry.rb +56 -27
- data/lib/hecks/runtime/remote_dispatcher.rb +38 -23
- data/lib/hecks/runtime/routing.rb +10 -88
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +17 -17
- data/lib/hecks/runtime/saga_interpreter.rb +93 -56
- data/lib/hecks/runtime/saga_pending_dispatch.rb +12 -12
- data/lib/hecks/runtime/tenant_check.rb +9 -9
- data/lib/hecks/runtime/tenant_scope.rb +5 -5
- data/lib/hecks/runtime/value/admission.rb +75 -30
- data/lib/hecks/runtime/value/coercion.rb +379 -226
- data/lib/hecks/runtime/value/entity_list_coercion.rb +248 -0
- data/lib/hecks/runtime/value.rb +28 -23
- data/lib/hecks/runtime.rb +7 -7
- data/lib/hecks/storehouse.rb +64 -64
- data/lib/hecks/version.rb +3 -3
- data/lib/hecks/vocabulary.rb +207 -5
- data/lib/hecks.rb +13 -11
- data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +11 -11
- data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +14 -12
- data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +11 -11
- metadata +43 -2
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
module Hecks
|
|
2
|
+
module Fuzzing
|
|
3
|
+
# The weighted half of `QualityControl::Target.Rotation`
|
|
4
|
+
# (qa/bluebook/quality_control.bluebook) — see that query's own
|
|
5
|
+
# comment for why the ledger itself still only offers
|
|
6
|
+
# least-recently-swept order: `order_by` sorts by exactly one stored
|
|
7
|
+
# field, and a target's actual rotation priority wants two blended
|
|
8
|
+
# together (time since last swept, and recent yield), which nothing
|
|
9
|
+
# in the query sublanguage can express. `Rotation` stays the raw
|
|
10
|
+
# view; this module is where the blend actually happens, against the
|
|
11
|
+
# rows that query already returns.
|
|
12
|
+
#
|
|
13
|
+
# **Pure, deliberately**. Every method here is a function of its own
|
|
14
|
+
# arguments only — no clock read, no query dispatched, nothing
|
|
15
|
+
# random — so this is unit-testable with plain hashes and no ledger
|
|
16
|
+
# boot at all, and reruns identically given the same rotation, the
|
|
17
|
+
# same `now` and the same dials. `now` arrives as an argument for
|
|
18
|
+
# the exact reason `Target.Claim`'s own comment already gives: a
|
|
19
|
+
# pure function cannot ask the time, so whoever calls this supplies
|
|
20
|
+
# it, exactly as it supplies an id.
|
|
21
|
+
#
|
|
22
|
+
# Where this actually matters, and where it does not — checked
|
|
23
|
+
# against `bin/qa_sweep`'s own code, not assumed. `bin/qa_sweep
|
|
24
|
+
# --all` sweeps every currently-waiting target in one pass,
|
|
25
|
+
# regardless of order (`run_all_mode`'s own `waiting.map { spawn_
|
|
26
|
+
# sweep_child }` — every element the query returned, never
|
|
27
|
+
# `.first`), so nothing about this module's own ordering changes
|
|
28
|
+
# what `--all` does; it already sweeps everything the ledger has to
|
|
29
|
+
# offer. What it changes is `bin/qa_sweep` invoked with no target
|
|
30
|
+
# argument, which today picks exactly one target via `Target.
|
|
31
|
+
# Rotation.first` — wiring `.pick` in there instead is this module's
|
|
32
|
+
# one real caller, and (per the same investigation) its only one:
|
|
33
|
+
# there is no separate scheduling or concurrency-limit mechanism
|
|
34
|
+
# elsewhere in this repository for it to feed instead.
|
|
35
|
+
module RotationPriority
|
|
36
|
+
module_function
|
|
37
|
+
|
|
38
|
+
# The next stored `Target.yield_score` — decay what survives from
|
|
39
|
+
# before, then add whatever this just-concluded period actually
|
|
40
|
+
# found. Integer division, like every other count in this ledger
|
|
41
|
+
# (`Sweep.CheckCount`, `Bug.BugOrder`): a yield score is a
|
|
42
|
+
# priority signal, not a precise statistic, and a fractional score
|
|
43
|
+
# would need a value object this ledger does not have.
|
|
44
|
+
#
|
|
45
|
+
# `decay_percent` defaults to the dial, not a literal, so a caller
|
|
46
|
+
# that does not care still gets the practice's own current answer
|
|
47
|
+
# to "how much of this is 'recent'" rather than a second, silently
|
|
48
|
+
# drifting copy of the same number.
|
|
49
|
+
def next_yield_score(old_score:, surprises_this_period:,
|
|
50
|
+
decay_percent: QualityControlDials::YIELD_DECAY_PERCENT)
|
|
51
|
+
raise ArgumentError, "old_score must not be negative" if old_score.negative?
|
|
52
|
+
raise ArgumentError, "surprises_this_period must not be negative" if surprises_this_period.negative?
|
|
53
|
+
|
|
54
|
+
((old_score * decay_percent) / 100) + surprises_this_period
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# The pick itself. `rows` is whatever `Target.Rotation` returned —
|
|
58
|
+
# each row a hash carrying at least `:last_swept` and
|
|
59
|
+
# `:yield_score`, both `{ value: Integer }`, the shape every
|
|
60
|
+
# VO-typed field in this ledger already comes back as. Returns
|
|
61
|
+
# `nil` for an empty rotation, the same "nothing waiting" case
|
|
62
|
+
# `bin/qa_sweep` already handles by seeding the default targets.
|
|
63
|
+
#
|
|
64
|
+
# The floor wins outright — no starvation, on purpose (see
|
|
65
|
+
# `QualityControlDials::ROTATION_STALE_FLOOR_SECONDS`'s own
|
|
66
|
+
# comment for why a floor and not a total exclusion). A row stale
|
|
67
|
+
# past `floor_seconds` is picked ahead of every row that is not,
|
|
68
|
+
# oldest-first among however many have crossed it — the same
|
|
69
|
+
# tiebreak `Rotation` itself already uses for everything, which
|
|
70
|
+
# keeps the floor from becoming a new source of starvation between
|
|
71
|
+
# two long-neglected targets.
|
|
72
|
+
#
|
|
73
|
+
# Below the floor, highest combined score wins. `staleness +
|
|
74
|
+
# (yield_score * weight_seconds)` — plain addition, never a ratio
|
|
75
|
+
# or anything that could divide by zero, and the units are
|
|
76
|
+
# deliberately the same (seconds) so `weight_seconds` reads as
|
|
77
|
+
# "how many seconds of extra staleness one point of yield is
|
|
78
|
+
# worth" rather than an opaque multiplier nobody could sanity
|
|
79
|
+
# check by eye.
|
|
80
|
+
def pick(rows, now:, weight_seconds: QualityControlDials::YIELD_WEIGHT_SECONDS,
|
|
81
|
+
floor_seconds: QualityControlDials::ROTATION_STALE_FLOOR_SECONDS)
|
|
82
|
+
return nil if rows.empty?
|
|
83
|
+
|
|
84
|
+
floored = rows.select { |row| staleness(row, now) >= floor_seconds }
|
|
85
|
+
return floored.min_by { |row| row[:last_swept][:value] } unless floored.empty?
|
|
86
|
+
|
|
87
|
+
rows.max_by { |row| staleness(row, now) + (row[:yield_score][:value] * weight_seconds) }
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def staleness(row, now) = now - row[:last_swept][:value]
|
|
91
|
+
private_class_method :staleness
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
require "hecks/naming"
|
|
3
|
+
|
|
4
|
+
module Hecks
|
|
5
|
+
module Fuzzing
|
|
6
|
+
# What a compiled Rust binary declares it did not generate — read off the
|
|
7
|
+
# `manifest.json` files `rust/project/domain_generator.rb` writes beside
|
|
8
|
+
# every generated module, never inferred from Rust's refusal wording.
|
|
9
|
+
#
|
|
10
|
+
# The differential fuzzer (`Differential.diff`) used to drop any refusal
|
|
11
|
+
# whose Rust error contained "is not generated for this domain". That
|
|
12
|
+
# tolerated whatever Rust happened to say, including a codegen regression
|
|
13
|
+
# that started refusing a construct it used to generate. Now a query or
|
|
14
|
+
# read-model verb is dropped from the comparison if and only if the
|
|
15
|
+
# generator's own manifest recorded it as `generated: false`, with the
|
|
16
|
+
# `gap_class` and `construct` that explain why. A refusal the manifest
|
|
17
|
+
# does not account for stays in the comparison and fails it.
|
|
18
|
+
#
|
|
19
|
+
# **Which manifests describe a binary**. `build_and_pin` (spec/support/
|
|
20
|
+
# rust_conformance_helpers.rb) and `bin/qa_generated_domains` both pin a
|
|
21
|
+
# feature's binary at `<rust_dir>/target/debug/rust-<feature>`. That
|
|
22
|
+
# binary compiles `src/generated/<feature>/` plus every shared framework
|
|
23
|
+
# chapter (a generated directory with no `merged.rs` of its own —
|
|
24
|
+
# `governance`, `identity`; see the generated `mod.rs` header). Ids in
|
|
25
|
+
# those manifests are domain-qualified, so a chapter a domain never
|
|
26
|
+
# attaches contributes entries no sequence for that domain can name.
|
|
27
|
+
#
|
|
28
|
+
# **A missing manifest tolerates nothing**. A hand-written fixture crate, or
|
|
29
|
+
# a tree generated before manifests existed, has no declaration to
|
|
30
|
+
# honour, so every refusal it produces is compared as-is. That is the
|
|
31
|
+
# fail-closed direction.
|
|
32
|
+
class RustGapManifest
|
|
33
|
+
# The only kinds the kernel answers as a query step. A not-generated
|
|
34
|
+
# command changes state, so dropping its refusal would not make the
|
|
35
|
+
# comparison honest; those stay compared and fail.
|
|
36
|
+
TOLERABLE_KINDS = %w[query read_model].freeze
|
|
37
|
+
PINNED_BINARY = %r{\A(?<rust_dir>.+)/target/debug/rust-(?<feature>[a-z0-9_]+)\z}
|
|
38
|
+
|
|
39
|
+
attr_reader :rust_dir, :feature, :entries
|
|
40
|
+
|
|
41
|
+
def self.for_binary(binary)
|
|
42
|
+
match = PINNED_BINARY.match(File.expand_path(binary.to_s))
|
|
43
|
+
unless match
|
|
44
|
+
raise ArgumentError, "#{binary.inspect} is not a pinned conformance binary " \
|
|
45
|
+
"(<rust_dir>/target/debug/rust-<feature>) — cannot tell which manifest describes it"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
new(rust_dir: match[:rust_dir], feature: match[:feature])
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Every committed manifest entry under `rust_dir`, each tagged with the
|
|
52
|
+
# generated module it came from — what the boundary ratchet and
|
|
53
|
+
# bin/rust_coverage's allowlist staleness check read.
|
|
54
|
+
def self.all_entries(rust_dir)
|
|
55
|
+
Dir.glob(File.join(rust_dir, "src/generated/*/manifest.json")).flat_map do |path|
|
|
56
|
+
module_name = File.basename(File.dirname(path))
|
|
57
|
+
JSON.parse(File.read(path)).map { |entry| entry.merge("module" => module_name) }
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def initialize(rust_dir:, feature:)
|
|
62
|
+
@rust_dir = rust_dir
|
|
63
|
+
@feature = feature
|
|
64
|
+
@entries = manifest_paths.flat_map { |path| JSON.parse(File.read(path)) }.freeze
|
|
65
|
+
@not_generated = index_not_generated
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# The manifest entry that declares `verb` not generated, or nil. `verb`
|
|
69
|
+
# is the wire spelling a sequence step uses; an ad hoc filter (a Hash)
|
|
70
|
+
# is never declared and answers nil.
|
|
71
|
+
def not_generated(verb)
|
|
72
|
+
return nil unless verb.is_a?(String)
|
|
73
|
+
|
|
74
|
+
@not_generated[verb]
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def not_generated?(verb) = !not_generated(verb).nil?
|
|
78
|
+
|
|
79
|
+
def not_generated_verbs = @not_generated.keys.to_set
|
|
80
|
+
|
|
81
|
+
private
|
|
82
|
+
|
|
83
|
+
def manifest_paths
|
|
84
|
+
generated = File.join(rust_dir, "src/generated")
|
|
85
|
+
own = File.join(generated, feature, "manifest.json")
|
|
86
|
+
chapters = Dir.glob(File.join(generated, "*/manifest.json")).reject do |path|
|
|
87
|
+
dir = File.dirname(path)
|
|
88
|
+
File.basename(dir) == feature || File.exist?(File.join(dir, "merged.rs"))
|
|
89
|
+
end
|
|
90
|
+
([own] + chapters.sort).select { |path| File.exist?(path) }
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def index_not_generated
|
|
94
|
+
@entries.each_with_object({}) do |entry, index|
|
|
95
|
+
next unless TOLERABLE_KINDS.include?(entry["kind"]) && entry["generated"] == false
|
|
96
|
+
|
|
97
|
+
wire_verbs(entry).each { |verb| index[verb] = entry }
|
|
98
|
+
end.freeze
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# A query is asked by its id. A read model's id is "Domain::Name", but
|
|
102
|
+
# it is asked as "Domain.Name" or "Domain.name_in_snake_case" — the two
|
|
103
|
+
# spellings `kernel::read_model::find` accepts (`matches_snake_alias`,
|
|
104
|
+
# a port of `Hecks::Naming.snake`).
|
|
105
|
+
def wire_verbs(entry)
|
|
106
|
+
return [entry["id"]] if entry["kind"] == "query"
|
|
107
|
+
|
|
108
|
+
domain, name = entry["id"].split("::", 2)
|
|
109
|
+
["#{domain}.#{name}", "#{domain}.#{Hecks::Naming.snake(name)}"].uniq
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|