hecks 1.3.0 → 1.5.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 +72 -7
- data/lib/hecks/adapters/driven/d1.rb +187 -23
- data/lib/hecks/adapters/driven/folder.rb +83 -10
- data/lib/hecks/adapters/driven/google_authentication.rb +33 -12
- data/lib/hecks/adapters/driven/governance_authorization.rb +87 -18
- data/lib/hecks/adapters/driven/heki/journal.rb +13 -4
- data/lib/hecks/adapters/driven/heki/saga_store.rb +56 -10
- data/lib/hecks/adapters/driven/heki/snapshot.rb +1 -1
- data/lib/hecks/adapters/driven/heki.rb +106 -9
- data/lib/hecks/adapters/driven/identity_registry.rb +12 -2
- data/lib/hecks/adapters/driven/in_memory_ordering.rb +25 -3
- data/lib/hecks/adapters/driven/in_process_key_vault.adapter +3 -0
- data/lib/hecks/adapters/driven/in_process_key_vault.rb +53 -0
- data/lib/hecks/adapters/driven/lambda/client.rb +67 -14
- data/lib/hecks/adapters/driven/lambda.rb +82 -35
- data/lib/hecks/adapters/driven/local_storage.rb +83 -10
- data/lib/hecks/adapters/driven/memory.rb +205 -9
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +21 -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/prism.rb +50 -11
- data/lib/hecks/adapters/driven/secure_random_identity.rb +3 -0
- 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/system_clock.rb +3 -0
- data/lib/hecks/adapters/driven/tenant_provisioner.adapter +3 -0
- data/lib/hecks/adapters/driven/tenant_provisioner.rb +66 -0
- data/lib/hecks/adapters/driven.rb +6 -4
- data/lib/hecks/adapters/driving/github_webhook.rb +31 -18
- data/lib/hecks/behaviors/dsl.rb +60 -2
- data/lib/hecks/behaviors/expectations.rb +190 -29
- data/lib/hecks/behaviors/ir.rb +12 -1
- data/lib/hecks/behaviors/rspec.rb +9 -1
- data/lib/hecks/behaviors/runner.rb +21 -2
- data/lib/hecks/behaviors.rb +9 -1
- data/lib/hecks/bluebook/aggregate.rb +43 -13
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +17 -10
- data/lib/hecks/bluebook/assembly/build.rb +26 -5
- data/lib/hecks/bluebook/assembly/contract.rb +98 -23
- data/lib/hecks/bluebook/assembly/contracts.rb +59 -52
- data/lib/hecks/bluebook/assembly/marks.rb +159 -30
- data/lib/hecks/bluebook/assembly/specializer.rb +38 -21
- data/lib/hecks/bluebook/assembly.rb +32 -14
- data/lib/hecks/bluebook/attribute.rb +26 -12
- data/lib/hecks/bluebook/behaviour/aggregate.rb +43 -11
- data/lib/hecks/bluebook/behaviour/attribute.rb +18 -5
- data/lib/hecks/bluebook/behaviour/chapter.rb +76 -5
- data/lib/hecks/bluebook/behaviour/command.rb +55 -25
- data/lib/hecks/bluebook/behaviour/domain_port.rb +27 -7
- data/lib/hecks/bluebook/behaviour/entity.rb +20 -8
- data/lib/hecks/bluebook/behaviour/hexagon.rb +30 -4
- data/lib/hecks/bluebook/behaviour/lifecycle.rb +27 -6
- data/lib/hecks/bluebook/behaviour/policy.rb +42 -17
- data/lib/hecks/bluebook/behaviour/process_manager.rb +39 -8
- data/lib/hecks/bluebook/behaviour/query.rb +6 -1
- data/lib/hecks/bluebook/behaviour/read_model.rb +29 -8
- data/lib/hecks/bluebook/behaviour/traits.rb +48 -12
- data/lib/hecks/bluebook/behaviour/value_object.rb +21 -9
- data/lib/hecks/bluebook/capabilities.rb +27 -0
- data/lib/hecks/bluebook/chapter.rb +51 -9
- data/lib/hecks/bluebook/command.rb +62 -17
- data/lib/hecks/bluebook/domain_port.rb +34 -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 +282 -123
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +112 -75
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +81 -2
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +486 -117
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +179 -47
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +116 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +284 -122
- 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 +191 -61
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +148 -132
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +130 -30
- data/lib/hecks/bluebook/dsl/identity_declaration.rb +38 -21
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +27 -4
- data/lib/hecks/bluebook/dsl/policy_builder.rb +86 -36
- 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 +111 -47
- data/lib/hecks/bluebook/dsl/query_builder.rb +37 -8
- data/lib/hecks/bluebook/dsl/read_model_builder.rb +127 -52
- data/lib/hecks/bluebook/dsl/rule_reference.rb +97 -43
- data/lib/hecks/bluebook/dsl/translation_builder.rb +150 -44
- data/lib/hecks/bluebook/dsl/value_object_builder.rb +68 -20
- 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 +40 -11
- data/lib/hecks/bluebook/expression/ast_json.rb +128 -36
- data/lib/hecks/bluebook/expression/ast_reader.rb +32 -3
- data/lib/hecks/bluebook/expression/canonical_form.rb +55 -16
- data/lib/hecks/bluebook/expression/evaluator.rb +221 -43
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +54 -18
- data/lib/hecks/bluebook/expression/resolver.rb +369 -128
- data/lib/hecks/bluebook/hexagon.rb +35 -1
- data/lib/hecks/bluebook/lifecycle.rb +12 -1
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +2 -1
- data/lib/hecks/bluebook/meta_validator/judge.rb +126 -108
- data/lib/hecks/bluebook/meta_validator/plan.rb +81 -46
- data/lib/hecks/bluebook/meta_validator/port_judge.rb +3 -2
- data/lib/hecks/bluebook/meta_validator/readings.rb +200 -50
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +68 -41
- data/lib/hecks/bluebook/meta_validator/shapes.rb +166 -21
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +286 -46
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +11 -10
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -5
- data/lib/hecks/bluebook/meta_validator.rb +235 -139
- data/lib/hecks/bluebook/model_check.rb +434 -104
- data/lib/hecks/bluebook/pattern_subset.rb +32 -10
- data/lib/hecks/bluebook/policy.rb +15 -13
- data/lib/hecks/bluebook/process_manager.rb +27 -14
- data/lib/hecks/bluebook/project_discovery.rb +5 -0
- data/lib/hecks/bluebook/project_loader.rb +40 -0
- data/lib/hecks/bluebook/project_register.rb +50 -6
- data/lib/hecks/bluebook/query.rb +31 -4
- data/lib/hecks/bluebook/read_model.rb +35 -15
- data/lib/hecks/bluebook/reference.rb +26 -13
- data/lib/hecks/bluebook/smoke_test.rb +46 -23
- data/lib/hecks/bluebook/synthesizer.rb +46 -12
- data/lib/hecks/bluebook/translation.rb +34 -5
- data/lib/hecks/bluebook/value_object.rb +29 -11
- data/lib/hecks/bluebook.rb +5 -6
- data/lib/hecks/codemod.rb +138 -50
- data/lib/hecks/construct.rb +21 -7
- data/lib/hecks/corpus.rb +438 -0
- data/lib/hecks/deploy/bluebook/deploy.hecksagon +19 -0
- data/lib/hecks/doc/reference.rb +200 -31
- data/lib/hecks/embryonaut_bluebook.rb +38 -15
- 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 +155 -35
- data/lib/hecks/facade/json_door.rb +106 -25
- data/lib/hecks/facade/surface/aggregate_door.rb +50 -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 -19
- data/lib/hecks/forms/html.rb +51 -7
- data/lib/hecks/forms/index_renderer.rb +14 -2
- data/lib/hecks/forms/page.rb +14 -0
- data/lib/hecks/forms/params.rb +120 -23
- data/lib/hecks/forms/port_argument.rb +14 -2
- data/lib/hecks/forms/query_form_renderer.rb +65 -2
- data/lib/hecks/forms/record_renderer.rb +60 -2
- data/lib/hecks/forms/record_table.rb +28 -1
- data/lib/hecks/forms/reference_options.rb +24 -0
- data/lib/hecks/forms/value_object_shape.rb +13 -3
- data/lib/hecks/forms.rb +24 -4
- data/lib/hecks/fqn.rb +59 -1
- data/lib/hecks/framework/bluebook/governance.bluebook +9 -0
- data/lib/hecks/framework/bluebook/privacy.bluebook +155 -0
- data/lib/hecks/framework/oidc.json +15 -0
- data/lib/hecks/framework.rb +79 -25
- data/lib/hecks/freezer.rb +27 -11
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +241 -106
- data/lib/hecks/fuzzing/combination_miner.rb +178 -0
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +241 -45
- data/lib/hecks/fuzzing/coverage_campaign.rb +161 -0
- data/lib/hecks/fuzzing/differential.rb +192 -0
- data/lib/hecks/fuzzing/domain_generator.rb +871 -0
- data/lib/hecks/fuzzing/era_boundary.rb +68 -19
- data/lib/hecks/fuzzing/form_census.rb +121 -20
- data/lib/hecks/fuzzing/generated_domain_check.rb +171 -0
- data/lib/hecks/fuzzing/invalid_value_generator.rb +45 -6
- data/lib/hecks/fuzzing/isolated_boot.rb +137 -80
- data/lib/hecks/fuzzing/nondeterministic.rb +79 -0
- data/lib/hecks/fuzzing/persistence_parity.rb +111 -21
- data/lib/hecks/fuzzing/properties/corrections.rb +34 -9
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +300 -51
- data/lib/hecks/fuzzing/properties/guards.rb +86 -42
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +80 -32
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +40 -35
- data/lib/hecks/fuzzing/properties/outbox.rb +70 -32
- data/lib/hecks/fuzzing/properties/querying.rb +82 -28
- data/lib/hecks/fuzzing/properties.rb +84 -51
- data/lib/hecks/fuzzing/qa_settings.rb +164 -0
- data/lib/hecks/fuzzing/replay.rb +241 -133
- data/lib/hecks/fuzzing/rotation_priority.rb +48 -28
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +139 -0
- data/lib/hecks/fuzzing/self_consistency.rb +315 -137
- data/lib/hecks/fuzzing/sequence_generator/adversary.rb +46 -40
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +18 -11
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +13 -12
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +21 -12
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +59 -32
- data/lib/hecks/fuzzing/sequence_generator.rb +158 -23
- data/lib/hecks/fuzzing/shrinker.rb +309 -0
- data/lib/hecks/fuzzing/structural_skips.rb +37 -130
- data/lib/hecks/fuzzing/sweep_depth.rb +12 -4
- data/lib/hecks/fuzzing/target_capabilities.rb +107 -29
- data/lib/hecks/fuzzing/value_generator.rb +110 -22
- data/lib/hecks/fuzzing.rb +5 -0
- data/lib/hecks/grammar/evolve.rb +188 -12
- data/lib/hecks/grammar.rb +53 -7
- data/lib/hecks/ir.rb +51 -20
- 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 +348 -13
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +11 -0
- data/lib/hecks/language/oidc.json +5 -0
- data/lib/hecks/literal.rb +41 -9
- data/lib/hecks/naming.rb +112 -31
- data/lib/hecks/ports/access_control.rb +53 -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 +50 -11
- data/lib/hecks/ports/clock.rb +42 -23
- data/lib/hecks/ports/extraction.rb +16 -0
- data/lib/hecks/ports/identity_assignment.rb +23 -2
- data/lib/hecks/ports/identity_generation.rb +17 -3
- data/lib/hecks/ports/identity_resolution.rb +17 -1
- data/lib/hecks/ports/key_vault.port +6 -0
- data/lib/hecks/ports/key_vault.rb +58 -0
- 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 +118 -66
- 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 +34 -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 +33 -9
- 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 +95 -6
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +25 -2
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +314 -90
- 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 +48 -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 +58 -19
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +96 -5
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +15 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +9 -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 +23 -3
- 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 +41 -8
- data/lib/hecks/ports/query/ordering.rb +21 -6
- data/lib/hecks/ports/query.rb +35 -0
- data/lib/hecks/ports.rb +1 -0
- data/lib/hecks/projections/bootstrap_table.rb +147 -0
- data/lib/hecks/projections/diagrams.rb +315 -79
- data/lib/hecks/projections/glossary/html.rb +91 -3
- data/lib/hecks/projections/glossary/markdown.rb +50 -3
- data/lib/hecks/projections/glossary/mermaid.rb +49 -1
- data/lib/hecks/projections/glossary/sections.rb +1 -1
- data/lib/hecks/projections/glossary/sentences.rb +110 -5
- data/lib/hecks/projections/glossary.rb +173 -31
- data/lib/hecks/projections/ir.rb +1 -1
- data/lib/hecks/projections/model/deviations.rb +62 -17
- data/lib/hecks/projections/model.rb +75 -21
- data/lib/hecks/projections/oidc.rb +45 -8
- data/lib/hecks/projections/parser_table.rb +53 -12
- data/lib/hecks/projections/reference.rb +15 -3
- data/lib/hecks/projections/rust_vocabulary.rb +646 -0
- data/lib/hecks/projections/shape.rb +10 -2
- data/lib/hecks/projections/statements.rb +69 -22
- data/lib/hecks/projections/vocabulary.rb +26 -9
- data/lib/hecks/projections.rb +5 -3
- data/lib/hecks/projector/cli_projector.rb +245 -37
- data/lib/hecks/projector/docs_projector.rb +154 -28
- data/lib/hecks/projector/exporter.rb +104 -29
- data/lib/hecks/projector/ir_projector.rb +7 -1
- data/lib/hecks/projector/narrate_projector.rb +144 -23
- data/lib/hecks/projector/target.rb +42 -18
- data/lib/hecks/projector.rb +86 -18
- data/lib/hecks/query_ir.rb +94 -47
- data/lib/hecks/query_specification/common/comparators.rb +19 -3
- data/lib/hecks/query_specification/common/comparison.rb +109 -27
- data/lib/hecks/query_specification/common/dsl.rb +65 -9
- data/lib/hecks/query_specification/common/null_policy.rb +61 -15
- 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 +9 -3
- data/lib/hecks/router/namespace_installer.rb +16 -3
- data/lib/hecks/router.rb +56 -1
- data/lib/hecks/runtime/aggregate_lock.rb +20 -11
- data/lib/hecks/runtime/boot_gates.rb +21 -3
- data/lib/hecks/runtime/caller.rb +40 -8
- data/lib/hecks/runtime/capability_graph.rb +13 -2
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +40 -41
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +45 -67
- data/lib/hecks/runtime/command_interpreter.rb +195 -113
- data/lib/hecks/runtime/command_rules/admissibility.rb +231 -80
- data/lib/hecks/runtime/command_rules/arithmetic.rb +154 -96
- 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 +145 -55
- data/lib/hecks/runtime/command_rules.rb +3 -0
- data/lib/hecks/runtime/dependency_planning.rb +56 -11
- data/lib/hecks/runtime/dispatcher.rb +263 -92
- data/lib/hecks/runtime/entity_element.rb +304 -67
- data/lib/hecks/runtime/entity_interpreter.rb +149 -88
- data/lib/hecks/runtime/errors.rb +37 -23
- data/lib/hecks/runtime/event.rb +15 -10
- data/lib/hecks/runtime/identity.rb +91 -23
- data/lib/hecks/runtime/instance.rb +103 -18
- data/lib/hecks/runtime/interpreting.rb +24 -16
- data/lib/hecks/runtime/invocation.rb +358 -0
- data/lib/hecks/runtime/loader.rb +105 -19
- data/lib/hecks/runtime/outbox.rb +164 -26
- data/lib/hecks/runtime/policy_interpreter.rb +73 -60
- data/lib/hecks/runtime/port_operation_interpreter.rb +42 -19
- data/lib/hecks/runtime/query_interpreter.rb +93 -74
- data/lib/hecks/runtime/reaction_invocation.rb +73 -28
- data/lib/hecks/runtime/read_model_interpreter.rb +60 -44
- data/lib/hecks/runtime/rebuild_sweep.rb +32 -4
- data/lib/hecks/runtime/reference_hop.rb +48 -6
- data/lib/hecks/runtime/refusal_wording.rb +142 -115
- data/lib/hecks/runtime/registry/saga_persistence.rb +32 -21
- data/lib/hecks/runtime/registry/verification.rb +153 -28
- data/lib/hecks/runtime/registry.rb +202 -32
- data/lib/hecks/runtime/remote_dispatcher.rb +125 -24
- data/lib/hecks/runtime/routing.rb +36 -154
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +25 -27
- data/lib/hecks/runtime/saga_interpreter.rb +90 -76
- data/lib/hecks/runtime/saga_pending_dispatch.rb +12 -12
- data/lib/hecks/runtime/tenant_check.rb +33 -13
- data/lib/hecks/runtime/tenant_scope.rb +23 -5
- data/lib/hecks/runtime/value/admission.rb +75 -30
- data/lib/hecks/runtime/value/coercion.rb +555 -142
- data/lib/hecks/runtime/value/entity_list_coercion.rb +132 -60
- data/lib/hecks/runtime/value.rb +71 -21
- data/lib/hecks/runtime.rb +39 -7
- data/lib/hecks/storehouse.rb +368 -72
- data/lib/hecks/tenancy/bluebook/tenancy.bluebook +130 -0
- data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +32 -0
- data/lib/hecks/version.rb +3 -3
- data/lib/hecks/vocabulary.rb +205 -4
- data/lib/hecks.rb +91 -11
- data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +19 -11
- data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +24 -12
- data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +38 -14
- metadata +28 -2
|
@@ -1,51 +1,61 @@
|
|
|
1
1
|
module Hecks
|
|
2
2
|
module Fuzzing
|
|
3
|
-
#
|
|
3
|
+
# The weighted half of `QualityControl::Target.Rotation`
|
|
4
4
|
# (qa/bluebook/quality_control.bluebook) — see that query's own
|
|
5
5
|
# comment for why the ledger itself still only offers
|
|
6
6
|
# least-recently-swept order: `order_by` sorts by exactly one stored
|
|
7
7
|
# field, and a target's actual rotation priority wants two blended
|
|
8
|
-
# together (time since last swept,
|
|
8
|
+
# together (time since last swept, and recent yield), which nothing
|
|
9
9
|
# in the query sublanguage can express. `Rotation` stays the raw
|
|
10
10
|
# view; this module is where the blend actually happens, against the
|
|
11
11
|
# rows that query already returns.
|
|
12
12
|
#
|
|
13
|
-
#
|
|
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.
|
|
13
|
+
# ## Pure, deliberately
|
|
21
14
|
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
15
|
+
# Every method here is a function of its own arguments only — no clock
|
|
16
|
+
# read, no query dispatched, nothing random — so this is unit-testable
|
|
17
|
+
# with plain hashes and no ledger boot at all, and reruns identically
|
|
18
|
+
# given the same rotation, the same `now` and the same dials. `now`
|
|
19
|
+
# arrives as an argument for the exact reason `Target.Claim`'s own
|
|
20
|
+
# comment already gives: a pure function cannot ask the time, so
|
|
21
|
+
# whoever calls this supplies it, exactly as it supplies an id.
|
|
22
|
+
#
|
|
23
|
+
# ## Where this actually matters, and where it does not
|
|
24
|
+
#
|
|
25
|
+
# Checked against `bin/qa_sweep`'s own code, not assumed. `bin/qa_sweep
|
|
26
|
+
# --all` sweeps every currently-waiting target in one pass, regardless
|
|
27
|
+
# of order (`run_all_mode`'s own `waiting.map { spawn_sweep_child }` —
|
|
28
|
+
# every element the query returned, never `.first`), so nothing about
|
|
29
|
+
# this module's own ordering changes what `--all` does; it already
|
|
30
|
+
# sweeps everything the ledger has to offer. What it changes is
|
|
31
|
+
# `bin/qa_sweep` invoked with no target argument, which today picks
|
|
32
|
+
# exactly one target via `Target.Rotation.first` — wiring `.pick` in
|
|
33
|
+
# there instead is this module's one real caller, and (per the same
|
|
34
|
+
# investigation) its only one: there is no separate scheduling or
|
|
35
|
+
# concurrency-limit mechanism elsewhere in this repository for it to
|
|
36
|
+
# feed instead.
|
|
35
37
|
module RotationPriority
|
|
36
38
|
module_function
|
|
37
39
|
|
|
38
|
-
#
|
|
40
|
+
# The next stored `Target.yield_score` — decay what survives from
|
|
39
41
|
# before, then add whatever this just-concluded period actually
|
|
40
42
|
# found. Integer division, like every other count in this ledger
|
|
41
43
|
# (`Sweep.CheckCount`, `Bug.BugOrder`): a yield score is a
|
|
42
44
|
# priority signal, not a precise statistic, and a fractional score
|
|
43
45
|
# would need a value object this ledger does not have.
|
|
44
46
|
#
|
|
45
|
-
# `decay_percent`
|
|
47
|
+
# `decay_percent` defaults to the dial, not a literal, so a caller
|
|
46
48
|
# that does not care still gets the practice's own current answer
|
|
47
49
|
# to "how much of this is 'recent'" rather than a second, silently
|
|
48
50
|
# drifting copy of the same number.
|
|
51
|
+
#
|
|
52
|
+
# @param old_score [Integer] the target's `Target.yield_score` before this period
|
|
53
|
+
# @param surprises_this_period [Integer] how many Surprised checks this period found
|
|
54
|
+
# @param decay_percent [Integer] percent of `old_score` that survives into the new
|
|
55
|
+
# score; defaults to `QualityControlDials::YIELD_DECAY_PERCENT`
|
|
56
|
+
# @return [Integer] the next `Target.yield_score` to store
|
|
57
|
+
# @raise [ArgumentError] if `old_score` is negative
|
|
58
|
+
# @raise [ArgumentError] if `surprises_this_period` is negative
|
|
49
59
|
def next_yield_score(old_score:, surprises_this_period:,
|
|
50
60
|
decay_percent: QualityControlDials::YIELD_DECAY_PERCENT)
|
|
51
61
|
raise ArgumentError, "old_score must not be negative" if old_score.negative?
|
|
@@ -54,14 +64,14 @@ module Hecks
|
|
|
54
64
|
((old_score * decay_percent) / 100) + surprises_this_period
|
|
55
65
|
end
|
|
56
66
|
|
|
57
|
-
#
|
|
67
|
+
# The pick itself. `rows` is whatever `Target.Rotation` returned —
|
|
58
68
|
# each row a hash carrying at least `:last_swept` and
|
|
59
69
|
# `:yield_score`, both `{ value: Integer }`, the shape every
|
|
60
70
|
# VO-typed field in this ledger already comes back as. Returns
|
|
61
71
|
# `nil` for an empty rotation, the same "nothing waiting" case
|
|
62
72
|
# `bin/qa_sweep` already handles by seeding the default targets.
|
|
63
73
|
#
|
|
64
|
-
#
|
|
74
|
+
# The floor wins outright — no starvation, on purpose (see
|
|
65
75
|
# `QualityControlDials::ROTATION_STALE_FLOOR_SECONDS`'s own
|
|
66
76
|
# comment for why a floor and not a total exclusion). A row stale
|
|
67
77
|
# past `floor_seconds` is picked ahead of every row that is not,
|
|
@@ -70,13 +80,23 @@ module Hecks
|
|
|
70
80
|
# keeps the floor from becoming a new source of starvation between
|
|
71
81
|
# two long-neglected targets.
|
|
72
82
|
#
|
|
73
|
-
#
|
|
83
|
+
# Below the floor, highest combined score wins. `staleness +
|
|
74
84
|
# (yield_score * weight_seconds)` — plain addition, never a ratio
|
|
75
85
|
# or anything that could divide by zero, and the units are
|
|
76
86
|
# deliberately the same (seconds) so `weight_seconds` reads as
|
|
77
87
|
# "how many seconds of extra staleness one point of yield is
|
|
78
88
|
# worth" rather than an opaque multiplier nobody could sanity
|
|
79
89
|
# check by eye.
|
|
90
|
+
#
|
|
91
|
+
# @param rows [Array<Hash>] rows from `Target.Rotation`, each carrying at least
|
|
92
|
+
# `:last_swept` and `:yield_score` as `{ value: Integer }`
|
|
93
|
+
# @param now [Integer] the current time, Unix epoch seconds
|
|
94
|
+
# @param weight_seconds [Integer] seconds of extra staleness one point of yield is
|
|
95
|
+
# worth; defaults to `QualityControlDials::YIELD_WEIGHT_SECONDS`
|
|
96
|
+
# @param floor_seconds [Integer] staleness, in seconds, past which a row is picked
|
|
97
|
+
# ahead of every row not yet that stale; defaults to
|
|
98
|
+
# `QualityControlDials::ROTATION_STALE_FLOOR_SECONDS`
|
|
99
|
+
# @return [Hash, nil] the picked row, or `nil` if `rows` is empty
|
|
80
100
|
def pick(rows, now:, weight_seconds: QualityControlDials::YIELD_WEIGHT_SECONDS,
|
|
81
101
|
floor_seconds: QualityControlDials::ROTATION_STALE_FLOOR_SECONDS)
|
|
82
102
|
return nil if rows.empty?
|
|
@@ -0,0 +1,139 @@
|
|
|
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`) drops a query or
|
|
11
|
+
# read-model verb from the comparison if and only if the generator's own
|
|
12
|
+
# manifest recorded it as `generated: false`, with the `gap_class` and
|
|
13
|
+
# `construct` that explain why — never by pattern-matching Rust's
|
|
14
|
+
# refusal wording ("is not generated for this domain"), which would
|
|
15
|
+
# tolerate whatever Rust happened to say, including a codegen
|
|
16
|
+
# regression that silently started refusing a construct it once
|
|
17
|
+
# generated. A refusal the manifest does not account for stays in the
|
|
18
|
+
# comparison and fails it.
|
|
19
|
+
#
|
|
20
|
+
# ## Which manifests describe a binary
|
|
21
|
+
#
|
|
22
|
+
# `build_and_pin` (spec/support/rust_conformance_helpers.rb) and
|
|
23
|
+
# `bin/qa_generated_domains` both pin a feature's binary at
|
|
24
|
+
# `<rust_dir>/target/debug/rust-<feature>`. That binary compiles
|
|
25
|
+
# `src/generated/<feature>/` plus every shared framework chapter (a
|
|
26
|
+
# generated directory with no `merged.rs` of its own — `governance`,
|
|
27
|
+
# `identity`; see the generated `mod.rs` header). Ids in those manifests
|
|
28
|
+
# are domain-qualified, so a chapter a domain never attaches contributes
|
|
29
|
+
# entries no sequence for that domain can name.
|
|
30
|
+
#
|
|
31
|
+
# ## A missing manifest tolerates nothing
|
|
32
|
+
#
|
|
33
|
+
# A hand-written fixture crate, or a tree generated before manifests
|
|
34
|
+
# existed, has no declaration to honour, so every refusal it produces
|
|
35
|
+
# is compared as-is. That is the fail-closed direction.
|
|
36
|
+
class RustGapManifest
|
|
37
|
+
# The only kinds the kernel answers as a query step. A not-generated
|
|
38
|
+
# command changes state, so dropping its refusal would not make the
|
|
39
|
+
# comparison honest; those stay compared and fail.
|
|
40
|
+
TOLERABLE_KINDS = %w[query read_model].freeze
|
|
41
|
+
PINNED_BINARY = %r{\A(?<rust_dir>.+)/target/debug/rust-(?<feature>[a-z0-9_]+)\z}
|
|
42
|
+
|
|
43
|
+
attr_reader :rust_dir, :feature, :entries
|
|
44
|
+
|
|
45
|
+
# Builds the manifest reader for the pinned conformance binary at `binary`.
|
|
46
|
+
#
|
|
47
|
+
# @param binary [String] path to a pinned binary, `<rust_dir>/target/debug/rust-<feature>`
|
|
48
|
+
# @return [Fuzzing::RustGapManifest] the manifest reader for that binary's feature
|
|
49
|
+
# @raise [ArgumentError] if `binary` does not match the pinned-binary path shape
|
|
50
|
+
def self.for_binary(binary)
|
|
51
|
+
match = PINNED_BINARY.match(File.expand_path(binary.to_s))
|
|
52
|
+
unless match
|
|
53
|
+
raise ArgumentError, "#{binary.inspect} is not a pinned conformance binary " \
|
|
54
|
+
"(<rust_dir>/target/debug/rust-<feature>) — cannot tell which manifest describes it"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
new(rust_dir: match[:rust_dir], feature: match[:feature])
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Every committed manifest entry under `rust_dir`, each tagged with the
|
|
61
|
+
# generated module it came from — what the boundary ratchet and
|
|
62
|
+
# bin/rust_coverage's allowlist staleness check read.
|
|
63
|
+
#
|
|
64
|
+
# @param rust_dir [String] path to the Rust project root (holds `src/generated/*/`)
|
|
65
|
+
# @return [Array<Hash>] every `src/generated/*/manifest.json` entry, each a
|
|
66
|
+
# String-keyed manifest Hash plus `"module" => String` naming the directory it came from
|
|
67
|
+
def self.all_entries(rust_dir)
|
|
68
|
+
Dir.glob(File.join(rust_dir, "src/generated/*/manifest.json")).flat_map do |path|
|
|
69
|
+
module_name = File.basename(File.dirname(path))
|
|
70
|
+
JSON.parse(File.read(path)).map { |entry| entry.merge("module" => module_name) }
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# @param rust_dir [String] path to the Rust project root (holds `src/generated/*/`)
|
|
75
|
+
# @param feature [String] the domain feature this manifest reader describes
|
|
76
|
+
def initialize(rust_dir:, feature:)
|
|
77
|
+
@rust_dir = rust_dir
|
|
78
|
+
@feature = feature
|
|
79
|
+
@entries = manifest_paths.flat_map { |path| JSON.parse(File.read(path)) }.freeze
|
|
80
|
+
@not_generated = index_not_generated
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# The manifest entry that declares `verb` not generated, or nil. `verb`
|
|
84
|
+
# is the wire spelling a sequence step uses; an ad hoc filter (a Hash)
|
|
85
|
+
# is never declared and answers nil.
|
|
86
|
+
#
|
|
87
|
+
# @param verb [String, Object] the wire-spelled query or read-model verb to look up
|
|
88
|
+
# @return [Hash, nil] the String-keyed manifest entry declaring `verb` not generated,
|
|
89
|
+
# or nil if `verb` is not a String or no entry declares it
|
|
90
|
+
def not_generated(verb)
|
|
91
|
+
return nil unless verb.is_a?(String)
|
|
92
|
+
|
|
93
|
+
@not_generated[verb]
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Answers whether `verb` is declared not generated by this manifest.
|
|
97
|
+
#
|
|
98
|
+
# @param verb [String, Object] the wire-spelled query or read-model verb to look up
|
|
99
|
+
# @return [Boolean] whether the manifest declares `verb` not generated
|
|
100
|
+
def not_generated?(verb) = !not_generated(verb).nil?
|
|
101
|
+
|
|
102
|
+
# Lists every verb this manifest declares not generated.
|
|
103
|
+
#
|
|
104
|
+
# @return [Set<String>] every verb the manifest declares not generated
|
|
105
|
+
def not_generated_verbs = @not_generated.keys.to_set
|
|
106
|
+
|
|
107
|
+
private
|
|
108
|
+
|
|
109
|
+
def manifest_paths
|
|
110
|
+
generated = File.join(rust_dir, "src/generated")
|
|
111
|
+
own = File.join(generated, feature, "manifest.json")
|
|
112
|
+
chapters = Dir.glob(File.join(generated, "*/manifest.json")).reject do |path|
|
|
113
|
+
dir = File.dirname(path)
|
|
114
|
+
File.basename(dir) == feature || File.exist?(File.join(dir, "merged.rs"))
|
|
115
|
+
end
|
|
116
|
+
([own] + chapters.sort).select { |path| File.exist?(path) }
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def index_not_generated
|
|
120
|
+
@entries.each_with_object({}) do |entry, index|
|
|
121
|
+
next unless TOLERABLE_KINDS.include?(entry["kind"]) && entry["generated"] == false
|
|
122
|
+
|
|
123
|
+
wire_verbs(entry).each { |verb| index[verb] = entry }
|
|
124
|
+
end.freeze
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# A query is asked by its id. A read model's id is "Domain::Name", but
|
|
128
|
+
# it is asked as "Domain.Name" or "Domain.name_in_snake_case" — the two
|
|
129
|
+
# spellings `kernel::read_model::find` accepts (`matches_snake_alias`,
|
|
130
|
+
# a port of `Hecks::Naming.snake`).
|
|
131
|
+
def wire_verbs(entry)
|
|
132
|
+
return [entry["id"]] if entry["kind"] == "query"
|
|
133
|
+
|
|
134
|
+
domain, name = entry["id"].split("::", 2)
|
|
135
|
+
["#{domain}.#{name}", "#{domain}.#{Hecks::Naming.snake(name)}"].uniq
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|