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,32 +1,32 @@
|
|
|
1
1
|
module Hecks
|
|
2
2
|
module Bluebook
|
|
3
3
|
module MetaValidator
|
|
4
|
-
# A bluebook rebuilt
|
|
4
|
+
# A bluebook rebuilt from the meta-domain, in the shape the builder produces.
|
|
5
5
|
#
|
|
6
6
|
# This is the second half of the claim at the top of bluebook.bluebook —
|
|
7
7
|
# "loading a domain becomes dispatching commands into this meta-domain ; the
|
|
8
8
|
# IR it stores must equal the IR the DSL builder produces". The judge is the
|
|
9
9
|
# first half. This reads the records back and assembles `to_h`.
|
|
10
10
|
#
|
|
11
|
-
# It is the
|
|
11
|
+
# It is the inverse of the walk and shares its plan: the walk reads a node's
|
|
12
12
|
# lists through the command that appends to each, and this reads them back out
|
|
13
13
|
# of the rows those commands wrote. The retired `experiment/replay.rb` needed
|
|
14
14
|
# 420 hand-written lines because the dispatch half was hand-written too; there
|
|
15
15
|
# is nothing to hand-write when both directions are one table.
|
|
16
16
|
#
|
|
17
|
-
# This file is the
|
|
17
|
+
# This file is the traversal. The hashes at its tips, and the encodings they
|
|
18
18
|
# undo, are in Shapes.
|
|
19
19
|
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
20
|
+
# It reads level by level, through `DeclaredIn`, and not through the read
|
|
21
|
+
# model — which is the difference between a reconstruction that can be the
|
|
22
|
+
# source and one that can only be a check.
|
|
23
23
|
#
|
|
24
24
|
# `Meta.whole_bluebook` gathers a chapter in a single read, and it sorts:
|
|
25
25
|
# `ReadModelInterpreter#matching` ends `.sort_by(&:id)` deliberately, because
|
|
26
26
|
# a store's iteration order is an accident, and a read model returning store
|
|
27
27
|
# order would let that accident leak into an answer.
|
|
28
28
|
# Right for a read model, fatal here — the order a bluebook declares its
|
|
29
|
-
# commands in is a
|
|
29
|
+
# commands in is a fact about the source, and the IR is a contract field for
|
|
30
30
|
# field and index for index ; the export carries that order verbatim.
|
|
31
31
|
# `DeclaredIn` preserves it (spec/executes_spec says so), so this asks each
|
|
32
32
|
# level for its own children rather than filtering one sorted gather.
|
|
@@ -35,7 +35,7 @@ module Hecks
|
|
|
35
35
|
# Plan the walk dispatches from — so the two directions really are one table,
|
|
36
36
|
# which is what the header above has always claimed.
|
|
37
37
|
#
|
|
38
|
-
#
|
|
38
|
+
# What it cannot rebuild matters as much as what it can, and
|
|
39
39
|
# spec/round_trip_spec pins the difference as an exact set: a field the language
|
|
40
40
|
# does not hold appears there as a named gap, and a field it stops holding
|
|
41
41
|
# appears as a failure.
|
|
@@ -60,6 +60,7 @@ module Hecks
|
|
|
60
60
|
classification: text(@chapter[:classification]),
|
|
61
61
|
formerly_known_as: text(@chapter[:formerly_known_as]),
|
|
62
62
|
attaches_to: attached_contexts(@chapter),
|
|
63
|
+
provides: provisions(@chapter),
|
|
63
64
|
aggregates: declared("Aggregate", chapter_id).map { |row| aggregate(row) },
|
|
64
65
|
read_models: declared("ReadModel", chapter_id).map { |row| read_model(row) },
|
|
65
66
|
policies: declared("Policy", chapter_id).map { |row| policy(row) },
|
|
@@ -71,14 +72,14 @@ module Hecks
|
|
|
71
72
|
|
|
72
73
|
def chapter_id = @chapter[:id].to_s
|
|
73
74
|
|
|
74
|
-
# Everything
|
|
75
|
+
# Everything declared in one parent, in the order it was declared. The key
|
|
75
76
|
# is the one the language's own creating command carries, read from Plan.
|
|
76
77
|
def declared(category, parent_id)
|
|
77
78
|
key = @plan.category(category).parent_key
|
|
78
79
|
@runtime.query("Bluebook::#{category}.DeclaredIn", key.to_sym => { value: parent_id.to_s })
|
|
79
80
|
end
|
|
80
81
|
|
|
81
|
-
#
|
|
82
|
+
# One declaration, built from the contract.
|
|
82
83
|
#
|
|
83
84
|
# There were eleven methods here, one per category, each spelling out the same
|
|
84
85
|
# keys `Assembly::Contracts` already names — which is the shape the judge used
|
|
@@ -126,14 +127,20 @@ module Hecks
|
|
|
126
127
|
|
|
127
128
|
def pairs(with) = Array(with).map { |binding| [text(binding[:key]), text(binding[:value])] }
|
|
128
129
|
|
|
129
|
-
#
|
|
130
|
+
# The parts, in the order they went in, because the identity is their join
|
|
130
131
|
# and a join read out of order names a different record.
|
|
131
132
|
def identity_paths(row) = Array(row[:identified_by]).map { |part| text(part[:value]).to_s }
|
|
132
133
|
|
|
133
|
-
#
|
|
134
|
+
# The contexts one chapter names itself onto, in the order they were
|
|
134
135
|
# attached — same shape identity_paths reads back, one level up.
|
|
135
136
|
def attached_contexts(row) = Array(row[:attaches_to]).map { |part| text(part[:value]).to_s }
|
|
136
137
|
|
|
138
|
+
def provisions(row)
|
|
139
|
+
Array(row[:provides]).map do |part|
|
|
140
|
+
{ capability: text(part[:capability]).to_s, key: text(part[:key]).to_s, verb: text(part[:verb]).to_s }
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
137
144
|
# Every cell of the meta-domain is a single-field value object, so a row
|
|
138
145
|
# arrives holding Values rather than Strings.
|
|
139
146
|
def text(cell)
|
|
@@ -143,19 +150,19 @@ module Hecks
|
|
|
143
150
|
cell
|
|
144
151
|
end
|
|
145
152
|
|
|
146
|
-
# An aggregate's
|
|
153
|
+
# An aggregate's own verbs and asks — the ones no entity declared. Both carry
|
|
147
154
|
# the parent link either way, because that is the head the reference resolves
|
|
148
155
|
# against, so the entity ones have to be told apart by `entity_id`. Rejecting
|
|
149
|
-
# from an
|
|
156
|
+
# from an ordered read keeps the order.
|
|
150
157
|
def own(category, aggregate_id)
|
|
151
158
|
declared(category, aggregate_id).select { |row| text(row[:entity_id]).to_s == "" }
|
|
152
159
|
end
|
|
153
160
|
|
|
154
161
|
# A piece's own verbs and asks. There is no `DeclaredIn` keyed by entity, so
|
|
155
162
|
# this reads the aggregate's — in declaration order — and keeps the ones that
|
|
156
|
-
# name this piece. `row[:aggregate]` — an
|
|
163
|
+
# name this piece. `row[:aggregate]` — an entity row's own `reference_to
|
|
157
164
|
# Aggregate` (bare, no `_id` since ADR 0025) — not `entity_id`, which
|
|
158
|
-
#
|
|
165
|
+
# stays suffixed below : that one is Command/Query's own explicit `as:`,
|
|
159
166
|
# never touched by the rename.
|
|
160
167
|
def within(category, row)
|
|
161
168
|
declared(category, text(row[:aggregate]))
|
|
@@ -172,7 +179,7 @@ module Hecks
|
|
|
172
179
|
attributes: Array(row[:attributes]).map { |field| attribute(field, id) },
|
|
173
180
|
value_objects: declared("ValueObject", id).map { |shape| value_object(shape) },
|
|
174
181
|
commands: own("Command", id).map { |verb| command(verb) },
|
|
175
|
-
#
|
|
182
|
+
# The aggregate boundary, and the precondition a command may
|
|
176
183
|
# reference by name (S10, ADR 0025 — "Rules") — the same
|
|
177
184
|
# `rule` reader `command`'s own givens/ensures already use
|
|
178
185
|
# (Assembly::Contracts' generic `declaration()` path), read
|
|
@@ -195,19 +202,19 @@ module Hecks
|
|
|
195
202
|
def closed_set_of(row) = !text(row[:rows]).nil?
|
|
196
203
|
|
|
197
204
|
# A closed set's admitted rows. S17, ADR 0026 — Member is a genuine
|
|
198
|
-
#
|
|
205
|
+
# entity now (`entity "Member" do ... end`, nested under
|
|
199
206
|
# ValueObject), created by `ValueObject.Member` (an ordinary append,
|
|
200
207
|
# the same way `Account.LogEntry` creates a LedgerEntry) and mutated
|
|
201
208
|
# by its own dotted `ValueObject.Member.Pair`. Its data therefore
|
|
202
|
-
# lives
|
|
209
|
+
# lives inline on the value object's own dispatched state — same as
|
|
203
210
|
# any other entity list — not behind a separate `DeclaredIn` query:
|
|
204
211
|
# there is no such query any more, because there is no top-level
|
|
205
|
-
# "Member" aggregate left to hold one. Pairs are still an
|
|
212
|
+
# "Member" aggregate left to hold one. Pairs are still an open map,
|
|
206
213
|
# which no value object can hold, so they still come back one pair
|
|
207
214
|
# at a time.
|
|
208
215
|
def members_row(row) = members_of(row)
|
|
209
216
|
|
|
210
|
-
#
|
|
217
|
+
# The key is stringified, never the value — the same split
|
|
211
218
|
# `Bluebook::ValueObject#to_h`'s own `members:` emission makes
|
|
212
219
|
# (lib/hecks/bluebook/value_object.rb, L7 docs/audits/
|
|
213
220
|
# 2026-08-11-bug-triage.md). `Pair.value` is declared `String`
|
|
@@ -219,7 +226,7 @@ module Hecks
|
|
|
219
226
|
# on the side spec/round_trip_spec.rb compares straight against a
|
|
220
227
|
# fresh raw load (`Reconstruction.of` directly, no Assembly in
|
|
221
228
|
# between): `declared 84, read back "84"` the moment `to_h` stopped
|
|
222
|
-
# erasing it on the
|
|
229
|
+
# erasing it on the other side and this one kept erasing it alone.
|
|
223
230
|
def members_of(value_object_row)
|
|
224
231
|
Array(value_object_row[:members]).map do |member|
|
|
225
232
|
Array(member[:pairs]).map { |pair| [text(pair[:key]).to_s, text(pair[:value])] }
|
|
@@ -230,15 +237,15 @@ module Hecks
|
|
|
230
237
|
|
|
231
238
|
def query(row) = declaration("Query", row).merge(options_of(row))
|
|
232
239
|
|
|
233
|
-
#
|
|
234
|
-
# ("Entity", root_id)` returns
|
|
235
|
-
#
|
|
240
|
+
# Every direct entity of one owner — S17, ADR 0026. `declared
|
|
241
|
+
# ("Entity", root_id)` returns every entity sharing the same
|
|
242
|
+
# root aggregate, nested or not (Dispatch and Handler both carry
|
|
236
243
|
# `aggregate: process_manager_id`) — `owner` is the field that
|
|
237
244
|
# actually tells them apart : `Judge#nest_entities`'s own
|
|
238
245
|
# comment explains why it is the one to repurpose. Called with
|
|
239
246
|
# `owner_id == root_id` for an aggregate's own direct entities
|
|
240
247
|
# (Handler), and with `owner_id == some entity's own id` for
|
|
241
|
-
#
|
|
248
|
+
# that entity's own nested ones (Dispatch, owned by Handler).
|
|
242
249
|
def direct_entities(root_id, owner_id)
|
|
243
250
|
declared("Entity", root_id).select { |held| text(held[:owner]).to_s == owner_id.to_s }
|
|
244
251
|
end
|
|
@@ -251,25 +258,25 @@ module Hecks
|
|
|
251
258
|
# Symbol there — the IR was not uniform about it, and only a round trip
|
|
252
259
|
# ever said so.
|
|
253
260
|
identified_by: identity_paths(row),
|
|
254
|
-
# `text(row[:aggregate])` — the
|
|
261
|
+
# `text(row[:aggregate])` — the owning aggregate, the same one
|
|
255
262
|
# `Judge#owning_aggregate_ref` resolved this piece's own
|
|
256
263
|
# attribute types against on the way in, so reconstruction reads
|
|
257
264
|
# a value-object-typed attribute back the identical way an
|
|
258
265
|
# aggregate's own is (`Shapes#shape_field`'s own comment).
|
|
259
266
|
attributes: Array(row[:attributes]).map { |field| shape_field(field, text(row[:aggregate])) },
|
|
260
|
-
# ADR 0028 — the
|
|
267
|
+
# ADR 0028 — the same shape `aggregate(row)`'s own
|
|
261
268
|
# `preconditions:` reads two hand-typed methods up, read by
|
|
262
269
|
# hand for the identical reason: `entity(row)` is hand-typed
|
|
263
270
|
# too, unlike `command`/`value_object`/`query`.
|
|
264
271
|
preconditions: Array(row[:preconditions]).map { |held| rule(held) },
|
|
265
|
-
# Round 7 — the
|
|
272
|
+
# Round 7 — the same shape `aggregate(row)`'s own
|
|
266
273
|
# `invariants:` reads, one level down: a piece's own shape
|
|
267
274
|
# rule, checked against every instance of this piece.
|
|
268
275
|
invariants: Array(row[:invariants]).map { |held| rule(held) },
|
|
269
276
|
commands: within("Command", row).map { |verb| command(verb) },
|
|
270
277
|
queries: within("Query", row).map { |ask| query(ask) },
|
|
271
278
|
# S17, ADR 0026 — Dispatch, inside Handler : an entity's own
|
|
272
|
-
#
|
|
279
|
+
# nested entities, found the same way its own direct ones
|
|
273
280
|
# were one level up.
|
|
274
281
|
entities: direct_entities(text(row[:aggregate]), row[:id]).map { |piece| entity(piece) },
|
|
275
282
|
# An entity has its own state machine, and the language has held it all
|
|
@@ -301,7 +308,7 @@ module Hecks
|
|
|
301
308
|
# ordinary append, the same way `Account.LogEntry` creates a
|
|
302
309
|
# LedgerEntry) and mutated by its own dotted `ProcessManager.
|
|
303
310
|
# Handler.Dispatch`/`...Dispatch.Bind`. Its data therefore lives
|
|
304
|
-
#
|
|
311
|
+
# inline on the process manager's own dispatched state — same as
|
|
305
312
|
# any other entity list — not behind a separate `DeclaredIn`
|
|
306
313
|
# query : there is no such query any more, the same fix
|
|
307
314
|
# `Reconstruction#members_of` already made for Member.
|
|
@@ -311,25 +318,25 @@ module Hecks
|
|
|
311
318
|
end
|
|
312
319
|
|
|
313
320
|
# S17, ADR 0026 — Dispatch, one level further in : nested under
|
|
314
|
-
# Handler, its data lives inline on the
|
|
315
|
-
# was just handed (`row` here
|
|
321
|
+
# Handler, its data lives inline on the handler row this method
|
|
322
|
+
# was just handed (`row` here is one element of `handlers`,
|
|
316
323
|
# above), not behind any query either.
|
|
317
324
|
def handler(row)
|
|
318
325
|
declaration("Handler", row,
|
|
319
326
|
dispatches: Array(row[:dispatches]).map { |leg| dispatch(leg) })
|
|
320
327
|
end
|
|
321
328
|
|
|
322
|
-
# `compensates` —
|
|
329
|
+
# `compensates` — two flat fields on this same row
|
|
323
330
|
# (`process_manager.bluebook`'s own comment on `Dispatch` for
|
|
324
|
-
# why), assembled
|
|
331
|
+
# why), assembled by hand into the shape its own field actually
|
|
325
332
|
# is — `declaration()`'s generic per-field hash-build has no
|
|
326
333
|
# way to turn two cells into a second object, so this reads
|
|
327
334
|
# them directly and passes the result through `extra:`, the
|
|
328
335
|
# same seam `handler`/`process_manager` already use for a
|
|
329
336
|
# `:children` shape a flat Contract cannot describe.
|
|
330
337
|
# `compensates_command_name` absent means no compensation at
|
|
331
|
-
# all — a plain dispatch with nothing to undo. A
|
|
332
|
-
#
|
|
338
|
+
# all — a plain dispatch with nothing to undo. A plain hash, the
|
|
339
|
+
# same declaration shape `to_h` spells for everything else in
|
|
333
340
|
# this file (this file's own top comment) — never a real
|
|
334
341
|
# `DispatchSpec` here; `Assembly#dispatch` is the one place a
|
|
335
342
|
# declaration hash becomes the real object, and building it
|
|
@@ -27,8 +27,8 @@ module Hecks
|
|
|
27
27
|
# bluebook that no longer says what it said.
|
|
28
28
|
optional: text(field[:optional]).to_s == "true",
|
|
29
29
|
pattern: presence(text(field[:pattern])),
|
|
30
|
-
#
|
|
31
|
-
#
|
|
30
|
+
# The round trip is the only way in. The grammar registry keeps the
|
|
31
|
+
# assembled graph — the language as its own judge read it back — so a
|
|
32
32
|
# fact dropped here is a fact no downstream projection ever sees, no
|
|
33
33
|
# matter how plainly the .bluebook file declares it.
|
|
34
34
|
admits: presence(text(field[:admits])),
|
|
@@ -36,8 +36,8 @@ module Hecks
|
|
|
36
36
|
}
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
-
# A
|
|
40
|
-
# Prefixed with the owner and the identity join, because that
|
|
39
|
+
# A type this aggregate owns, offered as its id and read back as its name.
|
|
40
|
+
# Prefixed with the owner and the identity join, because that is the value
|
|
41
41
|
# object's identity — the aggregate it belongs to, then its name.
|
|
42
42
|
def owned_type(type, aggregate_id)
|
|
43
43
|
prefix = Naming.identity([aggregate_id, ""])
|
|
@@ -46,7 +46,7 @@ module Hecks
|
|
|
46
46
|
type.delete_prefix(prefix)
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
#
|
|
49
|
+
# One part of an identity, read back as the path it went in as. The inverse
|
|
50
50
|
# of `Marks#identity_path`, and named the same so the two directions read
|
|
51
51
|
# as one table.
|
|
52
52
|
def identity_path(part) = text(part[:value]).to_s
|
|
@@ -54,7 +54,7 @@ module Hecks
|
|
|
54
54
|
# An argument, a parameter, a piece's attribute — the three places an
|
|
55
55
|
# attribute is written that carry no owner id to strip... except a
|
|
56
56
|
# piece's own attribute now does : an entity is its own root (repeating
|
|
57
|
-
# the aggregate's whole shape one level down), so
|
|
57
|
+
# the aggregate's whole shape one level down), so its attributes name a
|
|
58
58
|
# value object exactly the way an aggregate's own do (`Judge#cell`'s own
|
|
59
59
|
# comment), and reconstruction has to undo the same owned-vs-reference
|
|
60
60
|
# split `attribute`, below, already undoes for an aggregate — not the
|
|
@@ -66,11 +66,11 @@ module Hecks
|
|
|
66
66
|
# argument or a parameter carries no value-object type at all — see
|
|
67
67
|
# entity.bluebook's/command.bluebook's own comments on why — so the
|
|
68
68
|
# generic reader path calls this with one argument and gets the
|
|
69
|
-
#
|
|
69
|
+
# old reading unchanged), is the piece's owning aggregate — the same
|
|
70
70
|
# one its own attribute types were resolved against on the way in
|
|
71
71
|
# (`Judge#owning_aggregate_ref`).
|
|
72
72
|
#
|
|
73
|
-
# A
|
|
73
|
+
# A reference among the other two came in as the head's ID, because
|
|
74
74
|
# that is what Command/Query.Reference offer, so it goes back out as
|
|
75
75
|
# the encoding the IR spells. A qualified name is the tell : an
|
|
76
76
|
# ordinary type names something declared beside it (`Money`,
|
|
@@ -83,7 +83,7 @@ module Hecks
|
|
|
83
83
|
|
|
84
84
|
{
|
|
85
85
|
name: text(field[:name])&.to_sym,
|
|
86
|
-
# A
|
|
86
|
+
# A qualified name is the tell : an ordinary type names something
|
|
87
87
|
# declared beside it (`Money`, `AccountNumber`) and carries no join at
|
|
88
88
|
# all, where a head's id always does (chapter + name, joined the way
|
|
89
89
|
# every derived id is).
|
|
@@ -97,7 +97,7 @@ module Hecks
|
|
|
97
97
|
}
|
|
98
98
|
end
|
|
99
99
|
|
|
100
|
-
# An
|
|
100
|
+
# An absent pattern is nil, not "". The language holds every field as
|
|
101
101
|
# text, so a field nobody set comes back as the empty string — and ""
|
|
102
102
|
# is a real regex (it matches everything), so keeping it would turn
|
|
103
103
|
# "no pattern" into "a pattern that always passes" and quietly cost the
|
|
@@ -130,13 +130,17 @@ module Hecks
|
|
|
130
130
|
# `default:`.
|
|
131
131
|
def provenance(row) = decode_literal(text(row[:provenance]))
|
|
132
132
|
|
|
133
|
-
# `command "Debit", from: "open"` — the
|
|
133
|
+
# `command "Debit", from: "open"` — the same literal encoding
|
|
134
134
|
# `provenance`/`default:` already ride (S10, ADR 0025), one
|
|
135
135
|
# state or an array of them, or nil for a command with no
|
|
136
136
|
# lifecycle guard.
|
|
137
137
|
def from(row) = decode_literal(text(row[:from]))
|
|
138
138
|
|
|
139
|
-
#
|
|
139
|
+
# A flag is held as text ("true"/"false") and emitted as a boolean —
|
|
140
|
+
# `Policy#expect_undelivered` on the wire.
|
|
141
|
+
def expect_undelivered?(row) = text(row[:expect_undelivered]).to_s == "true"
|
|
142
|
+
|
|
143
|
+
# The option rows, gathered back into the shapes `extra_options_to_h` spells.
|
|
140
144
|
#
|
|
141
145
|
# One row per part, so a compound option is several rows and a repeated one is
|
|
142
146
|
# several groups told apart by `at`. Grouping by option name and then by `at`
|
|
@@ -157,8 +161,8 @@ module Hecks
|
|
|
157
161
|
.map { |group| group.to_h { |part| [text(part[:key]).to_sym, text(part[:value])] } }
|
|
158
162
|
end
|
|
159
163
|
|
|
160
|
-
# The IR keeps a where's field as a
|
|
161
|
-
# out, never called. The value stays
|
|
164
|
+
# The IR keeps a where's field as a string, not a symbol — it is read back
|
|
165
|
+
# out, never called. The value stays raw text here on purpose : this
|
|
162
166
|
# feeds the declaration hash Assembly::Marks#where_clause decodes
|
|
163
167
|
# from (via `read`), and decoding twice is worse than once — a
|
|
164
168
|
# kwarg reference (":ceiling") decoded here into the Symbol :ceiling
|
|
@@ -205,22 +209,22 @@ module Hecks
|
|
|
205
209
|
|
|
206
210
|
def group_by_field(row) = { field: text(row[:field]) }
|
|
207
211
|
|
|
208
|
-
# `count`'s own boolean, read back the
|
|
212
|
+
# `count`'s own boolean, read back the same way `head`'s own
|
|
209
213
|
# `many` is (`text(row[:many]).to_s == "true"`) — except a
|
|
210
|
-
# `ReadModel.Count` command is dispatched
|
|
214
|
+
# `ReadModel.Count` command is dispatched at all only when
|
|
211
215
|
# `@count` was truthy (`MetaValidator::Judge#setters` skips a
|
|
212
216
|
# setter whose every source is absent), so an undeclared read
|
|
213
217
|
# model's own `count` field never gets written and comes back
|
|
214
218
|
# `nil` here, never `"false"` — matching `ReadModel#to_h`'s own
|
|
215
219
|
# `true`/`nil` pair (never `false`) exactly, rather than the
|
|
216
220
|
# unconditional `true`/`false` `head`'s own `many` needs (every
|
|
217
|
-
# head
|
|
221
|
+
# head does get a `Gather` dispatch, declared or derived).
|
|
218
222
|
def read_model_count(row) = (true if text(row[:count]).to_s == "true")
|
|
219
223
|
|
|
220
|
-
#
|
|
224
|
+
# The append flattening, in reverse.
|
|
221
225
|
#
|
|
222
226
|
# An append binds several fields at once and the language's Change holds one
|
|
223
|
-
# field/kind/source triple, so the walk offers an append once
|
|
227
|
+
# field/kind/source triple, so the walk offers an append once per binding.
|
|
224
228
|
# Rebuilding groups those rows back into the single mutation the IR keeps —
|
|
225
229
|
# the only place here that undoes something rather than simply reading it.
|
|
226
230
|
def mutations(row)
|
|
@@ -229,7 +233,7 @@ module Hecks
|
|
|
229
233
|
.map { |(target, op), bindings| mutation(target, op, bindings) }
|
|
230
234
|
end
|
|
231
235
|
|
|
232
|
-
# `sign:` — read the
|
|
236
|
+
# `sign:` — read the same way the declared side computes it
|
|
233
237
|
# (`Bluebook::Mutation.sign_for`, item #5 of the whole-project
|
|
234
238
|
# table-unification survey), not stored on any row here — the
|
|
235
239
|
# meta-domain's own Change entity carries no `sign` field of its
|
|
@@ -241,7 +245,7 @@ module Hecks
|
|
|
241
245
|
def mutation(target, oper, bindings)
|
|
242
246
|
base = { target: target.to_sym, op: oper.to_sym, sign: Hecks::Bluebook::Mutation.sign_for(oper) }
|
|
243
247
|
# `:delegate`/`:corrects` (CommandBuilder#delegates_to's and
|
|
244
|
-
# #corrects_impl's own comments) ride the
|
|
248
|
+
# #corrects_impl's own comments) ride the same multi-binding
|
|
245
249
|
# shape `:append` does.
|
|
246
250
|
return base.merge(fields: appended(bindings)) if ["append", "delegate", "corrects"].include?(oper)
|
|
247
251
|
|