hecks 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/hecks/adapters/driven/claude_code.rb +7 -7
- data/lib/hecks/adapters/driven/d1.rb +187 -23
- data/lib/hecks/adapters/driven/folder.rb +10 -10
- data/lib/hecks/adapters/driven/google_authentication.rb +8 -8
- data/lib/hecks/adapters/driven/governance_authorization.rb +31 -13
- data/lib/hecks/adapters/driven/heki/journal.rb +5 -4
- data/lib/hecks/adapters/driven/heki/saga_store.rb +5 -5
- data/lib/hecks/adapters/driven/heki.rb +13 -7
- data/lib/hecks/adapters/driven/identity_registry.rb +2 -2
- data/lib/hecks/adapters/driven/in_memory_ordering.rb +3 -3
- data/lib/hecks/adapters/driven/lambda/client.rb +34 -9
- data/lib/hecks/adapters/driven/lambda.rb +39 -33
- data/lib/hecks/adapters/driven/local_storage.rb +17 -10
- data/lib/hecks/adapters/driven/memory.rb +205 -9
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +1 -1
- data/lib/hecks/adapters/driven/postgres/codec.rb +27 -11
- data/lib/hecks/adapters/driven/postgres/outbox.rb +40 -2
- data/lib/hecks/adapters/driven/postgres/reconnect.rb +23 -7
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +14 -14
- data/lib/hecks/adapters/driven/postgres.rb +175 -28
- data/lib/hecks/adapters/driven/prism.rb +4 -4
- data/lib/hecks/adapters/driven/sql_query_builder.rb +34 -22
- data/lib/hecks/adapters/driven/sqlite/codec.rb +38 -10
- data/lib/hecks/adapters/driven/sqlite/projection.rb +60 -32
- data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +12 -12
- data/lib/hecks/adapters/driven/sqlite.rb +181 -21
- data/lib/hecks/adapters/driven.rb +4 -4
- data/lib/hecks/adapters/driving/github_webhook.rb +18 -18
- data/lib/hecks/behaviors/dsl.rb +2 -2
- data/lib/hecks/behaviors/expectations.rb +23 -23
- data/lib/hecks/behaviors/ir.rb +1 -1
- data/lib/hecks/behaviors/rspec.rb +1 -1
- data/lib/hecks/behaviors/runner.rb +2 -2
- data/lib/hecks/behaviors.rb +1 -1
- data/lib/hecks/bluebook/aggregate.rb +13 -13
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +10 -10
- data/lib/hecks/bluebook/assembly/build.rb +1 -1
- data/lib/hecks/bluebook/assembly/contract.rb +39 -16
- data/lib/hecks/bluebook/assembly/contracts.rb +40 -38
- data/lib/hecks/bluebook/assembly/marks.rb +18 -18
- data/lib/hecks/bluebook/assembly/specializer.rb +19 -21
- data/lib/hecks/bluebook/assembly.rb +9 -9
- data/lib/hecks/bluebook/attribute.rb +9 -9
- data/lib/hecks/bluebook/behaviour/aggregate.rb +11 -11
- data/lib/hecks/bluebook/behaviour/attribute.rb +5 -5
- data/lib/hecks/bluebook/behaviour/chapter.rb +23 -5
- data/lib/hecks/bluebook/behaviour/command.rb +23 -23
- data/lib/hecks/bluebook/behaviour/domain_port.rb +7 -7
- data/lib/hecks/bluebook/behaviour/entity.rb +8 -8
- data/lib/hecks/bluebook/behaviour/hexagon.rb +4 -4
- data/lib/hecks/bluebook/behaviour/lifecycle.rb +5 -5
- data/lib/hecks/bluebook/behaviour/policy.rb +12 -12
- data/lib/hecks/bluebook/behaviour/process_manager.rb +7 -7
- data/lib/hecks/bluebook/behaviour/query.rb +1 -1
- data/lib/hecks/bluebook/behaviour/read_model.rb +8 -8
- data/lib/hecks/bluebook/behaviour/traits.rb +12 -12
- data/lib/hecks/bluebook/behaviour/value_object.rb +6 -6
- data/lib/hecks/bluebook/capabilities.rb +27 -0
- data/lib/hecks/bluebook/chapter.rb +28 -9
- data/lib/hecks/bluebook/command.rb +12 -12
- data/lib/hecks/bluebook/domain_port.rb +9 -9
- data/lib/hecks/bluebook/dsl/adapter_builder.rb +24 -0
- data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +49 -49
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +96 -96
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +41 -41
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +22 -2
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +111 -74
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +48 -30
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +116 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +103 -103
- data/lib/hecks/bluebook/dsl/const_shim.rb +46 -15
- data/lib/hecks/bluebook/dsl/domain_port_builder.rb +90 -25
- data/lib/hecks/bluebook/dsl/entity_builder.rb +56 -56
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +148 -132
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +89 -30
- data/lib/hecks/bluebook/dsl/identity_declaration.rb +17 -17
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +27 -4
- data/lib/hecks/bluebook/dsl/policy_builder.rb +30 -21
- data/lib/hecks/bluebook/dsl/port_builder.rb +38 -7
- data/lib/hecks/bluebook/dsl/port_operation_builder.rb +56 -22
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +35 -35
- data/lib/hecks/bluebook/dsl/query_builder.rb +5 -5
- data/lib/hecks/bluebook/dsl/read_model_builder.rb +34 -34
- data/lib/hecks/bluebook/dsl/rule_reference.rb +41 -39
- data/lib/hecks/bluebook/dsl/translation_builder.rb +9 -9
- data/lib/hecks/bluebook/dsl/value_object_builder.rb +16 -16
- data/lib/hecks/bluebook/dsl/word_gate.rb +59 -53
- data/lib/hecks/bluebook/dsl/world_builder.rb +51 -8
- data/lib/hecks/bluebook/entity.rb +11 -11
- data/lib/hecks/bluebook/expression/ast_json.rb +20 -20
- data/lib/hecks/bluebook/expression/ast_reader.rb +3 -3
- data/lib/hecks/bluebook/expression/canonical_form.rb +9 -9
- data/lib/hecks/bluebook/expression/evaluator.rb +18 -18
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +18 -18
- data/lib/hecks/bluebook/expression/resolver.rb +60 -62
- data/lib/hecks/bluebook/hexagon.rb +1 -1
- data/lib/hecks/bluebook/lifecycle.rb +1 -1
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -1
- data/lib/hecks/bluebook/meta_validator/judge.rb +101 -87
- data/lib/hecks/bluebook/meta_validator/plan.rb +39 -39
- data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -2
- data/lib/hecks/bluebook/meta_validator/readings.rb +43 -43
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +44 -37
- data/lib/hecks/bluebook/meta_validator/shapes.rb +25 -21
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +145 -31
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +6 -6
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +5 -5
- data/lib/hecks/bluebook/meta_validator.rb +70 -70
- data/lib/hecks/bluebook/model_check.rb +170 -84
- data/lib/hecks/bluebook/pattern_subset.rb +9 -9
- data/lib/hecks/bluebook/policy.rb +15 -13
- data/lib/hecks/bluebook/process_manager.rb +14 -14
- data/lib/hecks/bluebook/project_register.rb +6 -6
- data/lib/hecks/bluebook/query.rb +4 -4
- data/lib/hecks/bluebook/read_model.rb +14 -14
- data/lib/hecks/bluebook/reference.rb +8 -8
- data/lib/hecks/bluebook/smoke_test.rb +19 -19
- data/lib/hecks/bluebook/synthesizer.rb +12 -12
- data/lib/hecks/bluebook/translation.rb +4 -4
- data/lib/hecks/bluebook/value_object.rb +6 -6
- data/lib/hecks/bluebook.rb +2 -2
- data/lib/hecks/codemod/legacy_dispatch_args.rb +299 -0
- data/lib/hecks/codemod/legacy_dispatch_recorder.rb +186 -0
- data/lib/hecks/codemod.rb +36 -35
- data/lib/hecks/construct.rb +6 -6
- data/lib/hecks/corpus.rb +317 -0
- data/lib/hecks/deprecation.rb +95 -0
- data/lib/hecks/doc/reference.rb +19 -19
- data/lib/hecks/embryonaut_bluebook.rb +11 -11
- data/lib/hecks/facade/cli_door.rb +69 -10
- data/lib/hecks/facade/cli_runner.rb +105 -24
- data/lib/hecks/facade/command_request.rb +23 -0
- data/lib/hecks/facade/handle.rb +79 -32
- data/lib/hecks/facade/json_door.rb +106 -25
- data/lib/hecks/facade/surface/aggregate_door.rb +42 -27
- data/lib/hecks/facade/surface/chapter.rb +26 -17
- data/lib/hecks/facade/surface.rb +16 -3
- data/lib/hecks/facade.rb +15 -4
- data/lib/hecks/forms/app.rb +46 -30
- data/lib/hecks/forms/command_form_renderer.rb +70 -9
- data/lib/hecks/forms/field_renderer.rb +142 -6
- data/lib/hecks/forms/field_shape.rb +180 -19
- data/lib/hecks/forms/html.rb +51 -7
- data/lib/hecks/forms/index_renderer.rb +14 -2
- data/lib/hecks/forms/params.rb +120 -23
- data/lib/hecks/forms/port_argument.rb +2 -2
- data/lib/hecks/forms/query_form_renderer.rb +2 -2
- data/lib/hecks/forms/record_renderer.rb +2 -2
- data/lib/hecks/forms/record_table.rb +1 -1
- data/lib/hecks/forms/value_object_shape.rb +3 -3
- data/lib/hecks/forms.rb +24 -4
- data/lib/hecks/fqn.rb +1 -1
- data/lib/hecks/framework/bluebook/governance.bluebook +9 -0
- data/lib/hecks/framework.rb +48 -17
- data/lib/hecks/freezer.rb +11 -11
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +90 -90
- data/lib/hecks/fuzzing/combination_miner.rb +119 -0
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +140 -45
- data/lib/hecks/fuzzing/coverage_campaign.rb +118 -0
- data/lib/hecks/fuzzing/differential.rb +158 -0
- data/lib/hecks/fuzzing/domain_generator.rb +694 -0
- data/lib/hecks/fuzzing/era_boundary.rb +37 -18
- data/lib/hecks/fuzzing/form_census.rb +35 -20
- data/lib/hecks/fuzzing/generated_domain_check.rb +95 -0
- data/lib/hecks/fuzzing/invalid_value_generator.rb +6 -6
- data/lib/hecks/fuzzing/isolated_boot.rb +62 -62
- data/lib/hecks/fuzzing/nondeterministic.rb +67 -0
- data/lib/hecks/fuzzing/persistence_parity.rb +19 -21
- data/lib/hecks/fuzzing/properties/corrections.rb +9 -9
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +154 -49
- data/lib/hecks/fuzzing/properties/guards.rb +42 -42
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +32 -32
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +22 -35
- data/lib/hecks/fuzzing/properties/outbox.rb +24 -24
- data/lib/hecks/fuzzing/properties/querying.rb +17 -17
- data/lib/hecks/fuzzing/properties.rb +64 -40
- data/lib/hecks/fuzzing/qa_settings.rb +152 -0
- data/lib/hecks/fuzzing/replay.rb +114 -114
- data/lib/hecks/fuzzing/rotation_priority.rb +10 -10
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +113 -0
- data/lib/hecks/fuzzing/self_consistency.rb +141 -112
- data/lib/hecks/fuzzing/sequence_generator/adversary.rb +35 -35
- 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 +58 -31
- data/lib/hecks/fuzzing/sequence_generator.rb +111 -23
- data/lib/hecks/fuzzing/shrinker.rb +197 -0
- data/lib/hecks/fuzzing/structural_skips.rb +23 -130
- data/lib/hecks/fuzzing/sweep_depth.rb +4 -4
- data/lib/hecks/fuzzing/target_capabilities.rb +49 -18
- data/lib/hecks/fuzzing/value_generator.rb +14 -14
- data/lib/hecks/fuzzing.rb +5 -0
- data/lib/hecks/grammar/evolve.rb +10 -10
- data/lib/hecks/grammar.rb +7 -7
- data/lib/hecks/ir.rb +13 -13
- data/lib/hecks/language/bluebook/bluebook.bluebook +41 -0
- data/lib/hecks/language/bluebook/policy.bluebook +11 -1
- data/lib/hecks/language/bluebook/vocabulary.bluebook +348 -13
- data/lib/hecks/language/oidc.json +5 -0
- data/lib/hecks/literal.rb +9 -9
- data/lib/hecks/naming.rb +25 -25
- data/lib/hecks/ports/access_control.rb +58 -2
- data/lib/hecks/ports/agent/answers.rb +83 -6
- data/lib/hecks/ports/agent.rb +119 -35
- data/lib/hecks/ports/authentication.rb +44 -4
- data/lib/hecks/ports/authorization.rb +53 -11
- data/lib/hecks/ports/clock.rb +42 -23
- data/lib/hecks/ports/extraction.rb +16 -0
- data/lib/hecks/ports/identity_assignment.rb +24 -2
- data/lib/hecks/ports/identity_generation.rb +17 -3
- data/lib/hecks/ports/identity_resolution.rb +18 -1
- data/lib/hecks/ports/loading.rb +4 -0
- data/lib/hecks/ports/persistence/append_only.rb +172 -8
- data/lib/hecks/ports/persistence/binding_policy.rb +34 -0
- data/lib/hecks/ports/persistence/codec_boundary.rb +178 -0
- data/lib/hecks/ports/persistence/execution.rb +4 -0
- data/lib/hecks/ports/persistence/null_saga_store.rb +12 -1
- data/lib/hecks/ports/persistence/plugin.rb +42 -4
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +218 -25
- data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +77 -9
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +81 -24
- data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +29 -18
- data/lib/hecks/ports/persistence/plugins/era/lineage.rb +144 -60
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +103 -8
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +98 -23
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +282 -109
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +63 -25
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +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 +28 -5
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +25 -12
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +129 -34
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +51 -6
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +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 +57 -4
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +25 -2
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +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 +42 -8
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +16 -1
- data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +36 -5
- data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +23 -3
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +18 -19
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +5 -5
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -2
- data/lib/hecks/ports/persistence/plugins/era.rb +12 -2
- data/lib/hecks/ports/persistence/remote_runtime.rb +9 -2
- data/lib/hecks/ports/persistence/repository_factory.rb +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 +3 -3
- data/lib/hecks/ports/query/ordering.rb +6 -6
- data/lib/hecks/ports/query.rb +35 -0
- data/lib/hecks/projections/bootstrap_table.rb +112 -0
- data/lib/hecks/projections/diagrams.rb +75 -75
- data/lib/hecks/projections/glossary/html.rb +3 -3
- data/lib/hecks/projections/glossary/markdown.rb +3 -3
- data/lib/hecks/projections/glossary/mermaid.rb +1 -1
- data/lib/hecks/projections/glossary/sections.rb +1 -1
- data/lib/hecks/projections/glossary/sentences.rb +5 -5
- data/lib/hecks/projections/glossary.rb +15 -15
- data/lib/hecks/projections/ir.rb +1 -1
- data/lib/hecks/projections/model/deviations.rb +18 -17
- data/lib/hecks/projections/model.rb +25 -21
- data/lib/hecks/projections/oidc.rb +7 -7
- data/lib/hecks/projections/parser_table.rb +5 -5
- data/lib/hecks/projections/reference.rb +3 -3
- data/lib/hecks/projections/rust_vocabulary.rb +443 -0
- data/lib/hecks/projections/shape.rb +2 -2
- data/lib/hecks/projections/statements.rb +11 -11
- data/lib/hecks/projections/vocabulary.rb +9 -9
- data/lib/hecks/projections.rb +5 -3
- data/lib/hecks/projector/cli_projector.rb +29 -29
- data/lib/hecks/projector/docs_projector.rb +13 -13
- data/lib/hecks/projector/exporter.rb +42 -21
- data/lib/hecks/projector/ir_projector.rb +1 -1
- data/lib/hecks/projector/narrate_projector.rb +11 -11
- data/lib/hecks/projector/target.rb +13 -13
- data/lib/hecks/projector.rb +15 -15
- data/lib/hecks/query_ir.rb +47 -47
- data/lib/hecks/query_specification/common/comparators.rb +19 -3
- data/lib/hecks/query_specification/common/comparison.rb +109 -27
- data/lib/hecks/query_specification/common/dsl.rb +65 -9
- data/lib/hecks/query_specification/common/null_policy.rb +57 -13
- data/lib/hecks/query_specification/common/null_semantics.rb +4 -0
- data/lib/hecks/query_specification/common/options.rb +25 -0
- data/lib/hecks/query_specification/field_path.rb +69 -15
- data/lib/hecks/query_specification/hop_path.rb +57 -20
- data/lib/hecks/query_specification/read_model/specification.rb +4 -0
- data/lib/hecks/rendering.rb +3 -3
- data/lib/hecks/router/namespace_installer.rb +3 -3
- data/lib/hecks/router.rb +1 -1
- data/lib/hecks/runtime/aggregate_lock.rb +11 -11
- data/lib/hecks/runtime/boot_gates.rb +3 -3
- data/lib/hecks/runtime/caller.rb +8 -8
- data/lib/hecks/runtime/capability_graph.rb +2 -2
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +22 -25
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +42 -63
- data/lib/hecks/runtime/command_interpreter.rb +159 -102
- data/lib/hecks/runtime/command_rules/admissibility.rb +69 -69
- data/lib/hecks/runtime/command_rules/arithmetic.rb +137 -91
- data/lib/hecks/runtime/command_rules/authorization.rb +38 -17
- data/lib/hecks/runtime/command_rules/emission.rb +18 -1
- data/lib/hecks/runtime/command_rules/references.rb +35 -35
- data/lib/hecks/runtime/command_rules.rb +3 -0
- data/lib/hecks/runtime/dependency_planning.rb +11 -11
- data/lib/hecks/runtime/dispatcher.rb +283 -90
- data/lib/hecks/runtime/entity_element.rb +151 -67
- data/lib/hecks/runtime/entity_interpreter.rb +108 -82
- data/lib/hecks/runtime/errors.rb +19 -19
- data/lib/hecks/runtime/event.rb +6 -6
- data/lib/hecks/runtime/identity.rb +22 -22
- data/lib/hecks/runtime/instance.rb +39 -14
- data/lib/hecks/runtime/interpreting.rb +12 -12
- data/lib/hecks/runtime/invocation.rb +276 -0
- data/lib/hecks/runtime/loader.rb +14 -14
- data/lib/hecks/runtime/outbox.rb +23 -23
- data/lib/hecks/runtime/policy_interpreter.rb +54 -54
- data/lib/hecks/runtime/port_operation_interpreter.rb +22 -19
- data/lib/hecks/runtime/query_interpreter.rb +55 -64
- data/lib/hecks/runtime/reaction_invocation.rb +20 -20
- data/lib/hecks/runtime/read_model_interpreter.rb +40 -40
- data/lib/hecks/runtime/rebuild_sweep.rb +4 -4
- data/lib/hecks/runtime/reference_hop.rb +6 -6
- data/lib/hecks/runtime/refusal_wording.rb +92 -115
- data/lib/hecks/runtime/registry/saga_persistence.rb +21 -21
- data/lib/hecks/runtime/registry/verification.rb +36 -26
- data/lib/hecks/runtime/registry.rb +45 -28
- data/lib/hecks/runtime/remote_dispatcher.rb +38 -23
- data/lib/hecks/runtime/routing.rb +10 -153
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +17 -17
- data/lib/hecks/runtime/saga_interpreter.rb +64 -64
- data/lib/hecks/runtime/saga_pending_dispatch.rb +12 -12
- data/lib/hecks/runtime/tenant_check.rb +9 -9
- data/lib/hecks/runtime/tenant_scope.rb +5 -5
- data/lib/hecks/runtime/value/admission.rb +75 -30
- data/lib/hecks/runtime/value/coercion.rb +318 -127
- data/lib/hecks/runtime/value/entity_list_coercion.rb +34 -34
- data/lib/hecks/runtime/value.rb +21 -21
- data/lib/hecks/runtime.rb +7 -7
- data/lib/hecks/storehouse.rb +64 -64
- data/lib/hecks/version.rb +3 -3
- data/lib/hecks/vocabulary.rb +205 -4
- data/lib/hecks.rb +13 -11
- data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +11 -11
- data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +14 -12
- data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +11 -11
- metadata +22 -2
|
@@ -3,8 +3,8 @@ require_relative "../ir"
|
|
|
3
3
|
|
|
4
4
|
module Hecks
|
|
5
5
|
module Bluebook
|
|
6
|
-
# `compensates` — a
|
|
7
|
-
# one, naming the command that undoes
|
|
6
|
+
# `compensates` — a second `DispatchSpec`, shape-identical to this
|
|
7
|
+
# one, naming the command that undoes this dispatch specifically
|
|
8
8
|
# (see `ProcessManagerBuilder::HandlerBuilder#dispatch_impl`'s own
|
|
9
9
|
# comment). `nil` for a dispatch with nothing to undo (a pure
|
|
10
10
|
# bookkeeping mark, or one whose own effect is superseded by a later
|
|
@@ -14,7 +14,7 @@ module Hecks
|
|
|
14
14
|
# used" bar would refuse a second level speculatively.
|
|
15
15
|
DispatchSpec = Struct.new(:command_name, :with_spec, :compensates, keyword_init: true) do
|
|
16
16
|
# A Struct already answers to_h; including the mixin puts the
|
|
17
|
-
#
|
|
17
|
+
# declared emission ahead of Struct's own in the ancestry, which
|
|
18
18
|
# is what makes the shape data rather than a method body.
|
|
19
19
|
include Hecks::IR
|
|
20
20
|
|
|
@@ -39,32 +39,32 @@ module Hecks
|
|
|
39
39
|
|
|
40
40
|
# The compensation half of a procedure, as its own thing.
|
|
41
41
|
#
|
|
42
|
-
# A
|
|
43
|
-
# next. A
|
|
42
|
+
# A process manager coordinates: legs, states, an opinion about who goes
|
|
43
|
+
# next. A saga undoes: what makes the world good again when a leg it
|
|
44
44
|
# dispatched is refused. Two concepts, and the industry slurs them into one
|
|
45
45
|
# word — so here they are two objects, and a procedure either has a saga or
|
|
46
46
|
# does not.
|
|
47
47
|
#
|
|
48
48
|
# `undoes` is the ordered list of commands the compensation sends — a
|
|
49
|
-
#
|
|
49
|
+
# static preview, declaration order (`Behaviour::ProcessManager#saga`),
|
|
50
50
|
# not one instance's own runtime history. Per-dispatch compensation
|
|
51
51
|
# (`compensates`, on the step it compensates for) moved most of what
|
|
52
52
|
# a saga undoes off this leg's own hand-written body and onto
|
|
53
53
|
# whichever forward dispatch each one undoes — this reads every
|
|
54
|
-
# declared `compensates` across the
|
|
54
|
+
# declared `compensates` across the whole saga first, then whatever
|
|
55
55
|
# this leg's own hand-written body still lists, for compensation
|
|
56
|
-
# that isn't expressible as "undo command X."
|
|
56
|
+
# that isn't expressible as "undo command X." which of a declared
|
|
57
57
|
# `compensates` actually fires for one instance, and in what order
|
|
58
58
|
# (newest-first, completed-legs-only), is `SagaInterpreter`'s own
|
|
59
59
|
# dynamic `completed_compensations` — a per-instance runtime fact
|
|
60
60
|
# this declaration-only object could never hold.
|
|
61
61
|
#
|
|
62
|
-
#
|
|
62
|
+
# **Naming collision, once flagged, now resolved** — `command`'s own
|
|
63
63
|
# `corrects event, reverses: true` (docs/implemented/decisions/0036-
|
|
64
64
|
# corrects-is-an-appended-fact-not-a-rewrite.md) already claimed
|
|
65
|
-
# `reverses` for a different meaning: auto-deriving a command's
|
|
66
|
-
# corrective mutation from a past
|
|
67
|
-
# compensating leg from a past
|
|
65
|
+
# `reverses` for a different meaning: auto-deriving a command's own
|
|
66
|
+
# corrective mutation from a past event, not a saga's own
|
|
67
|
+
# compensating leg from a past dispatch. This feature keeps
|
|
68
68
|
# `reverses` reserved for `corrects` and uses `compensates` for
|
|
69
69
|
# per-dispatch saga compensation instead — a deliberate choice, not
|
|
70
70
|
# an accidental collision.
|
|
@@ -78,10 +78,10 @@ module Hecks
|
|
|
78
78
|
# produced by `DSL::ProcessManagerBuilder` — its start/end events,
|
|
79
79
|
# correlation field, derived states, and handler rows. Its
|
|
80
80
|
# compensation half (`saga`, `Behaviour::ProcessManager#saga`) is
|
|
81
|
-
#
|
|
81
|
+
# derived from the handler answering `REFUSED`, below, not declared as
|
|
82
82
|
# its own construct.
|
|
83
83
|
class ProcessManager
|
|
84
|
-
# The
|
|
84
|
+
# The bluebook's name for this construct, asked the same way of a class
|
|
85
85
|
# that has crossed over and of an IR object that has not. Collapses into
|
|
86
86
|
# Construct when this one crosses.
|
|
87
87
|
# The trigger of a compensating leg. Not an event name — no aggregate
|
|
@@ -86,15 +86,15 @@ module Hecks
|
|
|
86
86
|
end
|
|
87
87
|
end
|
|
88
88
|
|
|
89
|
-
#
|
|
89
|
+
# The actual "more than one tenant" moment — Runtime::TenantCheck's
|
|
90
90
|
# own header names this table as the one place real multitenancy
|
|
91
|
-
# happens: the
|
|
92
|
-
# `persisted_by` binding) registering a
|
|
93
|
-
# different realm, into this
|
|
94
|
-
#
|
|
91
|
+
# happens: the same on-disk directory (one domain, one
|
|
92
|
+
# `persisted_by` binding) registering a second time, under a
|
|
93
|
+
# different realm, into this same shared route table. A directory's
|
|
94
|
+
# first registration is never refused here — nothing shares its
|
|
95
95
|
# data yet, so a plain single-tenant deployment on an ordinary
|
|
96
96
|
# adapter (Postgres, no schema story) still boots exactly as
|
|
97
|
-
# before. Only the
|
|
97
|
+
# before. Only the second (and any later) registration of that
|
|
98
98
|
# same directory is refused, and refused before this call adds its
|
|
99
99
|
# routes to the table — so a leaking tenant's requests never
|
|
100
100
|
# become reachable through `Router#resolve` in the first place.
|
data/lib/hecks/bluebook/query.rb
CHANGED
|
@@ -8,14 +8,14 @@ module Hecks
|
|
|
8
8
|
module Bluebook
|
|
9
9
|
def self.render_value(value) = Literal.render(value)
|
|
10
10
|
|
|
11
|
-
# A query — an
|
|
11
|
+
# A query — an ask, declared on an aggregate or on one of its entities.
|
|
12
12
|
#
|
|
13
|
-
# It crosses over as an
|
|
13
|
+
# It crosses over as an instance rather than a class, and the reason is worth
|
|
14
14
|
# stating because it is the boundary of the pattern. A query inherits its
|
|
15
15
|
# whole body from `QuerySpecification::Common::Options` — `wheres`,
|
|
16
16
|
# `order_by`, `limit`, `offset`, `cursor`,
|
|
17
17
|
# `authorization`, `null_semantics`, `inspection` — and those
|
|
18
|
-
# are
|
|
18
|
+
# are instance methods that the runtime and the SQLite adapter both read.
|
|
19
19
|
# Hoisting the declaration onto a metaclass would put the identity and the
|
|
20
20
|
# specification on opposite sides of the object.
|
|
21
21
|
#
|
|
@@ -54,7 +54,7 @@ module Hecks
|
|
|
54
54
|
@attributes = attributes
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
-
# A query's shape is
|
|
57
|
+
# A query's shape is not fixed — `extra_options_to_h` carries
|
|
58
58
|
# whatever options the specification layer grew (count, median,
|
|
59
59
|
# group_by, scope_to). Declared emission covers the settled part
|
|
60
60
|
# and `super` hands it over; the tail stays dynamic, which is the
|
|
@@ -4,11 +4,11 @@ module Hecks
|
|
|
4
4
|
module Bluebook
|
|
5
5
|
# A read model — an ask that gathers heads from more than one aggregate.
|
|
6
6
|
#
|
|
7
|
-
# Like a query it crosses over as an
|
|
7
|
+
# Like a query it crosses over as an instance, and for the same reason: its
|
|
8
8
|
# body is inherited from `QuerySpecification::ReadModel::Specification`, whose
|
|
9
9
|
# readers the runtime and the SQLite adapter both call on the object. It gains
|
|
10
10
|
# an identity and an owner ; it keeps the name it always had, because only a
|
|
11
|
-
#
|
|
11
|
+
# class ever had a competing answer for `name`.
|
|
12
12
|
class ReadModel < QuerySpecification::ReadModel::Specification
|
|
13
13
|
include Construct
|
|
14
14
|
|
|
@@ -29,7 +29,7 @@ module Hecks
|
|
|
29
29
|
attr_reader :name, :description, :reference_name, :reference_target, :aggregate_heads, :group_by,
|
|
30
30
|
:count, :median_field
|
|
31
31
|
|
|
32
|
-
# `reference_name:`/`reference_target:` are nil for a
|
|
32
|
+
# `reference_name:`/`reference_target:` are nil for a rootless read
|
|
33
33
|
# model (no `reference_to` declared) — `&.` throughout, rather than
|
|
34
34
|
# the `.to_s`/`.to_sym` this used to require unconditionally, so
|
|
35
35
|
# `reference_target.nil?` stays a real, checkable fact for the
|
|
@@ -47,11 +47,11 @@ module Hecks
|
|
|
47
47
|
# `group_by_fields` is the convenience reader everything but
|
|
48
48
|
# `to_h`/the Judge's own generic walk actually wants.
|
|
49
49
|
@group_by = group_by
|
|
50
|
-
#
|
|
50
|
+
# **Absent is not false**. `@count` stays nil rather than becoming
|
|
51
51
|
# `false` when undeclared — the same "if you declare it, declare
|
|
52
52
|
# something" reading `Lifecycle`'s own optional fields rely on
|
|
53
53
|
# (MetaValidator::Judge#setters skips a setter whose every
|
|
54
|
-
# source is `nil`, so an
|
|
54
|
+
# source is `nil`, so an always-false `@count` would dispatch
|
|
55
55
|
# `ReadModel.Count` on every read model that never wrote the
|
|
56
56
|
# word at all). `!!count` collapses a truthy DSL `true` (or a
|
|
57
57
|
# reconstructed `true`) to the same `true`/`nil` pair either path
|
|
@@ -60,15 +60,15 @@ module Hecks
|
|
|
60
60
|
@median_field = median_field&.to_sym
|
|
61
61
|
end
|
|
62
62
|
|
|
63
|
-
# `.to_sym` regardless of source — the
|
|
63
|
+
# `.to_sym` regardless of source — the direct builder path stores
|
|
64
64
|
# symbols, but `Reconstruction::Shapes#group_by_field` (the
|
|
65
|
-
# replayed-from-the-meta-domain path every
|
|
65
|
+
# replayed-from-the-meta-domain path every real boot actually
|
|
66
66
|
# goes through) reads the field back as a String, the same way
|
|
67
|
-
# `aggregate_heads`' own `:as` does. Row hash
|
|
67
|
+
# `aggregate_heads`' own `:as` does. Row hash keys built by
|
|
68
68
|
# `Value.materialize_unwrapped` are symbols (`attr.name`), so
|
|
69
69
|
# this has to be too, or `row[field]` in `nest` silently misses.
|
|
70
70
|
|
|
71
|
-
# `wheres`/`order_by`/`limit` are spelled explicitly here, the
|
|
71
|
+
# `wheres`/`order_by`/`limit` are spelled explicitly here, the same
|
|
72
72
|
# mechanism `Query#to_h` already uses (query.rb, read directly
|
|
73
73
|
# before this was written) — always present, `wheres` a (possibly
|
|
74
74
|
# empty) array and `order_by`/`limit` nil when undeclared, exactly
|
|
@@ -78,16 +78,16 @@ module Hecks
|
|
|
78
78
|
# than a reader needing to learn a second one. See this file's own
|
|
79
79
|
# `filtered_head_name` and language/bluebook/syntax.bluebook's
|
|
80
80
|
# `ReadModel` `where`/`order_by`/`limit` member rows for the history
|
|
81
|
-
# of why this
|
|
81
|
+
# of why this was narrower, and 2026-08-11's read-model where/
|
|
82
82
|
# order_by/limit task for why it stopped being.
|
|
83
83
|
# Same dynamic tail as a Query's, plus two collections whose
|
|
84
|
-
#
|
|
84
|
+
# rows are plain hashes rather than constructs — they are
|
|
85
85
|
# normalised here rather than by `many`, which recurses through
|
|
86
86
|
# `to_h` and would have nothing to call.
|
|
87
|
-
# `count`/`median_field` are
|
|
87
|
+
# `count`/`median_field` are absent (no key at all), not `nil`,
|
|
88
88
|
# when undeclared — unlike `group_by` (always a `[]`, never
|
|
89
|
-
# missing) they are the
|
|
90
|
-
# added that no
|
|
89
|
+
# missing) they are the first fields this construct has ever
|
|
90
|
+
# added that no older real corpus member could possibly carry, so
|
|
91
91
|
# merging them unconditionally would have put a `null` onto every
|
|
92
92
|
# existing read model's own wire shape (banking's
|
|
93
93
|
# `ComplianceDashboard`/`CustomerPortfolio`, the language's own
|
|
@@ -2,15 +2,15 @@ module Hecks
|
|
|
2
2
|
module Bluebook
|
|
3
3
|
# An attribute that points at another aggregate's head.
|
|
4
4
|
#
|
|
5
|
-
# This used to be the
|
|
5
|
+
# This used to be the string `"Reference<Customer>"`, minted by
|
|
6
6
|
# `AggregateBuilder#reference_to` and `CommandBuilder#cross_reference` from
|
|
7
7
|
# a real constant that had just been handed in, and then parsed back apart
|
|
8
8
|
# by a regex in the command interpreter, by string equality in the read-model
|
|
9
9
|
# interpreter and the SQLite adapter, and by `delete_prefix` in the bluebook
|
|
10
10
|
# builder. Five readers of a spelling one writer invented.
|
|
11
11
|
#
|
|
12
|
-
# It holds the
|
|
13
|
-
# Aggregate. Resolution is
|
|
12
|
+
# It holds the target instead, and answers `resolve` with the target's
|
|
13
|
+
# Aggregate. Resolution is lazy and deliberately so: `reference_to
|
|
14
14
|
# Customer` may name an aggregate declared lower in the file — banking's
|
|
15
15
|
# Account points at Customer and survives only because Customer happens to
|
|
16
16
|
# be written above — so the edge cannot be resolved at declaration time.
|
|
@@ -34,7 +34,7 @@ module Hecks
|
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
# The Aggregate this points at, or nil when the target belongs to
|
|
37
|
-
#
|
|
37
|
+
# another domain — a cross-domain target may legitimately not be loaded,
|
|
38
38
|
# the same reading `across` policies get.
|
|
39
39
|
def resolve
|
|
40
40
|
unless declared_in
|
|
@@ -51,13 +51,13 @@ module Hecks
|
|
|
51
51
|
def to_s = "Reference<#{@target_name}>"
|
|
52
52
|
def inspect = "#<Reference #{@target_name}>"
|
|
53
53
|
|
|
54
|
-
#
|
|
55
|
-
# the
|
|
54
|
+
# Value equality, not identity — without this, two references to
|
|
55
|
+
# the same target, parsed from two separate bluebook reads (era
|
|
56
56
|
# N's own boot and a held era's own shadow reconstruction,
|
|
57
57
|
# coverage_check.rb's own comparison), are different objects and
|
|
58
58
|
# compare unequal by Ruby's default `==`. `EraGuard::ShapeDiff
|
|
59
59
|
# #diff_type`'s `held_type != current_type` check then reads as
|
|
60
|
-
# true for
|
|
60
|
+
# true for every reference_to attribute on every mint, regardless
|
|
61
61
|
# of whether the reference actually changed — a real refusal for
|
|
62
62
|
# attributes nothing about. `declared_in` (which aggregate carries
|
|
63
63
|
# this reference) is deliberately excluded: the same reference
|
|
@@ -65,7 +65,7 @@ module Hecks
|
|
|
65
65
|
# from separately-parsed bluebooks with structurally different
|
|
66
66
|
# (if same-shaped) owning aggregates, and `declared_in` is a
|
|
67
67
|
# cross-reference for `resolve`, not part of what this attribute
|
|
68
|
-
# itself
|
|
68
|
+
# itself is.
|
|
69
69
|
def ==(other) = other.is_a?(Reference) && target_name == other.target_name
|
|
70
70
|
alias eql? ==
|
|
71
71
|
def hash = [self.class, target_name].hash
|
|
@@ -4,10 +4,10 @@ require "fileutils"
|
|
|
4
4
|
|
|
5
5
|
module Hecks
|
|
6
6
|
module Bluebook
|
|
7
|
-
#
|
|
7
|
+
# Boots a real bluebook and actually dispatches against it — the
|
|
8
8
|
# sibling `bin/model_check` never had: that tool proves a bluebook
|
|
9
|
-
# is
|
|
10
|
-
# without ever running a single command; this proves it
|
|
9
|
+
# is structurally sound (no dead states, no unreachable transitions)
|
|
10
|
+
# without ever running a single command; this proves it works,
|
|
11
11
|
# catching exactly the class of bug static analysis structurally
|
|
12
12
|
# cannot see. Built and proved inside `bin/interview`'s own `smoke`
|
|
13
13
|
# command, where it first found two real bugs — a lifecycle field
|
|
@@ -15,20 +15,20 @@ module Hecks
|
|
|
15
15
|
# missing `Command.ActsOn` — that reloaded clean, checked clean,
|
|
16
16
|
# and only broke once something actually dispatched against them.
|
|
17
17
|
#
|
|
18
|
-
#
|
|
18
|
+
# Synthesized args, never random (`Synthesizer`) — a String becomes
|
|
19
19
|
# a fixed marker, a closed set uses its own first admitted member, a
|
|
20
20
|
# reference reuses whatever this same run already minted for that
|
|
21
|
-
# target.
|
|
21
|
+
# target. One call per declared command, one call per declared
|
|
22
22
|
# report, per created root; every failure is collected and reported
|
|
23
23
|
# together rather than stopping at the first.
|
|
24
24
|
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
25
|
+
# **What this cannot catch**: a call that dispatches cleanly but answers
|
|
26
|
+
# wrong — the read-model join bug this exact tool's own first user
|
|
27
27
|
# hit is the textbook case, a query that silently returned an empty
|
|
28
28
|
# array rather than raising. Smoke-testing proves nothing crashes;
|
|
29
29
|
# it does not prove the answer is the right one.
|
|
30
30
|
#
|
|
31
|
-
# A
|
|
31
|
+
# A failure here is not necessarily a domain bug, either — it may
|
|
32
32
|
# just be `Synthesizer`'s own naive values (0, an empty list,
|
|
33
33
|
# "smoke-test") not satisfying a real invariant this simple
|
|
34
34
|
# generator was never built to reason about (a positive amount, a
|
|
@@ -54,11 +54,11 @@ module Hecks
|
|
|
54
54
|
# per-domain realm resolution requires and a plain boot never
|
|
55
55
|
# did. Reports are reachable the identical way regardless of
|
|
56
56
|
# boot path — `dispatcher.query("Domain.report_name", **args)`
|
|
57
|
-
# is the
|
|
58
|
-
# was never actually required for this, only its
|
|
59
|
-
#
|
|
57
|
+
# is the same `Dispatcher#query` either boot hands back; Router
|
|
58
|
+
# was never actually required for this, only its own namespace
|
|
59
|
+
# sugar (`Domain.report_name(...)` as a bare method call) was.
|
|
60
60
|
#
|
|
61
|
-
#
|
|
61
|
+
# Never boots `dir`'s own real bindings — measured, not a
|
|
62
62
|
# precaution taken on spec: pointed at `examples/pizzas` (a real,
|
|
63
63
|
# persistent store carrying real accumulated records), a
|
|
64
64
|
# synthesized `CreatePizza` collided with an actual pre-existing
|
|
@@ -73,7 +73,7 @@ module Hecks
|
|
|
73
73
|
# `install_facade: false` — this only ever dispatches by FQN string
|
|
74
74
|
# (below), so it never needs the `Widget::Item.Add(...)` Ruby
|
|
75
75
|
# sugar `Hecks.boot` installs by default. Skipping it matters
|
|
76
|
-
# here specifically: that sugar lands as a
|
|
76
|
+
# here specifically: that sugar lands as a bare global constant on
|
|
77
77
|
# `Object` per domain and per aggregate name, with no scoping and
|
|
78
78
|
# no cleanup — and this tool boots throwaway domains under
|
|
79
79
|
# whatever generic names the caller's `.bluebook` happens to use
|
|
@@ -93,9 +93,9 @@ module Hecks
|
|
|
93
93
|
end
|
|
94
94
|
end
|
|
95
95
|
|
|
96
|
-
#
|
|
96
|
+
# Only the `.bluebook`, never `.world` either — a real world's own
|
|
97
97
|
# settings (`persisted_by("Heki") { dir "..." }`) are keyed to the
|
|
98
|
-
#
|
|
98
|
+
# real adapter it names, not to Memory; copied verbatim, they
|
|
99
99
|
# apply to the wrong binding and refuse with a `WiringError`
|
|
100
100
|
# ("Memory does not declare :dir") — measured, not assumed, the
|
|
101
101
|
# first time this ran against Banking. A plain `Hecks.boot`
|
|
@@ -112,8 +112,8 @@ module Hecks
|
|
|
112
112
|
Dir.glob(File.join(source, "*.bluebook")).each { |file| FileUtils.cp(file, target) }
|
|
113
113
|
end
|
|
114
114
|
|
|
115
|
-
#
|
|
116
|
-
# a
|
|
115
|
+
# Aggregates walked in declaration order, on purpose — so whatever
|
|
116
|
+
# a later aggregate's own shape needs from an earlier one (a
|
|
117
117
|
# `TripItem` needing a real `PackingItem`, say) already exists by
|
|
118
118
|
# the time that aggregate's own turn comes, the same reason
|
|
119
119
|
# `Synthesizer#args_for`'s `created` map is threaded through in
|
|
@@ -136,7 +136,7 @@ module Hecks
|
|
|
136
136
|
creating.each do |command|
|
|
137
137
|
args = Synthesizer.args_for(chapter, aggregate, command, created)
|
|
138
138
|
begin
|
|
139
|
-
result = dispatcher.
|
|
139
|
+
result = dispatcher.dispatch_flat("#{domain}::#{aggregate.name}.#{command.hecks_name}", args)
|
|
140
140
|
created[aggregate.name] = result.instance.id
|
|
141
141
|
rescue StandardError => e
|
|
142
142
|
failures << Failure.new(domain: domain, aggregate: aggregate.name, command: command.hecks_name,
|
|
@@ -146,7 +146,7 @@ module Hecks
|
|
|
146
146
|
|
|
147
147
|
noncreating.each do |nc_command|
|
|
148
148
|
nc_args = Synthesizer.args_for(chapter, aggregate, nc_command, created).merge(id: created[aggregate.name])
|
|
149
|
-
dispatcher.
|
|
149
|
+
dispatcher.dispatch_flat("#{domain}::#{aggregate.name}.#{nc_command.hecks_name}", nc_args)
|
|
150
150
|
rescue StandardError => e
|
|
151
151
|
failures << Failure.new(domain: domain, aggregate: aggregate.name, command: nc_command.hecks_name,
|
|
152
152
|
error: "#{e.class}: #{e.message}")
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
module Hecks
|
|
2
2
|
module Bluebook
|
|
3
|
-
#
|
|
3
|
+
# **One synthesized argument per declared attribute** — never a random
|
|
4
4
|
# guess. Reads only real `IR` (`Aggregate`, `Command`,
|
|
5
|
-
# `Attribute`, `ValueObject`), so it works against
|
|
5
|
+
# `Attribute`, `ValueObject`), so it works against any
|
|
6
6
|
# loaded bluebook, not one particular domain: a String becomes a
|
|
7
|
-
# fixed marker; an Integer becomes 0; a closed set uses
|
|
7
|
+
# fixed marker; an Integer becomes 0; a closed set uses its own
|
|
8
8
|
# first admitted member (never a value a real `one_of` would
|
|
9
|
-
# legitimately refuse); a reference uses whatever id the
|
|
9
|
+
# legitimately refuse); a reference uses whatever id the caller
|
|
10
10
|
# already knows for that target (`created`), so a command whose
|
|
11
11
|
# own shape depends on an earlier-created record — a `TripItem`
|
|
12
12
|
# needing a real `PackingItem`, say — gets something real to work
|
|
@@ -16,8 +16,8 @@ module Hecks
|
|
|
16
16
|
# got built and proved — the logic never actually knew anything
|
|
17
17
|
# about the Interview domain or any one app; it only ever read IR.
|
|
18
18
|
module Synthesizer
|
|
19
|
-
#
|
|
20
|
-
# a value object's own field names is
|
|
19
|
+
# The only type names that are ever truly scalar — anything else
|
|
20
|
+
# a value object's own field names is another value object,
|
|
21
21
|
# nested (`Pizza.price_cents: Price`, itself wrapping `cents:
|
|
22
22
|
# Integer` — a real, ordinary shape, not an edge case). Missing
|
|
23
23
|
# this the first time round meant a nested field silently
|
|
@@ -26,7 +26,7 @@ module Hecks
|
|
|
26
26
|
# only by testing against Pizzas instead of re-testing against
|
|
27
27
|
# the one simpler domain this was first built for, where every
|
|
28
28
|
# value object happened to be single-field and primitive-typed.
|
|
29
|
-
#
|
|
29
|
+
# The same list `Attribute::PRIMITIVES` holds, referenced rather
|
|
30
30
|
# than repeated. It was a second, byte-identical copy — and only
|
|
31
31
|
# the Attribute one is held to `vocabulary.bluebook` by
|
|
32
32
|
# spec/vocabulary_conformance_spec, so this copy could drift from
|
|
@@ -38,7 +38,7 @@ module Hecks
|
|
|
38
38
|
# `chapter`/`aggregate` are the real `Bluebook`/`Aggregate`
|
|
39
39
|
# the command belongs to — needed to resolve a value object type
|
|
40
40
|
# name back to its own declared shape. `created` maps an
|
|
41
|
-
# aggregate
|
|
41
|
+
# aggregate name to a real id already minted for it earlier in
|
|
42
42
|
# the same run; a reference whose target isn't in there yet gets
|
|
43
43
|
# a placeholder instead of failing outright, since the caller may
|
|
44
44
|
# not care about that particular argument's real value.
|
|
@@ -52,13 +52,13 @@ module Hecks
|
|
|
52
52
|
end
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
-
# A value object's
|
|
55
|
+
# A value object's own synthesized value — its first admitted
|
|
56
56
|
# member if it's a closed set (the one value guaranteed not to be
|
|
57
57
|
# refused), otherwise one synthesized scalar per declared field.
|
|
58
58
|
# Falls back to searching every aggregate in the chapter, the
|
|
59
59
|
# same tolerance `bin/interview shape`'s own lookup already
|
|
60
60
|
# needed: a value object referenced by name doesn't have to be
|
|
61
|
-
# declared on the
|
|
61
|
+
# declared on the same aggregate using it.
|
|
62
62
|
def value_for(chapter, aggregate, type_name)
|
|
63
63
|
value_object = aggregate.value_object(type_name) ||
|
|
64
64
|
chapter.aggregates.filter_map { |a| a.value_object(type_name) }.first
|
|
@@ -72,7 +72,7 @@ module Hecks
|
|
|
72
72
|
|
|
73
73
|
# A single field's own synthesized value — a plain scalar if its
|
|
74
74
|
# type is one of the true primitives, otherwise that type names
|
|
75
|
-
#
|
|
75
|
+
# another value object, resolved the identical way `value_for`
|
|
76
76
|
# resolves any other one (its own closed set or its own nested
|
|
77
77
|
# fields, however deep that nesting actually goes).
|
|
78
78
|
def field_value_for(chapter, aggregate, type_name)
|
|
@@ -80,7 +80,7 @@ module Hecks
|
|
|
80
80
|
end
|
|
81
81
|
|
|
82
82
|
# A bare primitive's own synthesized value. Never used for a
|
|
83
|
-
# closed set's
|
|
83
|
+
# closed set's own field (that's `value_for`'s job, reading the
|
|
84
84
|
# set's real first member) — only for a plain scalar field with
|
|
85
85
|
# no declared vocabulary to respect.
|
|
86
86
|
def scalar_for(primitive)
|
|
@@ -5,7 +5,7 @@ module Hecks
|
|
|
5
5
|
# Paths are dotted ("price.cents") for a VO member, bare otherwise.
|
|
6
6
|
TranslationMove = Struct.new(:from, :to)
|
|
7
7
|
|
|
8
|
-
# One field whose
|
|
8
|
+
# One field whose value, not just its name or position, changed —
|
|
9
9
|
# an old value has nothing in common with a new one, so the only
|
|
10
10
|
# honest way to bridge it is a declared, exhaustive lookup table.
|
|
11
11
|
# Paths follow `TranslationMove`'s convention (dotted reaches a VO
|
|
@@ -16,7 +16,7 @@ module Hecks
|
|
|
16
16
|
# rubocop:disable-next Lint/StructNewOverride
|
|
17
17
|
TranslationConvert = Struct.new(:from, :to, :values)
|
|
18
18
|
|
|
19
|
-
# A value object's or entity's own
|
|
19
|
+
# A value object's or entity's own type name changed with its member
|
|
20
20
|
# structure unchanged — the one drift `rename`/`move` cannot express,
|
|
21
21
|
# because the attribute kept its name and only the type it points at
|
|
22
22
|
# was renamed. Mirrors `was:` one level deeper.
|
|
@@ -29,7 +29,7 @@ module Hecks
|
|
|
29
29
|
# every other adapter.
|
|
30
30
|
TranslationCompute = Struct.new(:from, :to, :sql)
|
|
31
31
|
|
|
32
|
-
# The aggregate's own
|
|
32
|
+
# The aggregate's own identity changed what it's computed from — not
|
|
33
33
|
# a field crossing a boundary (that's `move`), a value objects's type
|
|
34
34
|
# name (`retype`), or a value transform (`compute`): the record's own
|
|
35
35
|
# key. No `from:`/`to:` path, unlike every other rule here, because
|
|
@@ -41,7 +41,7 @@ module Hecks
|
|
|
41
41
|
TranslationRekey = Struct.new(:sql)
|
|
42
42
|
|
|
43
43
|
# A newly added, required attribute with no source in old data at
|
|
44
|
-
# all — not a rename, move, or convert, all of which need a
|
|
44
|
+
# all — not a rename, move, or convert, all of which need a from
|
|
45
45
|
# path in the old shape. `default` is the value an existing record
|
|
46
46
|
# reads until the next command against it writes a real one; unlike
|
|
47
47
|
# `compute`, this is adapter-agnostic — applied in-process by
|
|
@@ -5,7 +5,7 @@ module Hecks
|
|
|
5
5
|
module Bluebook
|
|
6
6
|
Invariant = Struct.new(:description, :canonical, :predicate, :ast, keyword_init: true)
|
|
7
7
|
|
|
8
|
-
# A value object — a
|
|
8
|
+
# A value object — a declaration holder, never instantiated.
|
|
9
9
|
#
|
|
10
10
|
# `ValueObjectBuilder` returns an anonymous subclass whose singleton
|
|
11
11
|
# carries the declaration : attributes, invariants, members. Nothing ever
|
|
@@ -16,11 +16,11 @@ module Hecks
|
|
|
16
16
|
#
|
|
17
17
|
# `to_h` does not move. It is a byte-for-byte contract pinned by the
|
|
18
18
|
# golden fixtures, so it keeps spelling the short declared name, which
|
|
19
|
-
# is what `hecks_name` carries.
|
|
20
|
-
#
|
|
19
|
+
# is what `hecks_name` carries. Declarations in the graph, strings in the
|
|
20
|
+
# export.
|
|
21
21
|
class ValueObject
|
|
22
22
|
extend Construct
|
|
23
|
-
#
|
|
23
|
+
# Extended, not included — this construct is a class, so its
|
|
24
24
|
# emission is a class method. See Hecks::IR's own note on
|
|
25
25
|
# the two shapes.
|
|
26
26
|
extend Hecks::IR
|
|
@@ -29,7 +29,7 @@ module Hecks
|
|
|
29
29
|
emits_ir(
|
|
30
30
|
name: :hecks_name,
|
|
31
31
|
attributes: many(:attributes),
|
|
32
|
-
# `ast:` — a JSON-serializable rendering of the
|
|
32
|
+
# `ast:` — a JSON-serializable rendering of the same predicate
|
|
33
33
|
# `canonical` already spells as text, alongside it rather than
|
|
34
34
|
# replacing it (`canonical` stays the human-facing/doctest-facing
|
|
35
35
|
# form; parsing it back would just re-derive what `ast` already
|
|
@@ -39,7 +39,7 @@ module Hecks
|
|
|
39
39
|
# has no kernel crate to parse `canonical` with.
|
|
40
40
|
invariants: -> { invariants.map { |rule| Expression::AstJson.rule_row(rule) } },
|
|
41
41
|
closed_set: :closed_set?,
|
|
42
|
-
#
|
|
42
|
+
# The field name is stringified, never the value. A `member` row can
|
|
43
43
|
# hold any of the scalar types an attribute declares — `Integer 84`
|
|
44
44
|
# (`StatementFrequency#retention_months`, statements.bluebook), not
|
|
45
45
|
# only `String` — and `value.to_s` used to erase that on the way
|
data/lib/hecks/bluebook.rb
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# the meta-validator that its builders call at build time.
|
|
14
14
|
|
|
15
15
|
module Hecks
|
|
16
|
-
# Declared as a
|
|
16
|
+
# Declared as a class, not a module — `Hecks::Bluebook` is a
|
|
17
17
|
# chapter (bluebook/chapter.rb carries its body). Everything a chapter
|
|
18
18
|
# declares nests under it, as do the ways to build one (`DSL`) and to
|
|
19
19
|
# judge one (`MetaValidator`). Reopening this anywhere must say `class`.
|
|
@@ -29,7 +29,7 @@ require_relative "literal"
|
|
|
29
29
|
require_relative "query_specification"
|
|
30
30
|
|
|
31
31
|
require_relative "bluebook/expression"
|
|
32
|
-
#
|
|
32
|
+
# **The model itself** — the chapter class's own body first, then everything
|
|
33
33
|
# a chapter declares. Order matters only for reading: each is a bag of
|
|
34
34
|
# declarations with no load-time cross-references.
|
|
35
35
|
require_relative "bluebook/chapter"
|