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
|
@@ -4,11 +4,16 @@ module Hecks
|
|
|
4
4
|
module Adapters
|
|
5
5
|
class PostgresEra
|
|
6
6
|
class Lineage
|
|
7
|
-
#
|
|
7
|
+
# The per-`where`-field read cache that lets a declared query find
|
|
8
|
+
# its ids without reducing the whole aggregate first.
|
|
9
|
+
#
|
|
10
|
+
# ## Why a cache and not an index
|
|
11
|
+
#
|
|
12
|
+
# **The read-side of the era workaround**. Once a domain mints a
|
|
8
13
|
# second era, `head_view` is a `DISTINCT ON`/`UNION ALL`
|
|
9
14
|
# reduction — and a `where` clause on anything but `id` (its own
|
|
10
15
|
# partition key) cannot be pushed through that reduction, so every
|
|
11
|
-
# declared query pays the cost of reducing the
|
|
16
|
+
# declared query pays the cost of reducing the whole aggregate
|
|
12
17
|
# before it can filter anything (see docs/implemented/postgres-era-adapter-
|
|
13
18
|
# split-plan.md's own trigger section — this is a real
|
|
14
19
|
# SQL-semantics wall, not a missing index; adding one to
|
|
@@ -16,29 +21,35 @@ module Hecks
|
|
|
16
21
|
# prove a predicate on a non-partition column commutes with
|
|
17
22
|
# `DISTINCT ON` without risking a stale row winning).
|
|
18
23
|
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
24
|
+
# ## The table
|
|
25
|
+
#
|
|
26
|
+
# **The workaround**: one narrow table per declared `where`-field
|
|
27
|
+
# (never `order_by`-only fields — sorting the reduced output is
|
|
28
|
+
# not blocked by the reduction; only filtering is), holding
|
|
29
|
+
# exactly (id, ordinal, value) — the current extracted value for
|
|
23
30
|
# every live id, maintained transactionally by `append` alongside
|
|
24
31
|
# the head snapshot it already upserts (same ordinal-guard idiom:
|
|
25
32
|
# `WHERE ordinal < EXCLUDED.ordinal`). A query whose sole `where`
|
|
26
33
|
# is on a cached field never runs the reduction at all: `SELECT id
|
|
27
34
|
# FROM <field>_cache WHERE value <op> $1`, then `SELECT id, state
|
|
28
|
-
# FROM head_view WHERE id = ANY($ids)` — safe
|
|
35
|
+
# FROM head_view WHERE id = ANY($ids)` — safe through the
|
|
29
36
|
# reduction because `id` is its own partition key, unlike the
|
|
30
37
|
# original field.
|
|
31
38
|
#
|
|
32
|
-
#
|
|
39
|
+
# ## What it does not cover
|
|
40
|
+
#
|
|
41
|
+
# Scoped to non-list fields only, same reasoning Track A (plain
|
|
33
42
|
# Postgres) and Track B (Sqlite/D1) both landed on independently
|
|
34
43
|
# for their own automatic indexing: this codebase's `contains`
|
|
35
44
|
# compiles to element-membership (`jsonb_array_elements`/
|
|
36
45
|
# `json_each` + `EXISTS`), which a (id, ordinal, value) cache table
|
|
37
|
-
# keyed on
|
|
46
|
+
# keyed on one scalar value per id has no way to represent — a
|
|
38
47
|
# list field would need one row per (id, element), a different
|
|
39
48
|
# shape this plan does not build. `PostgresEra#eligible_for_cache?`
|
|
40
49
|
# is where that boundary lives.
|
|
41
50
|
module FieldCache
|
|
51
|
+
# Names the cache table for one field of one aggregate in one era.
|
|
52
|
+
#
|
|
42
53
|
# Deterministic and collision-free regardless of field-path
|
|
43
54
|
# length or storage-name length — Postgres identifiers cap at 63
|
|
44
55
|
# bytes, and a value-object member path (`compliance.review.
|
|
@@ -46,22 +57,52 @@ module Hecks
|
|
|
46
57
|
# that if built any less defensively. Not meant to be
|
|
47
58
|
# human-readable; `hecks_backfill_progress`/catalog lookups are
|
|
48
59
|
# always driven by this same computed name, never typed by hand.
|
|
60
|
+
#
|
|
61
|
+
# `@domain` is part of the hash input — this table is exposed to
|
|
62
|
+
# the exact same collision this whole file's siblings
|
|
63
|
+
# (`head_view`/`head_snapshot`/`matview`, `lineage.rb`) are
|
|
64
|
+
# domain-qualified against in docs/decisions/0059: without it,
|
|
65
|
+
# two domains bound to PostgresEra against the same database,
|
|
66
|
+
# each with an aggregate sharing a storage_name and a cached
|
|
67
|
+
# where-field of the same name, derive the identical
|
|
68
|
+
# `hecks_fc_<hash>` table and silently share cached rows across
|
|
69
|
+
# domains. Already fully hashed, so folding the domain in costs
|
|
70
|
+
# nothing readability could lose.
|
|
71
|
+
#
|
|
72
|
+
# @param storage_name [String] the aggregate's snake-cased storage name
|
|
73
|
+
# @param era [Integer] ordinal of the era the cache belongs to
|
|
74
|
+
# @param field [String] the cached `where` field, a dotted path for a
|
|
75
|
+
# value-object member such as `"compliance.review.deadline_at"`
|
|
76
|
+
# @return [String] unquoted table name, `hecks_fc_` plus 20 hex characters
|
|
49
77
|
def field_cache(storage_name, era, field)
|
|
50
|
-
"hecks_fc_#{Digest::SHA256.hexdigest("#{storage_name}\0#{era}\0#{field}")[0, 20]}"
|
|
78
|
+
"hecks_fc_#{Digest::SHA256.hexdigest("#{@domain}\0#{storage_name}\0#{era}\0#{field}")[0, 20]}"
|
|
51
79
|
end
|
|
52
80
|
|
|
81
|
+
# Creates one field's cache table if it is missing, then backfills it
|
|
82
|
+
# from the current head until the backfill is recorded complete.
|
|
83
|
+
#
|
|
53
84
|
# Self-healing, same idiom as `ensure_head_snapshot!`: cheap,
|
|
54
|
-
# unconditional, safe to call on every boot.
|
|
85
|
+
# unconditional, safe to call on every boot. Creation is a
|
|
55
86
|
# short-held lock (table doesn't exist yet — nothing to block);
|
|
56
|
-
#
|
|
87
|
+
# backfill runs outside it, chunk by chunk, each chunk its own
|
|
57
88
|
# short lock — never one transaction spanning the scan, per
|
|
58
89
|
# principle 1. `value_expression` is the exact SQL
|
|
59
90
|
# `PostgresEra#query_expression(field)` already compiles for
|
|
60
91
|
# this field, applied against a `state` column this module's own
|
|
61
92
|
# SQL always makes available in scope (see `field_cache_source_sql`)
|
|
62
|
-
# —
|
|
93
|
+
# — one source of truth for "what does this field mean", not a
|
|
63
94
|
# second hand-rolled copy that could silently drift from what a
|
|
64
95
|
# live query actually filters on.
|
|
96
|
+
#
|
|
97
|
+
# @param storage_name [String] the aggregate's snake-cased storage name
|
|
98
|
+
# @param era [Integer] ordinal of the era the cache belongs to
|
|
99
|
+
# @param field [String] the cached `where` field, dotted for a value-object member
|
|
100
|
+
# @param value_expression [String] SQL expression that extracts the field's
|
|
101
|
+
# value as text from a jsonb column named `state`
|
|
102
|
+
# @return [String] unquoted name of the cache table, as `field_cache` derives it
|
|
103
|
+
# @raise [PG::Error] if Postgres refuses the DDL, a source read, or an upsert
|
|
104
|
+
# @raise [Runtime::WiringError] if `era` is past 1, a chunk is still to be
|
|
105
|
+
# backfilled, and a held era's text fails its digest check (see `eras`)
|
|
65
106
|
def ensure_field_cache!(storage_name, era, field, value_expression)
|
|
66
107
|
name = field_cache(storage_name, era, field)
|
|
67
108
|
unless table_exists?(name)
|
|
@@ -83,6 +124,19 @@ module Hecks
|
|
|
83
124
|
name
|
|
84
125
|
end
|
|
85
126
|
|
|
127
|
+
# Fills an existing cache table from the reduced head, one committed chunk
|
|
128
|
+
# of `ResumableBackfill::CHUNK_SIZE` ids at a time, resuming from the cursor
|
|
129
|
+
# held in `hecks_backfill_progress` and doing nothing once it is complete.
|
|
130
|
+
#
|
|
131
|
+
# @param name [String] unquoted cache table name, from `field_cache`
|
|
132
|
+
# @param storage_name [String] the aggregate's snake-cased storage name
|
|
133
|
+
# @param era [Integer] ordinal of the era whose head is read
|
|
134
|
+
# @param value_expression [String] SQL expression that extracts the field's
|
|
135
|
+
# value as text from a jsonb column named `state`
|
|
136
|
+
# @return [void]
|
|
137
|
+
# @raise [PG::Error] if Postgres refuses a source read or an upsert
|
|
138
|
+
# @raise [Runtime::WiringError] if `era` is past 1, a chunk is still to be
|
|
139
|
+
# backfilled, and a held era's text fails its digest check (see `eras`)
|
|
86
140
|
def backfill_field_cache!(name, storage_name, era, value_expression)
|
|
87
141
|
chunked_backfill!(
|
|
88
142
|
name,
|
|
@@ -99,16 +153,29 @@ module Hecks
|
|
|
99
153
|
)
|
|
100
154
|
end
|
|
101
155
|
|
|
102
|
-
#
|
|
156
|
+
# Upserts one id's cached value from the state being written, leaving the
|
|
157
|
+
# row alone when it already carries an equal or newer ordinal.
|
|
158
|
+
#
|
|
159
|
+
# **The live-write side** — called from `append`, inside the same
|
|
103
160
|
# transaction as the journal insert and the head-snapshot
|
|
104
161
|
# upsert, for every field this aggregate has a cache table for.
|
|
105
|
-
# `state_json` is the entry's
|
|
162
|
+
# `state_json` is the entry's own new state (already the thing
|
|
106
163
|
# `append` is about to write) — bound as a literal jsonb value
|
|
107
164
|
# and aliased `state`, so `value_expression` (built to read a
|
|
108
165
|
# column literally named `state`) evaluates identically here and
|
|
109
166
|
# in every backfill/query-time use, with no separate Ruby-side
|
|
110
167
|
# re-implementation of "how to pick a value-object's member" to
|
|
111
168
|
# keep in sync.
|
|
169
|
+
#
|
|
170
|
+
# @param name [String] unquoted cache table name, from `field_cache`
|
|
171
|
+
# @param id [String] the aggregate id the entry belongs to
|
|
172
|
+
# @param ordinal [String, Integer] the journal ordinal the entry was written
|
|
173
|
+
# at; `append` passes the decimal text Postgres returned from its INSERT
|
|
174
|
+
# @param state_json [String] the entry's encoded state, as JSON text
|
|
175
|
+
# @param value_expression [String] SQL expression that extracts the field's
|
|
176
|
+
# value as text from a jsonb column named `state`
|
|
177
|
+
# @return [void]
|
|
178
|
+
# @raise [PG::Error] if Postgres refuses the upsert
|
|
112
179
|
def upsert_field_cache_row!(name, id, ordinal, state_json, value_expression)
|
|
113
180
|
@db.exec_params(<<~SQL, [id, ordinal, state_json])
|
|
114
181
|
INSERT INTO #{quote(name)} (id, ordinal, value)
|
|
@@ -119,6 +186,14 @@ module Hecks
|
|
|
119
186
|
SQL
|
|
120
187
|
end
|
|
121
188
|
|
|
189
|
+
# Removes a deleted id's row from one cache table, so a cached-field query
|
|
190
|
+
# stops offering that id. Called from `append` for a delete entry, inside the
|
|
191
|
+
# same transaction as the journal insert and the head-snapshot tombstone.
|
|
192
|
+
#
|
|
193
|
+
# @param name [String] unquoted cache table name, from `field_cache`
|
|
194
|
+
# @param id [String] the aggregate id whose row is removed
|
|
195
|
+
# @return [void]
|
|
196
|
+
# @raise [PG::Error] if Postgres refuses the delete
|
|
122
197
|
def delete_field_cache_row!(name, id)
|
|
123
198
|
@db.exec_params("DELETE FROM #{quote(name)} WHERE id = $1", [id])
|
|
124
199
|
end
|
|
@@ -126,19 +201,19 @@ module Hecks
|
|
|
126
201
|
private
|
|
127
202
|
|
|
128
203
|
# The reduced (id, ordinal, state) source a field cache backfills
|
|
129
|
-
# from —
|
|
130
|
-
# own source): a field cache reflects the
|
|
204
|
+
# from — not the raw journal (unlike `backfill_head_snapshot!`'s
|
|
205
|
+
# own source): a field cache reflects the current head value,
|
|
131
206
|
# which for era > 1 can come from either this era's own live
|
|
132
|
-
# writes
|
|
207
|
+
# writes or an untouched-this-era id whose value still comes
|
|
133
208
|
# from the translated ancestor tail. Era 1 has no ancestor tail
|
|
134
|
-
# (the snapshot table
|
|
135
|
-
#
|
|
209
|
+
# (the snapshot table is the head, verbatim); era N reduces the
|
|
210
|
+
# same two sources `compile_head!`'s own final view definition
|
|
136
211
|
# unions (head_compiler.rb) — this is deliberately the identical
|
|
137
212
|
# shape, ordinal kept in the SELECT list instead of dropped,
|
|
138
|
-
# because a backfilled cache row needs a
|
|
213
|
+
# because a backfilled cache row needs a real ordinal to guard
|
|
139
214
|
# against a concurrent live write the same way every other
|
|
140
215
|
# upsert in this adapter already does. Ordinals are safe to
|
|
141
|
-
# compare across that union because they come from
|
|
216
|
+
# compare across that union because they come from one spanning
|
|
142
217
|
# sequence per domain (see lineage.rb's own header comment) —
|
|
143
218
|
# an ancestor-era ordinal is always numerically smaller than any
|
|
144
219
|
# current-era one, so the ordinary `ordinal <` guard already
|
|
@@ -157,7 +232,7 @@ module Hecks
|
|
|
157
232
|
"SELECT ordinal, aggregate_id AS id, state FROM #{quote(view)} WHERE operation = 'save'"
|
|
158
233
|
else
|
|
159
234
|
# No compiled ancestor matview yet (e.g. this era was just
|
|
160
|
-
# minted and compile_head! hasn't run for
|
|
235
|
+
# minted and compile_head! hasn't run for this aggregate) —
|
|
161
236
|
# the live snapshot side alone is the whole truth so far.
|
|
162
237
|
"SELECT NULL::bigint AS ordinal, NULL::text AS id, NULL::jsonb AS state WHERE FALSE"
|
|
163
238
|
end
|