hecks 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/hecks/adapters/driven/claude_code.rb +7 -7
- data/lib/hecks/adapters/driven/d1.rb +187 -23
- data/lib/hecks/adapters/driven/folder.rb +10 -10
- data/lib/hecks/adapters/driven/google_authentication.rb +8 -8
- data/lib/hecks/adapters/driven/governance_authorization.rb +31 -13
- data/lib/hecks/adapters/driven/heki/journal.rb +60 -2
- data/lib/hecks/adapters/driven/heki/saga_store.rb +5 -5
- data/lib/hecks/adapters/driven/heki.rb +13 -7
- data/lib/hecks/adapters/driven/identity_registry.rb +2 -2
- data/lib/hecks/adapters/driven/in_memory_ordering.rb +3 -3
- data/lib/hecks/adapters/driven/lambda/client.rb +34 -9
- data/lib/hecks/adapters/driven/lambda.rb +39 -33
- data/lib/hecks/adapters/driven/local_storage.rb +17 -10
- data/lib/hecks/adapters/driven/memory.rb +205 -9
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +1 -1
- data/lib/hecks/adapters/driven/postgres/codec.rb +27 -11
- data/lib/hecks/adapters/driven/postgres/outbox.rb +40 -2
- data/lib/hecks/adapters/driven/postgres/reconnect.rb +23 -7
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +14 -14
- data/lib/hecks/adapters/driven/postgres.rb +175 -28
- data/lib/hecks/adapters/driven/postgres_era.adapter +5 -0
- data/lib/hecks/adapters/driven/prism.rb +4 -4
- data/lib/hecks/adapters/driven/sql_query_builder.rb +34 -22
- data/lib/hecks/adapters/driven/sqlite/codec.rb +38 -10
- data/lib/hecks/adapters/driven/sqlite/projection.rb +60 -32
- data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +12 -12
- data/lib/hecks/adapters/driven/sqlite.rb +181 -21
- data/lib/hecks/adapters/driven.rb +4 -4
- data/lib/hecks/adapters/driving/github_webhook.rb +145 -0
- data/lib/hecks/behaviors/dsl.rb +2 -2
- data/lib/hecks/behaviors/expectations.rb +51 -23
- data/lib/hecks/behaviors/ir.rb +1 -1
- data/lib/hecks/behaviors/rspec.rb +1 -1
- data/lib/hecks/behaviors/runner.rb +2 -2
- data/lib/hecks/behaviors.rb +1 -1
- data/lib/hecks/bluebook/aggregate.rb +13 -13
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +10 -10
- data/lib/hecks/bluebook/assembly/build.rb +1 -1
- data/lib/hecks/bluebook/assembly/contract.rb +39 -16
- data/lib/hecks/bluebook/assembly/contracts.rb +40 -38
- data/lib/hecks/bluebook/assembly/marks.rb +18 -18
- data/lib/hecks/bluebook/assembly/specializer.rb +19 -21
- data/lib/hecks/bluebook/assembly.rb +9 -9
- data/lib/hecks/bluebook/attribute.rb +9 -9
- data/lib/hecks/bluebook/behaviour/aggregate.rb +11 -11
- data/lib/hecks/bluebook/behaviour/attribute.rb +5 -5
- data/lib/hecks/bluebook/behaviour/chapter.rb +23 -5
- data/lib/hecks/bluebook/behaviour/command.rb +23 -23
- data/lib/hecks/bluebook/behaviour/domain_port.rb +27 -3
- data/lib/hecks/bluebook/behaviour/entity.rb +8 -8
- data/lib/hecks/bluebook/behaviour/hexagon.rb +4 -4
- data/lib/hecks/bluebook/behaviour/lifecycle.rb +5 -5
- data/lib/hecks/bluebook/behaviour/policy.rb +12 -12
- data/lib/hecks/bluebook/behaviour/process_manager.rb +7 -7
- data/lib/hecks/bluebook/behaviour/query.rb +1 -1
- data/lib/hecks/bluebook/behaviour/read_model.rb +8 -8
- data/lib/hecks/bluebook/behaviour/traits.rb +12 -12
- data/lib/hecks/bluebook/behaviour/value_object.rb +6 -6
- data/lib/hecks/bluebook/capabilities.rb +27 -0
- data/lib/hecks/bluebook/chapter.rb +28 -9
- data/lib/hecks/bluebook/command.rb +12 -12
- data/lib/hecks/bluebook/domain_port.rb +9 -9
- data/lib/hecks/bluebook/dsl/adapter_builder.rb +24 -0
- data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +49 -49
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +96 -96
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +41 -41
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +22 -2
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +111 -74
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +48 -30
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +116 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +103 -103
- data/lib/hecks/bluebook/dsl/const_shim.rb +46 -15
- data/lib/hecks/bluebook/dsl/domain_port_builder.rb +90 -25
- data/lib/hecks/bluebook/dsl/entity_builder.rb +56 -56
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +148 -132
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +89 -30
- data/lib/hecks/bluebook/dsl/identity_declaration.rb +17 -17
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +27 -4
- data/lib/hecks/bluebook/dsl/policy_builder.rb +30 -21
- data/lib/hecks/bluebook/dsl/port_builder.rb +38 -7
- data/lib/hecks/bluebook/dsl/port_operation_builder.rb +56 -22
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +35 -35
- data/lib/hecks/bluebook/dsl/query_builder.rb +5 -5
- data/lib/hecks/bluebook/dsl/read_model_builder.rb +34 -34
- data/lib/hecks/bluebook/dsl/rule_reference.rb +41 -39
- data/lib/hecks/bluebook/dsl/translation_builder.rb +9 -9
- data/lib/hecks/bluebook/dsl/value_object_builder.rb +16 -16
- data/lib/hecks/bluebook/dsl/word_gate.rb +59 -53
- data/lib/hecks/bluebook/dsl/world_builder.rb +51 -8
- data/lib/hecks/bluebook/entity.rb +11 -11
- data/lib/hecks/bluebook/expression/ast_json.rb +20 -20
- data/lib/hecks/bluebook/expression/ast_reader.rb +3 -3
- data/lib/hecks/bluebook/expression/canonical_form.rb +9 -9
- data/lib/hecks/bluebook/expression/evaluator.rb +18 -18
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +18 -18
- data/lib/hecks/bluebook/expression/resolver.rb +60 -62
- data/lib/hecks/bluebook/hexagon.rb +1 -1
- data/lib/hecks/bluebook/lifecycle.rb +1 -1
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -1
- data/lib/hecks/bluebook/meta_validator/judge.rb +122 -86
- data/lib/hecks/bluebook/meta_validator/plan.rb +39 -39
- data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -2
- data/lib/hecks/bluebook/meta_validator/readings.rb +43 -43
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +44 -37
- data/lib/hecks/bluebook/meta_validator/shapes.rb +25 -21
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +145 -31
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +6 -6
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +5 -5
- data/lib/hecks/bluebook/meta_validator.rb +70 -70
- data/lib/hecks/bluebook/model_check.rb +301 -84
- data/lib/hecks/bluebook/pattern_subset.rb +9 -9
- data/lib/hecks/bluebook/policy.rb +15 -13
- data/lib/hecks/bluebook/process_manager.rb +14 -14
- data/lib/hecks/bluebook/project_register.rb +6 -6
- data/lib/hecks/bluebook/query.rb +4 -4
- data/lib/hecks/bluebook/read_model.rb +14 -14
- data/lib/hecks/bluebook/reference.rb +8 -8
- data/lib/hecks/bluebook/smoke_test.rb +19 -19
- data/lib/hecks/bluebook/synthesizer.rb +12 -12
- data/lib/hecks/bluebook/translation.rb +4 -4
- data/lib/hecks/bluebook/value_object.rb +6 -6
- data/lib/hecks/bluebook.rb +2 -2
- data/lib/hecks/codemod/legacy_dispatch_args.rb +299 -0
- data/lib/hecks/codemod/legacy_dispatch_recorder.rb +186 -0
- data/lib/hecks/codemod.rb +36 -35
- data/lib/hecks/construct.rb +6 -6
- data/lib/hecks/corpus.rb +317 -0
- data/lib/hecks/deprecation.rb +95 -0
- data/lib/hecks/doc/reference.rb +19 -19
- data/lib/hecks/embryonaut_bluebook.rb +11 -11
- data/lib/hecks/facade/cli_door.rb +69 -10
- data/lib/hecks/facade/cli_runner.rb +105 -24
- data/lib/hecks/facade/command_request.rb +23 -0
- data/lib/hecks/facade/handle.rb +79 -32
- data/lib/hecks/facade/json_door.rb +106 -25
- data/lib/hecks/facade/surface/aggregate_door.rb +42 -27
- data/lib/hecks/facade/surface/chapter.rb +26 -17
- data/lib/hecks/facade/surface.rb +16 -3
- data/lib/hecks/facade.rb +15 -4
- data/lib/hecks/forms/app.rb +46 -30
- data/lib/hecks/forms/command_form_renderer.rb +70 -9
- data/lib/hecks/forms/field_renderer.rb +142 -6
- data/lib/hecks/forms/field_shape.rb +183 -20
- data/lib/hecks/forms/html.rb +51 -7
- data/lib/hecks/forms/index_renderer.rb +14 -2
- data/lib/hecks/forms/params.rb +120 -23
- data/lib/hecks/forms/port_argument.rb +2 -2
- data/lib/hecks/forms/query_form_renderer.rb +2 -2
- data/lib/hecks/forms/record_renderer.rb +2 -2
- data/lib/hecks/forms/record_table.rb +1 -1
- data/lib/hecks/forms/value_object_shape.rb +3 -3
- data/lib/hecks/forms.rb +24 -4
- data/lib/hecks/fqn.rb +1 -1
- data/lib/hecks/framework/bluebook/governance.bluebook +9 -0
- data/lib/hecks/framework.rb +48 -17
- data/lib/hecks/freezer.rb +11 -11
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +90 -90
- data/lib/hecks/fuzzing/combination_miner.rb +119 -0
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +361 -0
- data/lib/hecks/fuzzing/coverage_campaign.rb +118 -0
- data/lib/hecks/fuzzing/differential.rb +158 -0
- data/lib/hecks/fuzzing/domain_generator.rb +694 -0
- data/lib/hecks/fuzzing/era_boundary.rb +124 -0
- data/lib/hecks/fuzzing/form_census.rb +199 -0
- data/lib/hecks/fuzzing/generated_domain_check.rb +95 -0
- data/lib/hecks/fuzzing/invalid_value_generator.rb +6 -6
- data/lib/hecks/fuzzing/isolated_boot.rb +226 -38
- data/lib/hecks/fuzzing/nondeterministic.rb +67 -0
- data/lib/hecks/fuzzing/persistence_parity.rb +161 -0
- data/lib/hecks/fuzzing/properties/corrections.rb +100 -0
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +321 -41
- data/lib/hecks/fuzzing/properties/guards.rb +129 -26
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +32 -32
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +31 -11
- data/lib/hecks/fuzzing/properties/outbox.rb +142 -0
- data/lib/hecks/fuzzing/properties/querying.rb +17 -17
- data/lib/hecks/fuzzing/properties.rb +84 -39
- data/lib/hecks/fuzzing/qa_settings.rb +152 -0
- data/lib/hecks/fuzzing/replay.rb +224 -114
- data/lib/hecks/fuzzing/rotation_priority.rb +94 -0
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +113 -0
- data/lib/hecks/fuzzing/self_consistency.rb +676 -0
- data/lib/hecks/fuzzing/sequence_generator/adversary.rb +526 -0
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +101 -30
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +55 -8
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +31 -11
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +123 -32
- data/lib/hecks/fuzzing/sequence_generator.rb +152 -31
- data/lib/hecks/fuzzing/shrinker.rb +197 -0
- data/lib/hecks/fuzzing/structural_skips.rb +39 -0
- data/lib/hecks/fuzzing/sweep_depth.rb +53 -0
- data/lib/hecks/fuzzing/target_capabilities.rb +180 -0
- data/lib/hecks/fuzzing/value_generator.rb +66 -14
- data/lib/hecks/fuzzing.rb +11 -0
- data/lib/hecks/grammar/evolve.rb +10 -10
- data/lib/hecks/grammar.rb +7 -7
- data/lib/hecks/ir.rb +13 -13
- data/lib/hecks/language/bluebook/bluebook.bluebook +41 -0
- data/lib/hecks/language/bluebook/policy.bluebook +11 -1
- data/lib/hecks/language/bluebook/vocabulary.bluebook +365 -15
- data/lib/hecks/language/oidc.json +5 -0
- data/lib/hecks/literal.rb +9 -9
- data/lib/hecks/naming.rb +89 -21
- data/lib/hecks/ports/access_control.rb +58 -2
- data/lib/hecks/ports/agent/answers.rb +83 -6
- data/lib/hecks/ports/agent.rb +119 -35
- data/lib/hecks/ports/authentication.rb +44 -4
- data/lib/hecks/ports/authorization.rb +53 -11
- data/lib/hecks/ports/clock.rb +42 -23
- data/lib/hecks/ports/extraction.rb +16 -0
- data/lib/hecks/ports/identity_assignment.rb +24 -2
- data/lib/hecks/ports/identity_generation.rb +17 -3
- data/lib/hecks/ports/identity_resolution.rb +18 -1
- data/lib/hecks/ports/loading.rb +4 -0
- data/lib/hecks/ports/persistence/append_only.rb +172 -8
- data/lib/hecks/ports/persistence/binding_policy.rb +34 -0
- data/lib/hecks/ports/persistence/codec_boundary.rb +178 -0
- data/lib/hecks/ports/persistence/execution.rb +4 -0
- data/lib/hecks/ports/persistence/null_saga_store.rb +12 -1
- data/lib/hecks/ports/persistence/plugin.rb +42 -4
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +218 -25
- data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +77 -9
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +81 -24
- data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +29 -18
- data/lib/hecks/ports/persistence/plugins/era/lineage.rb +144 -60
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +103 -8
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +98 -23
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +282 -109
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +63 -25
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +160 -58
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +51 -28
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +28 -5
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +25 -12
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +129 -34
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +51 -6
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +44 -6
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +16 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +57 -4
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +25 -2
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +338 -83
- data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +68 -10
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +9 -3
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +9 -2
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +42 -8
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +16 -1
- data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +36 -5
- data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +23 -3
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +18 -19
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +5 -5
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -2
- data/lib/hecks/ports/persistence/plugins/era.rb +12 -2
- data/lib/hecks/ports/persistence/remote_runtime.rb +9 -2
- data/lib/hecks/ports/persistence/repository_factory.rb +29 -6
- data/lib/hecks/ports/persistence/state_codec.rb +319 -0
- data/lib/hecks/ports/persistence.rb +36 -1
- data/lib/hecks/ports/projection.rb +61 -7
- data/lib/hecks/ports/query/in_memory.rb +3 -3
- data/lib/hecks/ports/query/ordering.rb +6 -6
- data/lib/hecks/ports/query.rb +35 -0
- data/lib/hecks/projections/bootstrap_table.rb +112 -0
- data/lib/hecks/projections/diagrams.rb +75 -75
- data/lib/hecks/projections/glossary/html.rb +250 -0
- data/lib/hecks/projections/glossary/markdown.rb +105 -0
- data/lib/hecks/projections/glossary/mermaid.rb +110 -0
- data/lib/hecks/projections/glossary/page.css +271 -0
- data/lib/hecks/projections/glossary/page.js +72 -0
- data/lib/hecks/projections/glossary/sections.rb +17 -0
- data/lib/hecks/projections/glossary/sentences.rb +205 -0
- data/lib/hecks/projections/glossary.rb +214 -286
- data/lib/hecks/projections/ir.rb +1 -1
- data/lib/hecks/projections/model/deviations.rb +18 -17
- data/lib/hecks/projections/model.rb +25 -21
- data/lib/hecks/projections/oidc.rb +7 -7
- data/lib/hecks/projections/parser_table.rb +5 -5
- data/lib/hecks/projections/reference.rb +3 -3
- data/lib/hecks/projections/rust_vocabulary.rb +443 -0
- data/lib/hecks/projections/shape.rb +2 -2
- data/lib/hecks/projections/statements.rb +11 -11
- data/lib/hecks/projections/vocabulary.rb +9 -9
- data/lib/hecks/projections.rb +5 -3
- data/lib/hecks/projector/cli_projector.rb +29 -29
- data/lib/hecks/projector/docs_projector.rb +13 -13
- data/lib/hecks/projector/exporter.rb +42 -21
- data/lib/hecks/projector/ir_projector.rb +1 -1
- data/lib/hecks/projector/narrate_projector.rb +15 -22
- data/lib/hecks/projector/target.rb +13 -13
- data/lib/hecks/projector.rb +15 -15
- data/lib/hecks/query_ir.rb +47 -47
- data/lib/hecks/query_specification/common/comparators.rb +19 -3
- data/lib/hecks/query_specification/common/comparison.rb +132 -24
- data/lib/hecks/query_specification/common/dsl.rb +65 -9
- data/lib/hecks/query_specification/common/null_policy.rb +57 -13
- data/lib/hecks/query_specification/common/null_semantics.rb +4 -0
- data/lib/hecks/query_specification/common/options.rb +25 -0
- data/lib/hecks/query_specification/field_path.rb +69 -15
- data/lib/hecks/query_specification/hop_path.rb +57 -20
- data/lib/hecks/query_specification/read_model/specification.rb +4 -0
- data/lib/hecks/rendering.rb +3 -3
- data/lib/hecks/router/namespace_installer.rb +3 -3
- data/lib/hecks/router.rb +1 -1
- data/lib/hecks/runtime/aggregate_lock.rb +11 -11
- data/lib/hecks/runtime/boot_gates.rb +3 -3
- data/lib/hecks/runtime/caller.rb +8 -8
- data/lib/hecks/runtime/capability_graph.rb +2 -2
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +22 -25
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +64 -67
- data/lib/hecks/runtime/command_interpreter.rb +159 -102
- data/lib/hecks/runtime/command_rules/admissibility.rb +69 -69
- data/lib/hecks/runtime/command_rules/arithmetic.rb +137 -91
- data/lib/hecks/runtime/command_rules/authorization.rb +38 -17
- data/lib/hecks/runtime/command_rules/emission.rb +18 -1
- data/lib/hecks/runtime/command_rules/references.rb +94 -19
- data/lib/hecks/runtime/command_rules.rb +3 -0
- data/lib/hecks/runtime/dependency_planning.rb +11 -11
- data/lib/hecks/runtime/dispatcher.rb +283 -90
- data/lib/hecks/runtime/entity_element.rb +282 -46
- data/lib/hecks/runtime/entity_interpreter.rb +160 -69
- data/lib/hecks/runtime/errors.rb +19 -19
- data/lib/hecks/runtime/event.rb +6 -6
- data/lib/hecks/runtime/identity.rb +22 -22
- data/lib/hecks/runtime/instance.rb +39 -14
- data/lib/hecks/runtime/interpreting.rb +12 -12
- data/lib/hecks/runtime/invocation.rb +276 -0
- data/lib/hecks/runtime/loader.rb +14 -14
- data/lib/hecks/runtime/outbox.rb +23 -23
- data/lib/hecks/runtime/policy_interpreter.rb +54 -54
- data/lib/hecks/runtime/port_operation_interpreter.rb +22 -19
- data/lib/hecks/runtime/query_interpreter.rb +111 -56
- data/lib/hecks/runtime/reaction_invocation.rb +76 -9
- data/lib/hecks/runtime/read_model_interpreter.rb +40 -40
- data/lib/hecks/runtime/rebuild_sweep.rb +4 -4
- data/lib/hecks/runtime/reference_hop.rb +6 -6
- data/lib/hecks/runtime/refusal_wording.rb +92 -112
- data/lib/hecks/runtime/registry/saga_persistence.rb +21 -21
- data/lib/hecks/runtime/registry/verification.rb +36 -26
- data/lib/hecks/runtime/registry.rb +56 -27
- data/lib/hecks/runtime/remote_dispatcher.rb +38 -23
- data/lib/hecks/runtime/routing.rb +10 -88
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +17 -17
- data/lib/hecks/runtime/saga_interpreter.rb +93 -56
- data/lib/hecks/runtime/saga_pending_dispatch.rb +12 -12
- data/lib/hecks/runtime/tenant_check.rb +9 -9
- data/lib/hecks/runtime/tenant_scope.rb +5 -5
- data/lib/hecks/runtime/value/admission.rb +75 -30
- data/lib/hecks/runtime/value/coercion.rb +379 -226
- data/lib/hecks/runtime/value/entity_list_coercion.rb +248 -0
- data/lib/hecks/runtime/value.rb +28 -23
- data/lib/hecks/runtime.rb +7 -7
- data/lib/hecks/storehouse.rb +64 -64
- data/lib/hecks/version.rb +3 -3
- data/lib/hecks/vocabulary.rb +207 -5
- data/lib/hecks.rb +13 -11
- data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +11 -11
- data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +14 -12
- data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +11 -11
- metadata +43 -2
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
module Hecks
|
|
2
2
|
module Bluebook
|
|
3
3
|
module MetaValidator
|
|
4
|
-
# What the language says about
|
|
4
|
+
# What the language says about itself, read back as something walkable.
|
|
5
5
|
#
|
|
6
6
|
# The judge used to carry one hand-written branch per category, and the
|
|
7
7
|
# reason given for keeping it that way was that "which append command
|
|
8
8
|
# belongs to which list is not derivable from a name". True — and beside
|
|
9
9
|
# the point. It is derivable from the language's own IR, because every
|
|
10
|
-
# append command
|
|
10
|
+
# append command declares its target:
|
|
11
11
|
#
|
|
12
12
|
# command "Argument" do
|
|
13
13
|
# reference_to Command
|
|
@@ -18,7 +18,7 @@ module Hecks
|
|
|
18
18
|
# appender for the `arguments` list, and the map binds each value-object
|
|
19
19
|
# field to the command argument that fills it. Nothing is matched by name.
|
|
20
20
|
#
|
|
21
|
-
# The same reading recovers the containment tree. A command with
|
|
21
|
+
# The same reading recovers the containment tree. A command with no
|
|
22
22
|
# self-reference is the creating one, and the `*_id` argument it carries
|
|
23
23
|
# names the parent — so Bluebook -> Aggregate -> Command / ValueObject /
|
|
24
24
|
# Query / Entity, ValueObject -> Member, ProcessManager -> Handler ->
|
|
@@ -57,7 +57,7 @@ module Hecks
|
|
|
57
57
|
*alternates.map(&:verb), *sealers].compact
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
-
#
|
|
60
|
+
# Does this argument carry an ID? A reference is the id of a head, and
|
|
61
61
|
# an id is a scalar — so the judge offers it bare, where every other
|
|
62
62
|
# field goes as a one-field value object. The language answers this
|
|
63
63
|
# about itself, so declaring a new reference needs no change here.
|
|
@@ -84,33 +84,33 @@ module Hecks
|
|
|
84
84
|
|
|
85
85
|
@categories[aggregate.hecks_name] = read(aggregate)
|
|
86
86
|
|
|
87
|
-
# S17, ADR 0026 — Member/Handler/Dispatch are
|
|
87
|
+
# S17, ADR 0026 — Member/Handler/Dispatch are entities now
|
|
88
88
|
# (`entity "Member" do ... end`, nested under `ValueObject`/
|
|
89
89
|
# `ProcessManager`/`Handler`), not their own top-level
|
|
90
90
|
# aggregates — so `meta.aggregates` alone no longer finds
|
|
91
91
|
# them the way it always found a standalone `aggregate
|
|
92
|
-
# "Member"`. Each
|
|
92
|
+
# "Member"`. Each still needs its own named category here:
|
|
93
93
|
# `Assembly::Contracts` keeps a bespoke entry for each
|
|
94
94
|
# (Member's own open-map `pairs`, Dispatch's own open-map
|
|
95
95
|
# `with_spec`), distinct from the single generic "Entity"
|
|
96
|
-
# category every
|
|
96
|
+
# category every ordinary real-corpus entity (LedgerEntry,
|
|
97
97
|
# Withdrawal, ...) is described through instead. Safe to
|
|
98
|
-
# walk
|
|
99
|
-
# unconditionally — `Plan` only ever reads the
|
|
100
|
-
#
|
|
98
|
+
# walk every meta-domain aggregate's own `.entities`
|
|
99
|
+
# unconditionally — `Plan` only ever reads the meta-
|
|
100
|
+
# domain's own self-description (`Plan.for(MetaValidator.
|
|
101
101
|
# grammar_registry)`), which never declares a generic,
|
|
102
|
-
# nameless entity of its own the way a
|
|
102
|
+
# nameless entity of its own the way a real domain's
|
|
103
103
|
# `LedgerEntry` is; the only entities the meta-domain
|
|
104
104
|
# itself ever declares are exactly the three this ADR
|
|
105
|
-
# names. `entity_owned: true` records
|
|
105
|
+
# names. `entity_owned: true` records why this is a
|
|
106
106
|
# category at all — the real runtime has no top-level
|
|
107
|
-
# aggregate named "Member" to dispatch a
|
|
108
|
-
# any more, so the judge has to build a
|
|
107
|
+
# aggregate named "Member" to dispatch a bare verb into
|
|
108
|
+
# any more, so the judge has to build a dotted one instead
|
|
109
109
|
# (see `Judge#verb_for`).
|
|
110
110
|
#
|
|
111
|
-
#
|
|
111
|
+
# Recurses — `Dispatch` nests inside `Handler`, which nests
|
|
112
112
|
# inside `ProcessManager`, two levels deep, not one. Each
|
|
113
|
-
# nested entity's own `parent` names the
|
|
113
|
+
# nested entity's own `parent` names the direct owner it was
|
|
114
114
|
# actually found under (Dispatch's is "Handler", not
|
|
115
115
|
# "ProcessManager") — `read`'s own `owner:` argument already
|
|
116
116
|
# takes whichever name is passed, so walking one level deeper
|
|
@@ -125,10 +125,10 @@ module Hecks
|
|
|
125
125
|
def names = @categories.keys
|
|
126
126
|
|
|
127
127
|
# Every verb the language declares, spelled as the judge would
|
|
128
|
-
# dispatch it. S17, ADR 0026 — an
|
|
128
|
+
# dispatch it. S17, ADR 0026 — an entity-owned category (its
|
|
129
129
|
# own `entity_owned` flag) has no real top-level aggregate the
|
|
130
|
-
# runtime can route a
|
|
131
|
-
# spelled
|
|
130
|
+
# runtime can route a bare verb into any more, so it is
|
|
131
|
+
# spelled dotted here too — `Bluebook::ValueObject.Member.
|
|
132
132
|
# Declare`, `Bluebook::ProcessManager.Handler.Dispatch.Bind` —
|
|
133
133
|
# matching `Judge#verb_for`/`#dotted_prefix`'s own build
|
|
134
134
|
# exactly (recursing the same way, for the same reason: an
|
|
@@ -147,8 +147,8 @@ module Hecks
|
|
|
147
147
|
# found entity's own `.entities` in turn — S17, ADR 0026's
|
|
148
148
|
# two-level chain (`Dispatch`, inside `Handler`, inside
|
|
149
149
|
# `ProcessManager`). `owner` is passed down explicitly rather
|
|
150
|
-
# than re-derived, because it names whichever construct
|
|
151
|
-
# call actually found the entity under — the
|
|
150
|
+
# than re-derived, because it names whichever construct this
|
|
151
|
+
# call actually found the entity under — the direct parent, not
|
|
152
152
|
# the root.
|
|
153
153
|
def add_nested_entities(owner)
|
|
154
154
|
owner.entities.each do |entity|
|
|
@@ -159,9 +159,9 @@ module Hecks
|
|
|
159
159
|
end
|
|
160
160
|
end
|
|
161
161
|
|
|
162
|
-
#
|
|
162
|
+
# The full dotted prefix a category's own verbs hang off —
|
|
163
163
|
# mirrors `Judge#dotted_prefix` exactly (S17, ADR 0026): the
|
|
164
|
-
# plain name for an ordinary category, or its
|
|
164
|
+
# plain name for an ordinary category, or its parent's own
|
|
165
165
|
# prefix with this category's name appended, for an entity-
|
|
166
166
|
# owned one, recursing because the parent may itself be
|
|
167
167
|
# entity-owned.
|
|
@@ -172,28 +172,28 @@ module Hecks
|
|
|
172
172
|
"#{dotted_prefix(found.parent)}.#{name}"
|
|
173
173
|
end
|
|
174
174
|
|
|
175
|
-
# `owner:`/`entity_owned:` — S17, ADR 0026. An
|
|
175
|
+
# `owner:`/`entity_owned:` — S17, ADR 0026. An aggregate-level
|
|
176
176
|
# creating command carries its own parent as a `reference_to`
|
|
177
177
|
# argument (read via `parent_reference_of` below), the same
|
|
178
|
-
# way it always has. An
|
|
178
|
+
# way it always has. An entity-level one never does — `entity
|
|
179
179
|
# "Member" do ... end`'s own creating command reaches its
|
|
180
|
-
# parent through the
|
|
180
|
+
# parent through the dotted call itself (`ValueObject.Member.
|
|
181
181
|
# Declare`), the same reason an ordinary entity's own commands
|
|
182
182
|
# never declare `reference_to` either (entity.md's own
|
|
183
|
-
# reference page states this). So the
|
|
183
|
+
# reference page states this). So the owning aggregate's name
|
|
184
184
|
# is passed in directly here, by the caller who already knows
|
|
185
185
|
# it (the same `.entities` walk that found this node), rather
|
|
186
186
|
# than derived from an argument that was never going to be
|
|
187
187
|
# there.
|
|
188
188
|
def read(aggregate, owner: nil, entity_owned: false)
|
|
189
|
-
# An
|
|
189
|
+
# An entity-owned category has no creating command of its own to find.
|
|
190
190
|
# `creating_command` tests `command.references.nil?` — the same test
|
|
191
|
-
# a
|
|
191
|
+
# a real entity's own commands pass too, since `entity "Member" do
|
|
192
192
|
# command "Pair" ... end end` never writes `reference_to` (an
|
|
193
193
|
# entity's commands never do — banking's own LedgerEntry.Amend
|
|
194
194
|
# doesn't either). Calling it here would have it seize on Member's
|
|
195
|
-
# own "Pair" and call
|
|
196
|
-
# a Member is created by `ValueObject.Member`, its
|
|
195
|
+
# own "Pair" and call that the creating command, which it is not:
|
|
196
|
+
# a Member is created by `ValueObject.Member`, its owner's own bare
|
|
197
197
|
# append command, the same way a real LedgerEntry is created by
|
|
198
198
|
# `Account.LogEntry`, never by a dotted verb of its own.
|
|
199
199
|
declare = entity_owned ? nil : declaration_command(aggregate)
|
|
@@ -211,11 +211,11 @@ module Hecks
|
|
|
211
211
|
alternates: alternates_in(rest),
|
|
212
212
|
setters: setters_in(rest),
|
|
213
213
|
sealers: sealers_in(rest),
|
|
214
|
-
#
|
|
214
|
+
# Every command, not `rest` — the creating command carries the parent
|
|
215
215
|
# link, which is the most common reference of all.
|
|
216
216
|
references: references_in(aggregate.commands),
|
|
217
|
-
#
|
|
218
|
-
# than restated. The judge has to know a record's id
|
|
217
|
+
# How the category names its records, read from the language rather
|
|
218
|
+
# than restated. The judge has to know a record's id before it
|
|
219
219
|
# dispatches, because the children it walks next carry it as their
|
|
220
220
|
# parent — so it derives the same join the runtime will, off the same
|
|
221
221
|
# declaration. It used to be a branch per category, and a branch that
|
|
@@ -261,7 +261,7 @@ module Hecks
|
|
|
261
261
|
aggregate.attributes.find(&:reference?)
|
|
262
262
|
end
|
|
263
263
|
|
|
264
|
-
# What the creating command sets directly.
|
|
264
|
+
# What the creating command sets directly. Every reference
|
|
265
265
|
# argument is dropped, not just the parent link: a reference is
|
|
266
266
|
# not a field. Command.Declare carries `entity_id` as well as
|
|
267
267
|
# the parent `aggregate` reference, because an entity declares
|
|
@@ -279,7 +279,7 @@ module Hecks
|
|
|
279
279
|
Array(command.mutations).each do |mutation|
|
|
280
280
|
next unless mutation.op == :append
|
|
281
281
|
|
|
282
|
-
#
|
|
282
|
+
# First wins, not last. Two commands can append to the same list —
|
|
283
283
|
# Aggregate.Attribute and Aggregate.Reference both extend `attributes`,
|
|
284
284
|
# because a reference's type is not a value object and cannot go
|
|
285
285
|
# through the same verb. Overwriting would have let the one declared
|
|
@@ -290,7 +290,7 @@ module Hecks
|
|
|
290
290
|
end
|
|
291
291
|
end
|
|
292
292
|
|
|
293
|
-
# The appenders
|
|
293
|
+
# The appenders displaced by first-wins — Aggregate.Reference behind
|
|
294
294
|
# Aggregate.Attribute. The walk reaches them by reading the row, not the
|
|
295
295
|
# plan, but they are still verbs the language declares and the coverage
|
|
296
296
|
# gate has to see them.
|
|
@@ -311,7 +311,7 @@ module Hecks
|
|
|
311
311
|
end
|
|
312
312
|
end
|
|
313
313
|
|
|
314
|
-
# Commands that
|
|
314
|
+
# Commands that set rather than append. Lifecycle sets two targets at once,
|
|
315
315
|
# so a setter is keyed by its verb and carries every target it writes.
|
|
316
316
|
def setters_in(commands)
|
|
317
317
|
commands.filter_map do |command|
|
|
@@ -324,7 +324,7 @@ module Hecks
|
|
|
324
324
|
end
|
|
325
325
|
end
|
|
326
326
|
|
|
327
|
-
# Commands that change nothing — they exist to be
|
|
327
|
+
# Commands that change nothing — they exist to be refused. Aggregate.Seal is
|
|
328
328
|
# the whole-document check: dispatched once everything is declared, carrying
|
|
329
329
|
# only givens. A category with no sealer simply has no such rule.
|
|
330
330
|
def sealers_in(commands)
|
|
@@ -3,7 +3,7 @@ module Hecks
|
|
|
3
3
|
module MetaValidator
|
|
4
4
|
# Offers a built .port to the language that describes ports.
|
|
5
5
|
#
|
|
6
|
-
# A port is a
|
|
6
|
+
# A port is a sibling of a bluebook, the same shape WorldJudge already
|
|
7
7
|
# is one level over — its own file, its own door, judged through its
|
|
8
8
|
# own self-hosted language (port.bluebook) rather than left as a plain
|
|
9
9
|
# Ruby struct nothing checks. Whole-project table-unification survey,
|
|
@@ -34,7 +34,7 @@ module Hecks
|
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
def send_to(verb, label, **payload)
|
|
37
|
-
offer(label) { @runtime.
|
|
37
|
+
offer(label) { @runtime.dispatch_flat(verb, args(payload)) }
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
def judge!
|
|
@@ -6,10 +6,10 @@ module Hecks
|
|
|
6
6
|
# The language now spells its fields exactly as the IR spells them, so the
|
|
7
7
|
# judge reads almost everything straight through: `command.givens`,
|
|
8
8
|
# `value_object.invariants`, `read_model.aggregate_heads`. What remains here
|
|
9
|
-
# is not naming drift — it is places where the IR's
|
|
9
|
+
# is not naming drift — it is places where the IR's shape differs from the
|
|
10
10
|
# language's, and no amount of renaming would close that:
|
|
11
11
|
#
|
|
12
|
-
# transitions one declaration expands to
|
|
12
|
+
# transitions one declaration expands to several rows, because `from`
|
|
13
13
|
# may be a list of states
|
|
14
14
|
# value_objects the IR holds objects ; the language holds their names
|
|
15
15
|
# normalisations not on the bluebook at all — they come from the canonical
|
|
@@ -18,11 +18,11 @@ module Hecks
|
|
|
18
18
|
# lifecycle one IR object feeding two separate fields
|
|
19
19
|
#
|
|
20
20
|
# Everything in this file is a difference in shape. If something here is
|
|
21
|
-
# only a difference in
|
|
21
|
+
# only a difference in name, it is in the wrong file: rename the language.
|
|
22
22
|
module Readings
|
|
23
23
|
# A list the walk is about to offer, as rows it can shape into dispatches.
|
|
24
24
|
#
|
|
25
|
-
#
|
|
25
|
+
# From the table. This was nine hand-written cases keyed "Category.list", and
|
|
26
26
|
# every one of them was a fact `Assembly::Contracts` is the right place to
|
|
27
27
|
# keep: which shaper turns this list into rows. A list with no shaper reads
|
|
28
28
|
# straight off the node, which is most of them.
|
|
@@ -34,17 +34,17 @@ module Hecks
|
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
# A where-clause is read through its own to_h, which is where the IR spells a
|
|
37
|
-
# symbol argument as ":ceiling". Reading the
|
|
37
|
+
# symbol argument as ":ceiling". Reading the object instead lost the colon,
|
|
38
38
|
# and nothing downstream could tell an argument from a literal of the same
|
|
39
39
|
# name.
|
|
40
40
|
def where_rows(node) = Array(node.wheres).map(&:to_h)
|
|
41
41
|
|
|
42
|
-
# The language holds a value object's
|
|
42
|
+
# The language holds a value object's name here ; the IR holds the object.
|
|
43
43
|
def value_object_names(node) = node.value_objects.map { |shape| { name: shape.hecks_name } }
|
|
44
44
|
|
|
45
|
-
#
|
|
45
|
+
# An identity is a list of parts, so it is offered one part at a time — the
|
|
46
46
|
# same way attributes and transitions are. The IR holds the paths ; the
|
|
47
|
-
# language holds a row per path, and the
|
|
47
|
+
# language holds a row per path, and the order between them is the whole
|
|
48
48
|
# meaning, because the identity is their join.
|
|
49
49
|
def identity_rows(node) = node.identity_paths.map { |path| { value: path } }
|
|
50
50
|
|
|
@@ -53,10 +53,10 @@ module Hecks
|
|
|
53
53
|
# argument became indistinguishable from one carrying a literal string.
|
|
54
54
|
def with_spec_rows(node) = pair_rows(node.to_h[:with_spec])
|
|
55
55
|
|
|
56
|
-
#
|
|
56
|
+
# The same read, one level in — `compensates` folds `DispatchSpec`
|
|
57
57
|
# into the language's own `compensates_command_name`/
|
|
58
58
|
# `compensates_with_spec` (`Assembly::Contracts`' own comment on
|
|
59
|
-
# "Dispatch"), so its
|
|
59
|
+
# "Dispatch"), so its own with_spec pairs live nested one hash
|
|
60
60
|
# down from where `with_spec_rows` looks. `&.dig(...)` — no
|
|
61
61
|
# compensation at all is not an error, it is `pair_rows(nil)`, empty.
|
|
62
62
|
def compensates_with_spec_rows(node) = pair_rows(node.to_h[:compensates]&.dig(:with_spec))
|
|
@@ -70,7 +70,7 @@ module Hecks
|
|
|
70
70
|
def normalisation_table(_node) = normalisation_rows
|
|
71
71
|
|
|
72
72
|
# `lifecycle :status do transition "Retire" => "retired", from: ["issued", "active"] end`
|
|
73
|
-
# is
|
|
73
|
+
# is one declaration and two transitions. Offering it once would leave the
|
|
74
74
|
# second unjudged, which is the whole failure this judge exists to avoid.
|
|
75
75
|
def transition_rows(node)
|
|
76
76
|
lifecycle = node.respond_to?(:lifecycle) ? node.lifecycle : nil
|
|
@@ -84,17 +84,17 @@ module Hecks
|
|
|
84
84
|
end
|
|
85
85
|
end
|
|
86
86
|
|
|
87
|
-
# An
|
|
87
|
+
# An open map — a member's fields, a dispatch's argument bindings — has no
|
|
88
88
|
# value object that can hold it, so each entry becomes its own row. This is
|
|
89
89
|
# why Member and Dispatch are roots in the language rather than lists.
|
|
90
90
|
def pair_rows(map)
|
|
91
91
|
Array(map&.to_h).map { |key, value| { key: key, value: value } }
|
|
92
92
|
end
|
|
93
93
|
|
|
94
|
-
#
|
|
94
|
+
# Every specification option an ask carries, flattened to rows.
|
|
95
95
|
#
|
|
96
96
|
# `offset`, `cursor`, `nulls`, `authorize` and `inspect_query` are
|
|
97
|
-
# five options, one compound (authorize names a policy
|
|
97
|
+
# five options, one compound (authorize names a policy and a
|
|
98
98
|
# tenant). `extra_options_to_h` already spells every one of them
|
|
99
99
|
# and drops the absent ones, so this reads that rather than
|
|
100
100
|
# naming them here — a sixth option needs no change on either
|
|
@@ -103,18 +103,18 @@ module Hecks
|
|
|
103
103
|
# `filters: true` adds a read model's wheres, order_by and limit —
|
|
104
104
|
# `at` tells repeated rows apart, so two wheres do not collapse.
|
|
105
105
|
#
|
|
106
|
-
#
|
|
106
|
+
# The language may hold more than `to_h` carries, and this is where that
|
|
107
107
|
# mattered. Until 2026-08-11, `ReadModel#to_h` omitted all three —
|
|
108
108
|
# `extra_options_to_h` rejects them by name, still does — so a read
|
|
109
109
|
# model's filtering had never been in the wire contract, and I first
|
|
110
110
|
# read that as a wall: if the wire cannot carry it, the language cannot
|
|
111
111
|
# hold it, and a graph assembled from the language must lose it.
|
|
112
112
|
#
|
|
113
|
-
# That was the wrong conclusion. `to_h` is a
|
|
114
|
-
# is the
|
|
113
|
+
# That was the wrong conclusion. `to_h` is a projection ; the language
|
|
114
|
+
# is the source. They have to agree about everything
|
|
115
115
|
# to_h spells, not about everything the language knows. Held as option
|
|
116
116
|
# rows, the filters survived the round trip regardless of whether the
|
|
117
|
-
# wire carried them too — which is exactly why, when a
|
|
117
|
+
# wire carried them too — which is exactly why, when a later task
|
|
118
118
|
# (Rust read-model codegen) needed `wheres`/`order_by`/`limit` on the
|
|
119
119
|
# wire for an unrelated reason, `ReadModel#to_h` could be extended to
|
|
120
120
|
# spell them (the same mechanism `Query#to_h` already used) without
|
|
@@ -153,8 +153,8 @@ module Hecks
|
|
|
153
153
|
end
|
|
154
154
|
end
|
|
155
155
|
|
|
156
|
-
# A mutation is
|
|
157
|
-
# field/kind/source triple — and an append binds
|
|
156
|
+
# A mutation is one declaration, but the language's Change holds a single
|
|
157
|
+
# field/kind/source triple — and an append binds several fields at once
|
|
158
158
|
# (`append: { name: :name, amount: :amount }`). So an append is offered
|
|
159
159
|
# once per binding, and each one is judged.
|
|
160
160
|
#
|
|
@@ -164,7 +164,7 @@ module Hecks
|
|
|
164
164
|
def mutation_rows(node)
|
|
165
165
|
Array(node.mutations).flat_map do |mutation|
|
|
166
166
|
# `:delegate`/`:corrects` (CommandBuilder#delegates_to's and
|
|
167
|
-
# #corrects_impl's own comments) ride the
|
|
167
|
+
# #corrects_impl's own comments) ride the same multi-binding
|
|
168
168
|
# shape `:append` does — `with: {...}`/the assembled
|
|
169
169
|
# `as:`/`reason:`/`reverses:` hash is a field map, same as
|
|
170
170
|
# append's own `fields:`.
|
|
@@ -174,7 +174,7 @@ module Hecks
|
|
|
174
174
|
# Spelled the way Mutation#appended_fields spells it, because
|
|
175
175
|
# Assembly::Marks reads this row back through the same reader it
|
|
176
176
|
# reads that field with. `then_set :marks, append: { direction:
|
|
177
|
-
# "out" }` binds a
|
|
177
|
+
# "out" }` binds a literal, and storing it raw made it
|
|
178
178
|
# indistinguishable from an argument called out.
|
|
179
179
|
{ target: mutation.target, op: mutation.op, field: field,
|
|
180
180
|
kind: argument.is_a?(Symbol) ? "argument" : "literal",
|
|
@@ -215,7 +215,7 @@ module Hecks
|
|
|
215
215
|
[]
|
|
216
216
|
end
|
|
217
217
|
|
|
218
|
-
# What the
|
|
218
|
+
# What the bluebook calls a node, whichever kind of thing the node is.
|
|
219
219
|
#
|
|
220
220
|
# This used to sniff — `respond_to?(:hecks_name) ? … : node.name` — because
|
|
221
221
|
# only value objects had crossed over. Every construct answers now, so
|
|
@@ -225,7 +225,7 @@ module Hecks
|
|
|
225
225
|
|
|
226
226
|
# One field of a Declare payload. Mostly a reader of the same name — the
|
|
227
227
|
# exceptions are fields the IR keeps somewhere else, or not at all.
|
|
228
|
-
#
|
|
228
|
+
# Read from the table, not from a branch per category.
|
|
229
229
|
#
|
|
230
230
|
# These were eight hand-written cases — `Entity.owner`, `Member.shape`, two
|
|
231
231
|
# lifecycle members twice over, and three of a query's — each one restating
|
|
@@ -237,7 +237,7 @@ module Hecks
|
|
|
237
237
|
return declared_name(node) if field == :name
|
|
238
238
|
|
|
239
239
|
contract = Assembly.contract(category)
|
|
240
|
-
# A setter names its target as a
|
|
240
|
+
# A setter names its target as a string and a Declare field arrives a Symbol,
|
|
241
241
|
# so the lookup keys on a Symbol either way. The case statement this replaced
|
|
242
242
|
# was type-blind because it interpolated ; a Hash is not.
|
|
243
243
|
named = field.to_sym
|
|
@@ -246,19 +246,19 @@ module Hecks
|
|
|
246
246
|
object, member = contract.folded(named)
|
|
247
247
|
return through(node, object, member) if member
|
|
248
248
|
|
|
249
|
-
# `limit` is a language field
|
|
249
|
+
# `limit` is a language field and an object in the IR — `Array(an_object)`
|
|
250
250
|
# wraps rather than destructures, so offering it stored
|
|
251
251
|
# "#<struct LimitSpec value=3>".
|
|
252
252
|
return node.limit&.to_h&.fetch(:value, nil) if "#{category}.#{field}" == "Query.limit"
|
|
253
253
|
|
|
254
|
-
# `provenance from: {...}` is a
|
|
254
|
+
# `provenance from: {...}` is a hash offered into a text field, and
|
|
255
255
|
# handing it over raw let the runtime's own coercion spell it — which
|
|
256
256
|
# meant Ruby's `Hash#to_s`, whose spelling changed under us between
|
|
257
257
|
# 3.3 and 3.4. Encoded here, the same way `default:` already is and the
|
|
258
258
|
# same way Shapes#provenance reads it back.
|
|
259
259
|
return encode_literal(node.provenance) if field == :provenance
|
|
260
260
|
|
|
261
|
-
# `identified_by` is no longer a
|
|
261
|
+
# `identified_by` is no longer a field of any declaration — it is a list,
|
|
262
262
|
# filled by Identify one part at a time, so it is read through `identity_rows`
|
|
263
263
|
# like every other list rather than special-cased here. What this branch
|
|
264
264
|
# existed to protect is now structural : a path cannot come back as its head,
|
|
@@ -268,7 +268,7 @@ module Hecks
|
|
|
268
268
|
end
|
|
269
269
|
|
|
270
270
|
# One member of the object a field folds into. `to_h` first, because the
|
|
271
|
-
# member names are the ones the IR
|
|
271
|
+
# member names are the ones the IR spells — a Lifecycle's `default`, an
|
|
272
272
|
# OrderBy's `direction` — and reading the object raw is how a colon or a type
|
|
273
273
|
# goes missing.
|
|
274
274
|
def through(node, object, member)
|
|
@@ -279,7 +279,7 @@ module Hecks
|
|
|
279
279
|
end
|
|
280
280
|
|
|
281
281
|
# What a setting command writes. A setter whose source is absent is not
|
|
282
|
-
# dispatched at all —
|
|
282
|
+
# dispatched at all — absent is not empty, and offering "" would turn every
|
|
283
283
|
# "if you declare it, declare something" rule into "you must declare it".
|
|
284
284
|
def setter_value(category, node, target)
|
|
285
285
|
# `rows` folds into `closed_set` and `members` between them, with no single
|
|
@@ -292,7 +292,7 @@ module Hecks
|
|
|
292
292
|
node.respond_to?(target) ? node.public_send(target) : nil
|
|
293
293
|
end
|
|
294
294
|
|
|
295
|
-
# Only a
|
|
295
|
+
# Only a declared closed set has a row count. An empty one is the defect,
|
|
296
296
|
# so `rows` must stay absent rather than arrive as zero.
|
|
297
297
|
def closed_set_size(node)
|
|
298
298
|
return nil unless node.respond_to?(:closed_set?) && node.closed_set?
|
|
@@ -300,7 +300,7 @@ module Hecks
|
|
|
300
300
|
Array(node.members).size
|
|
301
301
|
end
|
|
302
302
|
|
|
303
|
-
# `Reference<Customer>` is an IR
|
|
303
|
+
# `Reference<Customer>` is an IR encoding, not a domain fact. The fact is
|
|
304
304
|
# that the attribute points at Customer's head — so the language is offered
|
|
305
305
|
# that head's ID, and resolution does the rest. Encoding and decoding both
|
|
306
306
|
# live here, because this is where the IR's shape differs from the
|
|
@@ -308,24 +308,24 @@ module Hecks
|
|
|
308
308
|
def points_at(row, aggregate_id)
|
|
309
309
|
return nil unless row.reference?
|
|
310
310
|
|
|
311
|
-
#
|
|
311
|
+
# The chapter this head is in, and the head it points at — which is exactly
|
|
312
312
|
# how an aggregate is identified, so it is built the same way rather than
|
|
313
|
-
# spelled again with a separator of its own. This is dispatched as a
|
|
314
|
-
#
|
|
315
|
-
# `repository.find` against the target Aggregate-within-Meta record's
|
|
316
|
-
# stored id — so it
|
|
313
|
+
# spelled again with a separator of its own. This is dispatched as a real
|
|
314
|
+
# reference value (`Aggregate.Reference`'s `points_at:`), resolved by
|
|
315
|
+
# `repository.find` against the target Aggregate-within-Meta record's own
|
|
316
|
+
# stored id — so it must equal what that record's identity actually
|
|
317
317
|
# derives, not a wire-format spelling. `reference_type`, below, is the
|
|
318
318
|
# separate later reader that un-derives it back into "Reference<X>".
|
|
319
319
|
Naming.identity([aggregate_id.split(Naming::IDENTITY_JOIN).first, row.type.target_name])
|
|
320
320
|
end
|
|
321
321
|
|
|
322
|
-
# A
|
|
322
|
+
# A literal, written so it can be read back exactly.
|
|
323
323
|
#
|
|
324
324
|
# The language holds a default and a literal mutation source as text, and
|
|
325
325
|
# `to_s` threw the type away: 0.0 came back "0.0", and `{ value: "good" }`
|
|
326
326
|
# came back its inspect string with nowhere to say it had been a hash. The
|
|
327
327
|
# language already stores code as text — `canonical: "cents >= 0"` — so an
|
|
328
|
-
# encoding is in keeping; it simply has to be
|
|
328
|
+
# encoding is in keeping; it simply has to be self-describing. That rule is
|
|
329
329
|
# now Hecks::Literal's, stated once and shared with every other
|
|
330
330
|
# to_h-bound literal field ; Shapes#decode_literal reads it back.
|
|
331
331
|
#
|
|
@@ -334,23 +334,23 @@ module Hecks
|
|
|
334
334
|
def encode_literal(value) = value.nil? ? nil : Literal.render(value)
|
|
335
335
|
|
|
336
336
|
# The way back out: an aggregate id becomes the type the IR spells. The
|
|
337
|
-
# id is a
|
|
337
|
+
# id is a join of chapter + name (Naming::IDENTITY_JOIN, the same join
|
|
338
338
|
# `points_at` built it with, not the "::" a real bluebook's own type
|
|
339
339
|
# names never carry) ; the wire format wants only the bare name.
|
|
340
340
|
def reference_type(points_at_id) = "Reference<#{points_at_id.to_s.split(Naming::IDENTITY_JOIN).last}>"
|
|
341
341
|
|
|
342
342
|
# One value out of a row, named by the value object's field.
|
|
343
343
|
def row_value(row, field)
|
|
344
|
-
# A Hash
|
|
344
|
+
# A Hash first. Hash answers to `key` (Hash#key(value)) and to `value` on
|
|
345
345
|
# some rows, so asking respond_to? before checking for a Hash reads a
|
|
346
346
|
# member pair through entirely the wrong method.
|
|
347
347
|
return row[field] if row.is_a?(Hash)
|
|
348
348
|
return row.public_send(field) if row.respond_to?(field)
|
|
349
|
-
# A Struct answers to [] but
|
|
349
|
+
# A Struct answers to [] but raises for a member it does not have, so it
|
|
350
350
|
# is read through to_h — a field the row simply lacks reads as absent.
|
|
351
351
|
return row.to_h[field] if row.respond_to?(:to_h) && !row.is_a?(String)
|
|
352
352
|
|
|
353
|
-
# A bare scalar row — `emits` is a list of event
|
|
353
|
+
# A bare scalar row — `emits` is a list of event names, and the
|
|
354
354
|
# Announcement value object has to call that string something.
|
|
355
355
|
row
|
|
356
356
|
end
|