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
|
@@ -10,9 +10,19 @@ module Hecks
|
|
|
10
10
|
# loading, and the smaller checks are also called piecemeal by the
|
|
11
11
|
# repository factory.
|
|
12
12
|
module Verification
|
|
13
|
+
# Runs the whole wiring gate against this registry's loaded bluebooks,
|
|
14
|
+
# hexagons, ports and adapters.
|
|
15
|
+
#
|
|
16
|
+
# @return [Runtime::Registry] self
|
|
17
|
+
# @raise [Runtime::WiringError] if a bind names an undeclared aggregate, an
|
|
18
|
+
# adapter cannot satisfy its port's verb or declared `answers`, a world
|
|
19
|
+
# setting names a field its adapter does not declare, the default adapter
|
|
20
|
+
# is unusable, or a command declares a role with no authorization provider
|
|
21
|
+
# attached
|
|
13
22
|
def verify!
|
|
14
23
|
verify_default_adapter!
|
|
15
24
|
verify_singleton_port_answers!
|
|
25
|
+
refuse_cross_package_bluebook_merge!
|
|
16
26
|
|
|
17
27
|
@hecksagons.each_value do |hexagon|
|
|
18
28
|
refuse_ungoverned_roles!(hexagon)
|
|
@@ -21,11 +31,11 @@ module Hecks
|
|
|
21
31
|
# A domain-level default (§0) — `persisted_by "Heki"` bare,
|
|
22
32
|
# applying to whichever aggregates don't override it — names
|
|
23
33
|
# no aggregate of its own, so there's nothing to look up in
|
|
24
|
-
# the bluebook for
|
|
34
|
+
# the bluebook for this row specifically. Still validate its
|
|
25
35
|
# own adapter/verb shape (the same reason
|
|
26
36
|
# `verify_default_adapter!` checks the framework-wide
|
|
27
37
|
# default the same way, aggregate-less). Coverage of real
|
|
28
|
-
# aggregates that only resolve
|
|
38
|
+
# aggregates that only resolve through this default comes
|
|
29
39
|
# from their own dispatch-time `BindingPolicy.resolve` —
|
|
30
40
|
# deliberately not required to be exhaustive here, the same
|
|
31
41
|
# leniency this method already extended to any aggregate
|
|
@@ -50,6 +60,13 @@ module Hecks
|
|
|
50
60
|
self
|
|
51
61
|
end
|
|
52
62
|
|
|
63
|
+
# Checks that the framework-wide default persistence adapter (used by any
|
|
64
|
+
# aggregate left out of an explicit bind list) is itself wired correctly.
|
|
65
|
+
#
|
|
66
|
+
# @return [Runtime::Registry] self
|
|
67
|
+
# @raise [Runtime::WiringError] if the default adapter cannot satisfy the
|
|
68
|
+
# persistence port's verb, is missing a declared `answers` method, or has
|
|
69
|
+
# no Ruby implementation
|
|
53
70
|
def verify_default_adapter!
|
|
54
71
|
name = Ports::Persistence::DEFAULT_ADAPTER
|
|
55
72
|
|
|
@@ -68,6 +85,14 @@ module Hecks
|
|
|
68
85
|
"aggregate with no bind could not be given one: #{e.message}"
|
|
69
86
|
end
|
|
70
87
|
|
|
88
|
+
# Checks that `bind`'s adapter implements the port it names and satisfies
|
|
89
|
+
# the verb the bind declares.
|
|
90
|
+
#
|
|
91
|
+
# @param bind [Bluebook::Bind] the bind to check
|
|
92
|
+
# @return [void]
|
|
93
|
+
# @raise [Runtime::WiringError] if `bind`'s adapter is unknown, declares an
|
|
94
|
+
# unknown port, is missing a declared `answers` method, or cannot satisfy
|
|
95
|
+
# `bind`'s own verb
|
|
71
96
|
def check_verb(bind)
|
|
72
97
|
port = port_for(bind)
|
|
73
98
|
check_answers(port, bind.adapter)
|
|
@@ -78,13 +103,20 @@ module Hecks
|
|
|
78
103
|
"and cannot satisfy #{bind.verb}"
|
|
79
104
|
end
|
|
80
105
|
|
|
81
|
-
#
|
|
82
|
-
#
|
|
106
|
+
# The method contract a `.port` file's `verb`/`signal` never
|
|
107
|
+
# carried — an adapter can name the right port, satisfy the right
|
|
83
108
|
# verb, and admit every `.world` setting `check_settings` checks,
|
|
84
109
|
# and still be missing the one method a live dispatch will
|
|
85
110
|
# actually call. `answers` is optional per port (an empty list is
|
|
86
111
|
# today's pre-existing behavior, unchecked), so this only ever
|
|
87
112
|
# tightens a port that opted in.
|
|
113
|
+
#
|
|
114
|
+
# @param port [Bluebook::Port] the port whose declared `answers` methods
|
|
115
|
+
# `adapter_name` must respond to
|
|
116
|
+
# @param adapter_name [String] the adapter's declared name to check
|
|
117
|
+
# @return [void]
|
|
118
|
+
# @raise [Runtime::WiringError] if `adapter_name` has no Ruby implementation,
|
|
119
|
+
# or its implementation does not respond to one of `port.answers`
|
|
88
120
|
def check_answers(port, adapter_name)
|
|
89
121
|
answers = Array(port.answers)
|
|
90
122
|
return if answers.empty?
|
|
@@ -99,7 +131,7 @@ module Hecks
|
|
|
99
131
|
"#{answers.map(&:inspect).join(', ')}"
|
|
100
132
|
end
|
|
101
133
|
|
|
102
|
-
#
|
|
134
|
+
# **The nine singleton ports' own gap** — `persistence`, `projection`
|
|
103
135
|
# and `loading` are per-aggregate bindings, checked above through
|
|
104
136
|
# every real `bind` a hexagon declares; a singleton port
|
|
105
137
|
# (`clock`, `authorization`, …) is never bound to an aggregate at
|
|
@@ -108,12 +140,18 @@ module Hecks
|
|
|
108
140
|
# already refuses zero or multiple implementations, live, at
|
|
109
141
|
# first dispatch — that stays exactly as-is here (0 or 2+ is
|
|
110
142
|
# ambiguity, not a method-contract question, and asserting every
|
|
111
|
-
# declared port
|
|
143
|
+
# declared port must have exactly one adapter would wrongly
|
|
112
144
|
# refuse a boot that simply never wires a port it doesn't use).
|
|
113
|
-
# This only ever tightens the
|
|
145
|
+
# This only ever tightens the one case those checks don't cover:
|
|
114
146
|
# exactly one adapter, wired, missing a method `answers` names.
|
|
115
147
|
PER_AGGREGATE_PORTS = %w[persistence projection loading].freeze
|
|
116
148
|
|
|
149
|
+
# Checks every singleton port (not per-aggregate-bound) with exactly one
|
|
150
|
+
# wired adapter against its own declared `answers` methods.
|
|
151
|
+
#
|
|
152
|
+
# @return [Runtime::Registry] self
|
|
153
|
+
# @raise [Runtime::WiringError] if a singleton port's one wired adapter is
|
|
154
|
+
# missing one of its declared `answers` methods
|
|
117
155
|
def verify_singleton_port_answers!
|
|
118
156
|
@ports.each_value do |port|
|
|
119
157
|
next if PER_AGGREGATE_PORTS.include?(port.name)
|
|
@@ -127,6 +165,16 @@ module Hecks
|
|
|
127
165
|
self
|
|
128
166
|
end
|
|
129
167
|
|
|
168
|
+
# Checks that every setting `settings` declares (besides `:adapter`) is a
|
|
169
|
+
# field `bind`'s adapter actually admits.
|
|
170
|
+
#
|
|
171
|
+
# @param bind [Bluebook::Bind] the bind naming the adapter to check against;
|
|
172
|
+
# a no-op if its adapter is unknown
|
|
173
|
+
# @param settings [Hash{Symbol => Object}] the world's declared settings for
|
|
174
|
+
# this bind
|
|
175
|
+
# @return [void]
|
|
176
|
+
# @raise [Runtime::WiringError] if `settings` declares a field `bind`'s
|
|
177
|
+
# adapter does not declare
|
|
130
178
|
def check_settings(bind, settings)
|
|
131
179
|
adapter = @adapters[bind.adapter]
|
|
132
180
|
return unless adapter
|
|
@@ -141,6 +189,12 @@ module Hecks
|
|
|
141
189
|
"Add the field to the adapter, or remove it from the world."
|
|
142
190
|
end
|
|
143
191
|
|
|
192
|
+
# Finds the port `bind`'s adapter declares.
|
|
193
|
+
#
|
|
194
|
+
# @param bind [Bluebook::Bind] the bind naming the adapter to look up
|
|
195
|
+
# @return [Bluebook::Port] the port `bind`'s adapter declares
|
|
196
|
+
# @raise [Runtime::WiringError] if `bind` names an unknown adapter, or one
|
|
197
|
+
# declaring an unknown port
|
|
144
198
|
def port_for(bind)
|
|
145
199
|
adapter = @adapters[bind.adapter]
|
|
146
200
|
raise WiringError, "unknown adapter #{bind.adapter.inspect}" unless adapter
|
|
@@ -149,6 +203,12 @@ module Hecks
|
|
|
149
203
|
raise(WiringError, "adapter #{bind.adapter} declares unknown port #{adapter.port.inspect}")
|
|
150
204
|
end
|
|
151
205
|
|
|
206
|
+
# Finds the Ruby module implementing the adapter declared `name`.
|
|
207
|
+
#
|
|
208
|
+
# @param name [String] the adapter's declared name, such as `"PostgresEra"`
|
|
209
|
+
# @return [Module] the adapter module or class under `Hecks::Adapters`
|
|
210
|
+
# @raise [Runtime::WiringError] if no Ruby implementation named `name` exists
|
|
211
|
+
# under `Hecks::Adapters`
|
|
152
212
|
def adapter_class(name)
|
|
153
213
|
Adapters.const_get(name)
|
|
154
214
|
rescue NameError
|
|
@@ -158,34 +218,35 @@ module Hecks
|
|
|
158
218
|
|
|
159
219
|
private
|
|
160
220
|
|
|
161
|
-
# `role`
|
|
162
|
-
#
|
|
221
|
+
# `role` is real access control only when governance can check it
|
|
222
|
+
# against something — a command that declares a role but whose
|
|
163
223
|
# domain never attaches Governance would leave that role forever
|
|
164
224
|
# unchecked, exactly the defect ADR 0025 §9 names ("role gates
|
|
165
225
|
# access control by exact string equality ... Governance ...
|
|
166
|
-
# connected to none of it"). Checked here, at `verify!` —
|
|
167
|
-
# and
|
|
168
|
-
# build time (Bluebook::DSL::HecksagonBuilder#build),
|
|
169
|
-
# the moment a domain
|
|
226
|
+
# connected to none of it"). Checked here, at `verify!` — recovered
|
|
227
|
+
# and moved, not new: running this per-block, at hecksagon
|
|
228
|
+
# build time (Bluebook::DSL::HecksagonBuilder#build), breaks
|
|
229
|
+
# the moment a domain is split across multiple hecksagon
|
|
170
230
|
# blocks (base + an `environments/<name>.hecksagon` overlay,
|
|
171
231
|
# Runtime::Loader.boot's `environment:` — see its own comment for
|
|
172
232
|
# the recovery provenance): every block but the one declaring
|
|
173
233
|
# `uses_framework "Governance"` would be refused there, even
|
|
174
234
|
# though `Registry#add_hecksagon` merges every block for a domain
|
|
175
|
-
# into
|
|
176
|
-
# Checking the
|
|
235
|
+
# into one Hecksagon before anything ever dispatches against it.
|
|
236
|
+
# Checking the merged result once, here, after every file for
|
|
177
237
|
# this domain has loaded, is both more permissive (no need to
|
|
178
238
|
# repeat `uses_framework` in every file) and strictly more
|
|
179
239
|
# correct (a check against an incomplete, not-yet-merged
|
|
180
240
|
# hecksagon can never see the real final shape).
|
|
181
241
|
#
|
|
182
|
-
#
|
|
183
|
-
#
|
|
184
|
-
#
|
|
185
|
-
#
|
|
242
|
+
# A provider is recognised by its declaration, not its name —
|
|
243
|
+
# `authorization_provider_for` answers for the domain's own
|
|
244
|
+
# chapter too, so Governance (which declares `provides
|
|
245
|
+
# "authorization"`) passes here because of what it declares, and
|
|
246
|
+
# the same rule `CommandRules::Authorization#governance_attached?`
|
|
247
|
+
# applies at dispatch time.
|
|
186
248
|
def refuse_ungoverned_roles!(hexagon)
|
|
187
|
-
return if hexagon.domain
|
|
188
|
-
return if hexagon.framework_members.include?("Governance")
|
|
249
|
+
return if authorization_provider_for(hexagon.domain)
|
|
189
250
|
|
|
190
251
|
bluebook_ir = bluebook(hexagon.domain)
|
|
191
252
|
return unless bluebook_ir
|
|
@@ -195,18 +256,82 @@ module Hecks
|
|
|
195
256
|
|
|
196
257
|
raise WiringError,
|
|
197
258
|
"#{offender.hecks_fqn} declares role #{offender.role.inspect}, but " \
|
|
198
|
-
"#{hexagon.domain}'s hecksagon never
|
|
199
|
-
"real access control once
|
|
200
|
-
"it is silent decoration, the exact defect this refusal exists to catch"
|
|
259
|
+
"#{hexagon.domain}'s hecksagon never #{authorization_attachment_hint} — role is only " \
|
|
260
|
+
"real access control once an authorization provider is attached to check it against; " \
|
|
261
|
+
"without that it is silent decoration, the exact defect this refusal exists to catch"
|
|
201
262
|
end
|
|
202
263
|
|
|
203
|
-
#
|
|
264
|
+
# The suggestion, derived from whichever framework members actually
|
|
265
|
+
# declare `provides "authorization"` — never a hardcoded name.
|
|
266
|
+
def authorization_attachment_hint
|
|
267
|
+
providers = Framework.providers_of(Bluebook::Capabilities::AUTHORIZATION)
|
|
268
|
+
return "attaches a chapter that provides \"authorization\" (no framework member declares one)" if providers.empty?
|
|
269
|
+
|
|
270
|
+
providers.map { |name| "uses_framework #{name.inspect}" }.join(" or ")
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# Every command this domain declares, an aggregate's own and every
|
|
204
274
|
# entity nested inside one — the same reach `refuse_role_mismatch`
|
|
205
275
|
# itself needs at dispatch time, just walked ahead of time here.
|
|
206
276
|
def commands_in(bluebook_ir)
|
|
207
277
|
bluebook_ir.aggregates.flat_map { |aggregate| aggregate.commands + aggregate.entities.flat_map(&:commands) }
|
|
208
278
|
end
|
|
209
279
|
|
|
280
|
+
# TWO UNRELATED PACKAGES, ONE CHAPTER NAME BY COINCIDENCE — the
|
|
281
|
+
# real risk `Registry#bluebook_sources` exists to catch (found
|
|
282
|
+
# live: a stale `vendor/hecksagain` fork's own copy of Governance/
|
|
283
|
+
# Identity/Deploy, still reachable on 4 consuming apps' own load
|
|
284
|
+
# paths alongside the real gem). `BluebookBuilder.build`'s own
|
|
285
|
+
# accumulation (several files declaring the SAME chapter name ON
|
|
286
|
+
# PURPOSE — `lib/hecks/language/bluebook/*.bluebook` all open
|
|
287
|
+
# `Hecks.bluebook "Bluebook"`) is never touched here — that merge
|
|
288
|
+
# stays unconditional, checked only AFTER every file has loaded,
|
|
289
|
+
# the same "check the merged final result once" timing
|
|
290
|
+
# `refuse_ungoverned_roles!` already uses and for the same reason
|
|
291
|
+
# (a check against an incomplete load can never see the real
|
|
292
|
+
# shape). What distinguishes intentional accumulation from
|
|
293
|
+
# coincidence is PACKAGE ROOT, not file identity: files a real
|
|
294
|
+
# gemspec or a `vendor/` boundary already treats as one unit are
|
|
295
|
+
# expected to share a name; files from two DIFFERENT roots never
|
|
296
|
+
# legitimately do.
|
|
297
|
+
def refuse_cross_package_bluebook_merge!
|
|
298
|
+
@bluebook_sources.each do |name, paths|
|
|
299
|
+
roots = paths.map { |path| package_root_for(path) }.uniq
|
|
300
|
+
next if roots.size <= 1
|
|
301
|
+
|
|
302
|
+
raise WiringError,
|
|
303
|
+
"#{name.inspect} is declared by more than one package: #{roots.join(' and ')} — " \
|
|
304
|
+
"these are two unrelated sources sharing a chapter name by coincidence, not one " \
|
|
305
|
+
"domain split across files, and merging their declarations into one chapter is " \
|
|
306
|
+
"almost certainly a stale/vendored copy left on the load path (paths: " \
|
|
307
|
+
"#{paths.join(', ')})"
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
# THE NEAREST BOUNDARY A PATH ALREADY BELONGS TO — a real
|
|
312
|
+
# gemspec (this IS a package, whatever depends on it or vendors
|
|
313
|
+
# it), or a bare `vendor/` path component, treated as its OWN
|
|
314
|
+
# root regardless of what gemspec might sit above it: vendored
|
|
315
|
+
# code should never be considered "the same package" as whatever
|
|
316
|
+
# it's vendored into, even when nothing else marks the boundary.
|
|
317
|
+
# Neither found, the path's own directory is the root — two
|
|
318
|
+
# files with no closer marker only "belong together" if they are
|
|
319
|
+
# literally the same file.
|
|
320
|
+
def package_root_for(path)
|
|
321
|
+
return path.to_s if path.nil?
|
|
322
|
+
|
|
323
|
+
dir = File.dirname(File.expand_path(path))
|
|
324
|
+
loop do
|
|
325
|
+
return "vendor:#{dir}" if File.basename(dir) == "vendor"
|
|
326
|
+
return dir if Dir.glob(File.join(dir, "*.gemspec")).any?
|
|
327
|
+
|
|
328
|
+
parent = File.dirname(dir)
|
|
329
|
+
return dir if parent == dir
|
|
330
|
+
|
|
331
|
+
dir = parent
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
|
|
210
335
|
# A domain that declares a `process_manager` but whose
|
|
211
336
|
# `saga_persistence` resolves to `NULL_SAGA_STORE` (no anchor
|
|
212
337
|
# aggregate, a RemoteRuntime-shaped adapter, an adapter that
|
|
@@ -220,7 +345,7 @@ module Hecks
|
|
|
220
345
|
# 0025 named for an unchecked `role`, here applied to saga
|
|
221
346
|
# durability instead.
|
|
222
347
|
#
|
|
223
|
-
# A
|
|
348
|
+
# A warning, not a refusal — unlike `refuse_ungoverned_roles!`,
|
|
224
349
|
# running sagas on a store with no `save_saga` is legitimate on
|
|
225
350
|
# purpose in a fast in-memory test/dev boot (this project's own
|
|
226
351
|
# `saga_durability_spec.rb` boots a process manager on `Memory`
|
|
@@ -228,13 +353,13 @@ module Hecks
|
|
|
228
353
|
# refusing the boot outright would break a choice an author made
|
|
229
354
|
# deliberately. What a deploy needs is for the gap to be loud and
|
|
230
355
|
# undeniable, not for local dev/test to become impossible.
|
|
231
|
-
#
|
|
356
|
+
# The outbox's twin of `warn_undurable_sagas!` — a domain that
|
|
232
357
|
# declares anything a commit could owe a reaction to (a policy
|
|
233
358
|
# listening to one of its events, or a process manager) but is
|
|
234
359
|
# bound to an adapter with no outbox (`AppendOnly#outbox?`) gets
|
|
235
360
|
# reactions the pre-outbox way: run inline, lost on a crash
|
|
236
361
|
# between commit and reaction. A warning, not a refusal, for the
|
|
237
|
-
# reason `warn_undurable_sagas!` gives — and Memory
|
|
362
|
+
# reason `warn_undurable_sagas!` gives — and Memory has an outbox
|
|
238
363
|
# (in-process, like everything else it holds), so a dev/test
|
|
239
364
|
# boot stays quiet; this speaks up for the file/remote adapters
|
|
240
365
|
# that persist state durably but hand reactions to nothing.
|