hecks 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/hecks/adapters/driven/claude_code.rb +7 -7
- data/lib/hecks/adapters/driven/d1.rb +187 -23
- data/lib/hecks/adapters/driven/folder.rb +10 -10
- data/lib/hecks/adapters/driven/google_authentication.rb +8 -8
- data/lib/hecks/adapters/driven/governance_authorization.rb +31 -13
- data/lib/hecks/adapters/driven/heki/journal.rb +5 -4
- data/lib/hecks/adapters/driven/heki/saga_store.rb +5 -5
- data/lib/hecks/adapters/driven/heki.rb +13 -7
- data/lib/hecks/adapters/driven/identity_registry.rb +2 -2
- data/lib/hecks/adapters/driven/in_memory_ordering.rb +3 -3
- data/lib/hecks/adapters/driven/lambda/client.rb +34 -9
- data/lib/hecks/adapters/driven/lambda.rb +39 -33
- data/lib/hecks/adapters/driven/local_storage.rb +17 -10
- data/lib/hecks/adapters/driven/memory.rb +205 -9
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +1 -1
- data/lib/hecks/adapters/driven/postgres/codec.rb +27 -11
- data/lib/hecks/adapters/driven/postgres/outbox.rb +40 -2
- data/lib/hecks/adapters/driven/postgres/reconnect.rb +23 -7
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +14 -14
- data/lib/hecks/adapters/driven/postgres.rb +175 -28
- data/lib/hecks/adapters/driven/prism.rb +4 -4
- data/lib/hecks/adapters/driven/sql_query_builder.rb +34 -22
- data/lib/hecks/adapters/driven/sqlite/codec.rb +38 -10
- data/lib/hecks/adapters/driven/sqlite/projection.rb +60 -32
- data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +12 -12
- data/lib/hecks/adapters/driven/sqlite.rb +181 -21
- data/lib/hecks/adapters/driven.rb +4 -4
- data/lib/hecks/adapters/driving/github_webhook.rb +18 -18
- data/lib/hecks/behaviors/dsl.rb +2 -2
- data/lib/hecks/behaviors/expectations.rb +23 -23
- data/lib/hecks/behaviors/ir.rb +1 -1
- data/lib/hecks/behaviors/rspec.rb +1 -1
- data/lib/hecks/behaviors/runner.rb +2 -2
- data/lib/hecks/behaviors.rb +1 -1
- data/lib/hecks/bluebook/aggregate.rb +13 -13
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +10 -10
- data/lib/hecks/bluebook/assembly/build.rb +1 -1
- data/lib/hecks/bluebook/assembly/contract.rb +39 -16
- data/lib/hecks/bluebook/assembly/contracts.rb +40 -38
- data/lib/hecks/bluebook/assembly/marks.rb +18 -18
- data/lib/hecks/bluebook/assembly/specializer.rb +19 -21
- data/lib/hecks/bluebook/assembly.rb +9 -9
- data/lib/hecks/bluebook/attribute.rb +9 -9
- data/lib/hecks/bluebook/behaviour/aggregate.rb +11 -11
- data/lib/hecks/bluebook/behaviour/attribute.rb +5 -5
- data/lib/hecks/bluebook/behaviour/chapter.rb +23 -5
- data/lib/hecks/bluebook/behaviour/command.rb +23 -23
- data/lib/hecks/bluebook/behaviour/domain_port.rb +7 -7
- data/lib/hecks/bluebook/behaviour/entity.rb +8 -8
- data/lib/hecks/bluebook/behaviour/hexagon.rb +4 -4
- data/lib/hecks/bluebook/behaviour/lifecycle.rb +5 -5
- data/lib/hecks/bluebook/behaviour/policy.rb +12 -12
- data/lib/hecks/bluebook/behaviour/process_manager.rb +7 -7
- data/lib/hecks/bluebook/behaviour/query.rb +1 -1
- data/lib/hecks/bluebook/behaviour/read_model.rb +8 -8
- data/lib/hecks/bluebook/behaviour/traits.rb +12 -12
- data/lib/hecks/bluebook/behaviour/value_object.rb +6 -6
- data/lib/hecks/bluebook/capabilities.rb +27 -0
- data/lib/hecks/bluebook/chapter.rb +28 -9
- data/lib/hecks/bluebook/command.rb +12 -12
- data/lib/hecks/bluebook/domain_port.rb +9 -9
- data/lib/hecks/bluebook/dsl/adapter_builder.rb +24 -0
- data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +49 -49
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +96 -96
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +41 -41
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +22 -2
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +111 -74
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +48 -30
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +116 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +103 -103
- data/lib/hecks/bluebook/dsl/const_shim.rb +46 -15
- data/lib/hecks/bluebook/dsl/domain_port_builder.rb +90 -25
- data/lib/hecks/bluebook/dsl/entity_builder.rb +56 -56
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +148 -132
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +89 -30
- data/lib/hecks/bluebook/dsl/identity_declaration.rb +17 -17
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +27 -4
- data/lib/hecks/bluebook/dsl/policy_builder.rb +30 -21
- data/lib/hecks/bluebook/dsl/port_builder.rb +38 -7
- data/lib/hecks/bluebook/dsl/port_operation_builder.rb +56 -22
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +35 -35
- data/lib/hecks/bluebook/dsl/query_builder.rb +5 -5
- data/lib/hecks/bluebook/dsl/read_model_builder.rb +34 -34
- data/lib/hecks/bluebook/dsl/rule_reference.rb +41 -39
- data/lib/hecks/bluebook/dsl/translation_builder.rb +9 -9
- data/lib/hecks/bluebook/dsl/value_object_builder.rb +16 -16
- data/lib/hecks/bluebook/dsl/word_gate.rb +59 -53
- data/lib/hecks/bluebook/dsl/world_builder.rb +51 -8
- data/lib/hecks/bluebook/entity.rb +11 -11
- data/lib/hecks/bluebook/expression/ast_json.rb +20 -20
- data/lib/hecks/bluebook/expression/ast_reader.rb +3 -3
- data/lib/hecks/bluebook/expression/canonical_form.rb +9 -9
- data/lib/hecks/bluebook/expression/evaluator.rb +18 -18
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +18 -18
- data/lib/hecks/bluebook/expression/resolver.rb +60 -62
- data/lib/hecks/bluebook/hexagon.rb +1 -1
- data/lib/hecks/bluebook/lifecycle.rb +1 -1
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -1
- data/lib/hecks/bluebook/meta_validator/judge.rb +101 -87
- data/lib/hecks/bluebook/meta_validator/plan.rb +39 -39
- data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -2
- data/lib/hecks/bluebook/meta_validator/readings.rb +43 -43
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +44 -37
- data/lib/hecks/bluebook/meta_validator/shapes.rb +25 -21
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +145 -31
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +6 -6
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +5 -5
- data/lib/hecks/bluebook/meta_validator.rb +70 -70
- data/lib/hecks/bluebook/model_check.rb +170 -84
- data/lib/hecks/bluebook/pattern_subset.rb +9 -9
- data/lib/hecks/bluebook/policy.rb +15 -13
- data/lib/hecks/bluebook/process_manager.rb +14 -14
- data/lib/hecks/bluebook/project_register.rb +6 -6
- data/lib/hecks/bluebook/query.rb +4 -4
- data/lib/hecks/bluebook/read_model.rb +14 -14
- data/lib/hecks/bluebook/reference.rb +8 -8
- data/lib/hecks/bluebook/smoke_test.rb +19 -19
- data/lib/hecks/bluebook/synthesizer.rb +12 -12
- data/lib/hecks/bluebook/translation.rb +4 -4
- data/lib/hecks/bluebook/value_object.rb +6 -6
- data/lib/hecks/bluebook.rb +2 -2
- data/lib/hecks/codemod/legacy_dispatch_args.rb +299 -0
- data/lib/hecks/codemod/legacy_dispatch_recorder.rb +186 -0
- data/lib/hecks/codemod.rb +36 -35
- data/lib/hecks/construct.rb +6 -6
- data/lib/hecks/corpus.rb +317 -0
- data/lib/hecks/deprecation.rb +95 -0
- data/lib/hecks/doc/reference.rb +19 -19
- data/lib/hecks/embryonaut_bluebook.rb +11 -11
- data/lib/hecks/facade/cli_door.rb +69 -10
- data/lib/hecks/facade/cli_runner.rb +105 -24
- data/lib/hecks/facade/command_request.rb +23 -0
- data/lib/hecks/facade/handle.rb +79 -32
- data/lib/hecks/facade/json_door.rb +106 -25
- data/lib/hecks/facade/surface/aggregate_door.rb +42 -27
- data/lib/hecks/facade/surface/chapter.rb +26 -17
- data/lib/hecks/facade/surface.rb +16 -3
- data/lib/hecks/facade.rb +15 -4
- data/lib/hecks/forms/app.rb +46 -30
- data/lib/hecks/forms/command_form_renderer.rb +70 -9
- data/lib/hecks/forms/field_renderer.rb +142 -6
- data/lib/hecks/forms/field_shape.rb +180 -19
- data/lib/hecks/forms/html.rb +51 -7
- data/lib/hecks/forms/index_renderer.rb +14 -2
- data/lib/hecks/forms/params.rb +120 -23
- data/lib/hecks/forms/port_argument.rb +2 -2
- data/lib/hecks/forms/query_form_renderer.rb +2 -2
- data/lib/hecks/forms/record_renderer.rb +2 -2
- data/lib/hecks/forms/record_table.rb +1 -1
- data/lib/hecks/forms/value_object_shape.rb +3 -3
- data/lib/hecks/forms.rb +24 -4
- data/lib/hecks/fqn.rb +1 -1
- data/lib/hecks/framework/bluebook/governance.bluebook +9 -0
- data/lib/hecks/framework.rb +48 -17
- data/lib/hecks/freezer.rb +11 -11
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +90 -90
- data/lib/hecks/fuzzing/combination_miner.rb +119 -0
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +140 -45
- data/lib/hecks/fuzzing/coverage_campaign.rb +118 -0
- data/lib/hecks/fuzzing/differential.rb +158 -0
- data/lib/hecks/fuzzing/domain_generator.rb +694 -0
- data/lib/hecks/fuzzing/era_boundary.rb +37 -18
- data/lib/hecks/fuzzing/form_census.rb +35 -20
- data/lib/hecks/fuzzing/generated_domain_check.rb +95 -0
- data/lib/hecks/fuzzing/invalid_value_generator.rb +6 -6
- data/lib/hecks/fuzzing/isolated_boot.rb +62 -62
- data/lib/hecks/fuzzing/nondeterministic.rb +67 -0
- data/lib/hecks/fuzzing/persistence_parity.rb +19 -21
- data/lib/hecks/fuzzing/properties/corrections.rb +9 -9
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +154 -49
- data/lib/hecks/fuzzing/properties/guards.rb +42 -42
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +32 -32
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +22 -35
- data/lib/hecks/fuzzing/properties/outbox.rb +24 -24
- data/lib/hecks/fuzzing/properties/querying.rb +17 -17
- data/lib/hecks/fuzzing/properties.rb +64 -40
- data/lib/hecks/fuzzing/qa_settings.rb +152 -0
- data/lib/hecks/fuzzing/replay.rb +114 -114
- data/lib/hecks/fuzzing/rotation_priority.rb +10 -10
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +113 -0
- data/lib/hecks/fuzzing/self_consistency.rb +141 -112
- data/lib/hecks/fuzzing/sequence_generator/adversary.rb +35 -35
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +18 -11
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +13 -12
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +21 -12
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +58 -31
- data/lib/hecks/fuzzing/sequence_generator.rb +111 -23
- data/lib/hecks/fuzzing/shrinker.rb +197 -0
- data/lib/hecks/fuzzing/structural_skips.rb +23 -130
- data/lib/hecks/fuzzing/sweep_depth.rb +4 -4
- data/lib/hecks/fuzzing/target_capabilities.rb +49 -18
- data/lib/hecks/fuzzing/value_generator.rb +14 -14
- data/lib/hecks/fuzzing.rb +5 -0
- data/lib/hecks/grammar/evolve.rb +10 -10
- data/lib/hecks/grammar.rb +7 -7
- data/lib/hecks/ir.rb +13 -13
- data/lib/hecks/language/bluebook/bluebook.bluebook +41 -0
- data/lib/hecks/language/bluebook/policy.bluebook +11 -1
- data/lib/hecks/language/bluebook/vocabulary.bluebook +348 -13
- data/lib/hecks/language/oidc.json +5 -0
- data/lib/hecks/literal.rb +9 -9
- data/lib/hecks/naming.rb +25 -25
- data/lib/hecks/ports/access_control.rb +58 -2
- data/lib/hecks/ports/agent/answers.rb +83 -6
- data/lib/hecks/ports/agent.rb +119 -35
- data/lib/hecks/ports/authentication.rb +44 -4
- data/lib/hecks/ports/authorization.rb +53 -11
- data/lib/hecks/ports/clock.rb +42 -23
- data/lib/hecks/ports/extraction.rb +16 -0
- data/lib/hecks/ports/identity_assignment.rb +24 -2
- data/lib/hecks/ports/identity_generation.rb +17 -3
- data/lib/hecks/ports/identity_resolution.rb +18 -1
- data/lib/hecks/ports/loading.rb +4 -0
- data/lib/hecks/ports/persistence/append_only.rb +172 -8
- data/lib/hecks/ports/persistence/binding_policy.rb +34 -0
- data/lib/hecks/ports/persistence/codec_boundary.rb +178 -0
- data/lib/hecks/ports/persistence/execution.rb +4 -0
- data/lib/hecks/ports/persistence/null_saga_store.rb +12 -1
- data/lib/hecks/ports/persistence/plugin.rb +42 -4
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +218 -25
- data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +77 -9
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +81 -24
- data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +29 -18
- data/lib/hecks/ports/persistence/plugins/era/lineage.rb +144 -60
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +103 -8
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +98 -23
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +282 -109
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +63 -25
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +118 -66
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +51 -28
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +28 -5
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +25 -12
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +129 -34
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +51 -6
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +33 -9
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +16 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +57 -4
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +25 -2
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +314 -90
- data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +68 -10
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +9 -3
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +9 -2
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +42 -8
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +16 -1
- data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +36 -5
- data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +23 -3
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +18 -19
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +5 -5
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -2
- data/lib/hecks/ports/persistence/plugins/era.rb +12 -2
- data/lib/hecks/ports/persistence/remote_runtime.rb +9 -2
- data/lib/hecks/ports/persistence/repository_factory.rb +23 -3
- data/lib/hecks/ports/persistence/state_codec.rb +319 -0
- data/lib/hecks/ports/persistence.rb +36 -1
- data/lib/hecks/ports/projection.rb +61 -7
- data/lib/hecks/ports/query/in_memory.rb +3 -3
- data/lib/hecks/ports/query/ordering.rb +6 -6
- data/lib/hecks/ports/query.rb +35 -0
- data/lib/hecks/projections/bootstrap_table.rb +112 -0
- data/lib/hecks/projections/diagrams.rb +75 -75
- data/lib/hecks/projections/glossary/html.rb +3 -3
- data/lib/hecks/projections/glossary/markdown.rb +3 -3
- data/lib/hecks/projections/glossary/mermaid.rb +1 -1
- data/lib/hecks/projections/glossary/sections.rb +1 -1
- data/lib/hecks/projections/glossary/sentences.rb +5 -5
- data/lib/hecks/projections/glossary.rb +15 -15
- data/lib/hecks/projections/ir.rb +1 -1
- data/lib/hecks/projections/model/deviations.rb +18 -17
- data/lib/hecks/projections/model.rb +25 -21
- data/lib/hecks/projections/oidc.rb +7 -7
- data/lib/hecks/projections/parser_table.rb +5 -5
- data/lib/hecks/projections/reference.rb +3 -3
- data/lib/hecks/projections/rust_vocabulary.rb +443 -0
- data/lib/hecks/projections/shape.rb +2 -2
- data/lib/hecks/projections/statements.rb +11 -11
- data/lib/hecks/projections/vocabulary.rb +9 -9
- data/lib/hecks/projections.rb +5 -3
- data/lib/hecks/projector/cli_projector.rb +29 -29
- data/lib/hecks/projector/docs_projector.rb +13 -13
- data/lib/hecks/projector/exporter.rb +42 -21
- data/lib/hecks/projector/ir_projector.rb +1 -1
- data/lib/hecks/projector/narrate_projector.rb +11 -11
- data/lib/hecks/projector/target.rb +13 -13
- data/lib/hecks/projector.rb +15 -15
- data/lib/hecks/query_ir.rb +47 -47
- data/lib/hecks/query_specification/common/comparators.rb +19 -3
- data/lib/hecks/query_specification/common/comparison.rb +109 -27
- data/lib/hecks/query_specification/common/dsl.rb +65 -9
- data/lib/hecks/query_specification/common/null_policy.rb +57 -13
- data/lib/hecks/query_specification/common/null_semantics.rb +4 -0
- data/lib/hecks/query_specification/common/options.rb +25 -0
- data/lib/hecks/query_specification/field_path.rb +69 -15
- data/lib/hecks/query_specification/hop_path.rb +57 -20
- data/lib/hecks/query_specification/read_model/specification.rb +4 -0
- data/lib/hecks/rendering.rb +3 -3
- data/lib/hecks/router/namespace_installer.rb +3 -3
- data/lib/hecks/router.rb +1 -1
- data/lib/hecks/runtime/aggregate_lock.rb +11 -11
- data/lib/hecks/runtime/boot_gates.rb +3 -3
- data/lib/hecks/runtime/caller.rb +8 -8
- data/lib/hecks/runtime/capability_graph.rb +2 -2
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +22 -25
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +42 -63
- data/lib/hecks/runtime/command_interpreter.rb +159 -102
- data/lib/hecks/runtime/command_rules/admissibility.rb +69 -69
- data/lib/hecks/runtime/command_rules/arithmetic.rb +137 -91
- data/lib/hecks/runtime/command_rules/authorization.rb +38 -17
- data/lib/hecks/runtime/command_rules/emission.rb +18 -1
- data/lib/hecks/runtime/command_rules/references.rb +35 -35
- data/lib/hecks/runtime/command_rules.rb +3 -0
- data/lib/hecks/runtime/dependency_planning.rb +11 -11
- data/lib/hecks/runtime/dispatcher.rb +283 -90
- data/lib/hecks/runtime/entity_element.rb +151 -67
- data/lib/hecks/runtime/entity_interpreter.rb +108 -82
- data/lib/hecks/runtime/errors.rb +19 -19
- data/lib/hecks/runtime/event.rb +6 -6
- data/lib/hecks/runtime/identity.rb +22 -22
- data/lib/hecks/runtime/instance.rb +39 -14
- data/lib/hecks/runtime/interpreting.rb +12 -12
- data/lib/hecks/runtime/invocation.rb +276 -0
- data/lib/hecks/runtime/loader.rb +14 -14
- data/lib/hecks/runtime/outbox.rb +23 -23
- data/lib/hecks/runtime/policy_interpreter.rb +54 -54
- data/lib/hecks/runtime/port_operation_interpreter.rb +22 -19
- data/lib/hecks/runtime/query_interpreter.rb +55 -64
- data/lib/hecks/runtime/reaction_invocation.rb +20 -20
- data/lib/hecks/runtime/read_model_interpreter.rb +40 -40
- data/lib/hecks/runtime/rebuild_sweep.rb +4 -4
- data/lib/hecks/runtime/reference_hop.rb +6 -6
- data/lib/hecks/runtime/refusal_wording.rb +92 -115
- data/lib/hecks/runtime/registry/saga_persistence.rb +21 -21
- data/lib/hecks/runtime/registry/verification.rb +36 -26
- data/lib/hecks/runtime/registry.rb +45 -28
- data/lib/hecks/runtime/remote_dispatcher.rb +38 -23
- data/lib/hecks/runtime/routing.rb +10 -153
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +17 -17
- data/lib/hecks/runtime/saga_interpreter.rb +64 -64
- data/lib/hecks/runtime/saga_pending_dispatch.rb +12 -12
- data/lib/hecks/runtime/tenant_check.rb +9 -9
- data/lib/hecks/runtime/tenant_scope.rb +5 -5
- data/lib/hecks/runtime/value/admission.rb +75 -30
- data/lib/hecks/runtime/value/coercion.rb +318 -127
- data/lib/hecks/runtime/value/entity_list_coercion.rb +34 -34
- data/lib/hecks/runtime/value.rb +21 -21
- data/lib/hecks/runtime.rb +7 -7
- data/lib/hecks/storehouse.rb +64 -64
- data/lib/hecks/version.rb +3 -3
- data/lib/hecks/vocabulary.rb +205 -4
- data/lib/hecks.rb +13 -11
- data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +11 -11
- data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +14 -12
- data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +11 -11
- metadata +22 -2
|
@@ -5,12 +5,12 @@ module Hecks
|
|
|
5
5
|
# Command, ValueObject, Query, ...); see `Contract`'s own header
|
|
6
6
|
# (contract.rb) for the struct format each entry below fills in.
|
|
7
7
|
class Assembly
|
|
8
|
-
#
|
|
8
|
+
# One table, where there were five hand-written mirrors of it.
|
|
9
9
|
#
|
|
10
10
|
# `bluebook.bluebook` already declares what every construct is made of, and
|
|
11
11
|
# `Plan` already reads it — parent, fields, lists, setters. What the language
|
|
12
12
|
# cannot say is the three things Ruby needs to rebuild one, so those are here
|
|
13
|
-
# and
|
|
13
|
+
# and only those:
|
|
14
14
|
#
|
|
15
15
|
# holder which class holds it
|
|
16
16
|
# make :declare for a construct that became a class, :new for an
|
|
@@ -19,17 +19,17 @@ module Hecks
|
|
|
19
19
|
# fields each keyword the constructor takes, as
|
|
20
20
|
# keyword => [key in the declaration, how to read it]
|
|
21
21
|
#
|
|
22
|
-
# A
|
|
22
|
+
# A reader is a symbol naming a method on Marks, or :plain for a value that
|
|
23
23
|
# needs no decoding, or [:each, reader] for a list. Nothing here is a rule
|
|
24
24
|
# about whether a declaration is admissible — the language settled that on the
|
|
25
25
|
# way in. This is only how a spelling becomes an object again.
|
|
26
26
|
#
|
|
27
|
-
#
|
|
27
|
+
# Why a table and not a method per category. The judge used to carry one
|
|
28
28
|
# hand-written branch per category, and the price was fourteen verbs the
|
|
29
29
|
# language declared and the walk never offered — every rule hanging off them
|
|
30
30
|
# decoration, and nothing red, because a branch that does not exist cannot
|
|
31
31
|
# fail. An assembler with a method per category is the same shape. So the
|
|
32
|
-
# table is checked
|
|
32
|
+
# table is checked against the language by spec/assembly_spec: a field the
|
|
33
33
|
# language declares that no contract consumes is a failure, not a silence.
|
|
34
34
|
#
|
|
35
35
|
# The `derived` list is how a field says it needs no assembling — a parent
|
|
@@ -47,7 +47,8 @@ module Hecks
|
|
|
47
47
|
vision: [:vision, :plain],
|
|
48
48
|
classification: [:classification, :plain],
|
|
49
49
|
formerly_known_as: [:formerly_known_as, :plain],
|
|
50
|
-
attaches_to: [:attaches_to, :plain]
|
|
50
|
+
attaches_to: [:attaches_to, :plain],
|
|
51
|
+
provides: [:provides, :plain]
|
|
51
52
|
},
|
|
52
53
|
rows: { normalisations: :normalisation_table },
|
|
53
54
|
derived: { normalisations: :elsewhere }
|
|
@@ -60,7 +61,7 @@ module Hecks
|
|
|
60
61
|
description: [:description, :plain],
|
|
61
62
|
identified_by: [:identified_by, :plain],
|
|
62
63
|
attributes: [:attributes, [:each, :attribute]],
|
|
63
|
-
#
|
|
64
|
+
# The aggregate boundary, and the precondition a command may
|
|
64
65
|
# reference by name (S10, ADR 0025 — "Rules"). Same reader
|
|
65
66
|
# shapes ValueObject's own `invariants`/Command's own
|
|
66
67
|
# `givens` already use — `invariant` builds an Invariant,
|
|
@@ -101,7 +102,7 @@ module Hecks
|
|
|
101
102
|
ensures: [:ensures, [:each, :given]],
|
|
102
103
|
mutations: [:mutations, [:each, :mutation]],
|
|
103
104
|
emits: [:emits, :plain],
|
|
104
|
-
#
|
|
105
|
+
# Lifecycle state as a command guard (S10, ADR 0025) — a
|
|
105
106
|
# literal the same way `provenance`/`default:` already are;
|
|
106
107
|
# one state or an array of them, or nil for a command with
|
|
107
108
|
# no such guard.
|
|
@@ -138,7 +139,7 @@ module Hecks
|
|
|
138
139
|
wheres: [:wheres, [:each, :where_clause]],
|
|
139
140
|
order_by: [:order_by, :order_by],
|
|
140
141
|
limit: [:limit, :limit],
|
|
141
|
-
# Held by the language as an
|
|
142
|
+
# Held by the language as an open map, so every one of these reads the
|
|
142
143
|
# same way and a ninth option needs no new field on either side.
|
|
143
144
|
offset: [:offset, [:option, :offset]],
|
|
144
145
|
cursor: [:cursor, [:option, :cursor]],
|
|
@@ -162,20 +163,20 @@ module Hecks
|
|
|
162
163
|
fields: {
|
|
163
164
|
name: [:name, :plain],
|
|
164
165
|
description: [:description, :plain],
|
|
165
|
-
# A
|
|
166
|
+
# A list of paths, exactly as an aggregate's is. The two used to differ
|
|
166
167
|
# — a Symbol here and a String there, which byte equality with `to_h`
|
|
167
|
-
#
|
|
168
|
+
# could not see because both render as a string, so the assembled graph
|
|
168
169
|
# got a String and `element_of` looked up `args["sequence"]` in a
|
|
169
170
|
# symbol-keyed payload and found nothing: "Reverse acts on one
|
|
170
171
|
# LedgerEntry — pass sequence:", while passing sequence. There is one
|
|
171
172
|
# spelling now, and no room left for that difference.
|
|
172
173
|
identified_by: [:identified_by, :plain],
|
|
173
174
|
attributes: [:attributes, [:each, :shape_field]],
|
|
174
|
-
# ADR 0028 — the
|
|
175
|
+
# ADR 0028 — the same shape Aggregate's own `preconditions`
|
|
175
176
|
# already carries, one level down: a piece's own named
|
|
176
177
|
# `given`, referenced back by one of its own commands.
|
|
177
178
|
preconditions: [:preconditions, [:each, :given]],
|
|
178
|
-
# Round 7 — the
|
|
179
|
+
# Round 7 — the same shape Aggregate's own `invariants`
|
|
179
180
|
# already carries, one level down: checked against every
|
|
180
181
|
# instance of this piece, not the aggregate's own flat state.
|
|
181
182
|
invariants: [:invariants, [:each, :invariant]]
|
|
@@ -195,17 +196,18 @@ module Hecks
|
|
|
195
196
|
"Policy" => Contract.new(
|
|
196
197
|
holder: Policy, make: :new,
|
|
197
198
|
fields: {
|
|
198
|
-
name:
|
|
199
|
-
aggregate:
|
|
200
|
-
on_event:
|
|
201
|
-
trigger_command:
|
|
202
|
-
target_domain:
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
199
|
+
name: [:name, :plain],
|
|
200
|
+
aggregate: [:aggregate, :plain],
|
|
201
|
+
on_event: [:on_event, :plain],
|
|
202
|
+
trigger_command: [:trigger_command, :plain],
|
|
203
|
+
target_domain: [:target_domain, :plain],
|
|
204
|
+
expect_undelivered: [:expect_undelivered, :plain],
|
|
205
|
+
where: [:where, :plain],
|
|
206
|
+
for_each: [:for_each, :plain],
|
|
207
|
+
with_spec: [:with_spec, :bindings]
|
|
206
208
|
},
|
|
207
209
|
rows: { with_spec: :with_spec_rows },
|
|
208
|
-
reads: { with_spec: [:from, :with_spec] },
|
|
210
|
+
reads: { with_spec: [:from, :with_spec], expect_undelivered: :expect_undelivered? },
|
|
209
211
|
derived: { position: :walk }
|
|
210
212
|
),
|
|
211
213
|
|
|
@@ -213,7 +215,7 @@ module Hecks
|
|
|
213
215
|
holder: ProcessManager, make: :new,
|
|
214
216
|
fields: {
|
|
215
217
|
name: [:name, :plain],
|
|
216
|
-
# A
|
|
218
|
+
# **A symbol**. `SagaInterpreter` does `event.payload[pm.correlates_by]` — a
|
|
217
219
|
# hash lookup on a symbol-keyed payload — and `value == pm.correlates_by`
|
|
218
220
|
# when resolving a leg s bindings. A String there finds nothing and
|
|
219
221
|
# resolves to nothing, so the wire never advanced and a drawer that
|
|
@@ -224,7 +226,7 @@ module Hecks
|
|
|
224
226
|
states: [:states, :plain]
|
|
225
227
|
},
|
|
226
228
|
reads: { states: :names },
|
|
227
|
-
# S17, ADR 0026 — `handlers` is a
|
|
229
|
+
# S17, ADR 0026 — `handlers` is a real feature of the language's
|
|
228
230
|
# own "ProcessManager" declaration now (`attribute :handlers,
|
|
229
231
|
# list_of(Handler)`, reaction.bluebook), consumed by the judge
|
|
230
232
|
# walking `Plan`'s own containment tree (`Handler`'s own
|
|
@@ -237,7 +239,7 @@ module Hecks
|
|
|
237
239
|
# S17, ADR 0026 — Handler is a genuine entity now, nested under
|
|
238
240
|
# ProcessManager (`entity "Handler"`, reaction.bluebook). Neither
|
|
239
241
|
# `position` nor `handler` is a stored field any more: a saga
|
|
240
|
-
# answers each event
|
|
242
|
+
# answers each event once, so `event_type` is Handler's own real,
|
|
241
243
|
# non-positional identity (no walk-minted `position` to derive),
|
|
242
244
|
# and the process manager it belongs to is structural now — which
|
|
243
245
|
# list this element sits in, not a stored field to fold a parent
|
|
@@ -251,7 +253,7 @@ module Hecks
|
|
|
251
253
|
},
|
|
252
254
|
# `dispatches` — same reason ProcessManager's own `handlers`
|
|
253
255
|
# claim, above, is `:children` : a real feature of the
|
|
254
|
-
#
|
|
256
|
+
# language's own "Handler" declaration (`attribute :dispatches,
|
|
255
257
|
# list_of(Dispatch)`), consumed by the judge walking `Plan`'s
|
|
256
258
|
# own containment tree rather than by any field this contract
|
|
257
259
|
# reads.
|
|
@@ -261,7 +263,7 @@ module Hecks
|
|
|
261
263
|
# S17, ADR 0026 — Dispatch is a genuine entity now, nested under
|
|
262
264
|
# Handler (`entity "Dispatch"`, process_manager.bluebook) — two
|
|
263
265
|
# levels deep, "no life outside its Handler" (the ADR's own
|
|
264
|
-
# words). `command_name`
|
|
266
|
+
# words). `command_name` alone used to be Dispatch's own
|
|
265
267
|
# identity, until items #151/#152 (`process_manager.bluebook`'s
|
|
266
268
|
# own `DispatchPosition` comment) found it collided the instant a
|
|
267
269
|
# real handler fanned the same command out more than once —
|
|
@@ -270,22 +272,22 @@ module Hecks
|
|
|
270
272
|
# the same entry ProcessManager's own contract carries above) —
|
|
271
273
|
# never a stored field on `DispatchSpec` itself, exactly like
|
|
272
274
|
# `handler` before it.
|
|
273
|
-
# `compensates_command_name`/`compensates_with_spec` —
|
|
274
|
-
# the
|
|
275
|
-
# (one IR
|
|
275
|
+
# `compensates_command_name`/`compensates_with_spec` — folded,
|
|
276
|
+
# the same kind `Lifecycle`'s own `state_field`/`default` claim
|
|
277
|
+
# (one IR object, `DispatchSpec#compensates`, feeding two
|
|
276
278
|
# separate language fields): `Readings#field_value`'s own
|
|
277
279
|
# `contract.folded` branch reads
|
|
278
280
|
# `node.compensates.to_h[:command_name]` / `[:with_spec]` for
|
|
279
|
-
# the
|
|
281
|
+
# the judge's offering side, nil-safe when there is no
|
|
280
282
|
# compensation at all (`through`'s own `return nil unless
|
|
281
|
-
# held`). `compensates_with_spec`
|
|
282
|
-
# (`compensates_with_spec_rows`, readings.rb) for the
|
|
283
|
+
# held`). `compensates_with_spec` also needs its own row shaper
|
|
284
|
+
# (`compensates_with_spec_rows`, readings.rb) for the judge's
|
|
283
285
|
# list-offering side — the with_spec pairs still need one
|
|
284
286
|
# "BindCompensation" append per pair, the same reason
|
|
285
287
|
# `with_spec` itself needs `with_spec_rows`, one level deeper.
|
|
286
288
|
# `Reconstruction#dispatch` reads the two flat fields back off
|
|
287
289
|
# the row and assembles the nested `DispatchSpec` by hand — a
|
|
288
|
-
# nested
|
|
290
|
+
# nested object is not one of the shapes `declaration()`'s own
|
|
289
291
|
# generic per-field hash-build can produce, the identical reason
|
|
290
292
|
# `handler`/`process_manager` pass a `:children` list through
|
|
291
293
|
# `extra:` instead.
|
|
@@ -372,7 +374,7 @@ module Hecks
|
|
|
372
374
|
# is what `Assembly::Build` needs (fed the native `to_h`
|
|
373
375
|
# value directly, already `true`/`nil`/a String), and the
|
|
374
376
|
# `reads:` entry below is what `Reconstruction` needs
|
|
375
|
-
# instead (fed the
|
|
377
|
+
# instead (fed the stringified meta-domain row).
|
|
376
378
|
count: [:count, :plain],
|
|
377
379
|
median_field: [:median_field, :plain],
|
|
378
380
|
# A read model inherits every option an ask has, so it reads them the
|
|
@@ -392,12 +394,12 @@ module Hecks
|
|
|
392
394
|
# `nil` — even though a read model's row never carries `wheres` as a
|
|
393
395
|
# native field the way Query's does (`[:each, :where_clause]` over an
|
|
394
396
|
# absent `row[:wheres]` is `Array(nil).map { ... }`, i.e. `[]`, always).
|
|
395
|
-
# The
|
|
397
|
+
# The real values, when a read model declares any, arrive through
|
|
396
398
|
# `options_of(row)`'s merge in `read_model` below (dispatched as
|
|
397
399
|
# generic Option rows, `read_model_option_rows`/`filter_options` — not
|
|
398
400
|
# as dedicated where-clause rows), which overrides this default. Until
|
|
399
401
|
# `ReadModel#to_h` spelled `wheres`/`order_by`/`limit`
|
|
400
|
-
# unconditionally, `round_trip_spec`'s own "
|
|
402
|
+
# unconditionally, `round_trip_spec`'s own "source keys only" +compare
|
|
401
403
|
# never asked about this key at all, so the `nil`-vs-`[]` gap between
|
|
402
404
|
# this contract's default and `to_h`'s own `[]` default went unnoticed.
|
|
403
405
|
# `order_by`/`limit` need no matching entry — the generic reader's
|
|
@@ -419,7 +421,7 @@ module Hecks
|
|
|
419
421
|
}
|
|
420
422
|
),
|
|
421
423
|
|
|
422
|
-
# A member's pairs are an
|
|
424
|
+
# A member's pairs are an open map, which is why Member is its own root in
|
|
423
425
|
# the language. The IR keeps them as a plain hash on the value object, so
|
|
424
426
|
# they are assembled with their shape rather than as a construct.
|
|
425
427
|
# S17, ADR 0026 — Member is a genuine entity now, nested under
|
|
@@ -6,10 +6,10 @@ module Hecks
|
|
|
6
6
|
# `to_h` spells things as text so the export stands on its own, and every
|
|
7
7
|
# one of those spellings has to come back apart here. This is the same family
|
|
8
8
|
# of work `MetaValidator::Shapes` does for the reconstruction — the difference
|
|
9
|
-
# is that Shapes rebuilds
|
|
9
|
+
# is that Shapes rebuilds hashes and this rebuilds objects, so it has to
|
|
10
10
|
# recover types rather than just strings.
|
|
11
11
|
#
|
|
12
|
-
#
|
|
12
|
+
# Encoding losses are the LARGEST family of bug in this codebase, and every
|
|
13
13
|
# member has the same shape: reading an object where `to_h` holds a spelling.
|
|
14
14
|
# So each method below names the spelling it inverts.
|
|
15
15
|
module Marks
|
|
@@ -27,7 +27,7 @@ module Hecks
|
|
|
27
27
|
type: target ? Reference.new(target) : type,
|
|
28
28
|
list: field[:list] ? true : false,
|
|
29
29
|
default: field[:default],
|
|
30
|
-
# The
|
|
30
|
+
# The last place optionality can be dropped, and the one that was
|
|
31
31
|
# dropping it. Every bluebook in the registry is the round-trip
|
|
32
32
|
# product — MetaValidator dispatches the declaration in and reads it
|
|
33
33
|
# back — so a fact this constructor does not carry is a fact the
|
|
@@ -35,9 +35,9 @@ module Hecks
|
|
|
35
35
|
# wrote it.
|
|
36
36
|
optional: field[:optional] ? true : false,
|
|
37
37
|
pattern: field[:pattern],
|
|
38
|
-
#
|
|
38
|
+
# **The same lesson, one fact later**. `admits` is not on `to_h` — the
|
|
39
39
|
# wire does not carry it, on purpose — but it must still survive the
|
|
40
|
-
# round trip, because the grammar registry keeps the
|
|
40
|
+
# round trip, because the grammar registry keeps the assembled graph
|
|
41
41
|
# and downstream projections read the link off that. Dropped here, the
|
|
42
42
|
# language could not say `admits` about itself no matter how plainly
|
|
43
43
|
# the source wrote it, which is word for word what the note above
|
|
@@ -52,15 +52,15 @@ module Hecks
|
|
|
52
52
|
# both — `Aggregate.Attribute` and `Command.Argument` are separate verbs.
|
|
53
53
|
def shape_field(field) = attribute(field)
|
|
54
54
|
|
|
55
|
-
#
|
|
55
|
+
# One part of an identity. It goes in as a row so the language can hold an
|
|
56
56
|
# ordered list of them, and comes back out as the path it always was —
|
|
57
57
|
# a String, because `identity_paths` splits paths and never symbols.
|
|
58
58
|
def identity_path(part) = part[:value].to_s
|
|
59
59
|
|
|
60
|
-
# A member's fields — an
|
|
60
|
+
# A member's fields — an open map, which is why Member is its own root in
|
|
61
61
|
# the language and why the pairs arrive as a list rather than a value object.
|
|
62
62
|
#
|
|
63
|
-
# The values are
|
|
63
|
+
# The values are unmarked, because `ValueObject#to_h` spells them with `to_s`
|
|
64
64
|
# and the language stores them as text: `member code: "JPY", minor_units: 0`
|
|
65
65
|
# came back with a minor_units of "0", and a closed set that admits the string
|
|
66
66
|
# would refuse the number the caller passes.
|
|
@@ -69,7 +69,7 @@ module Hecks
|
|
|
69
69
|
end
|
|
70
70
|
|
|
71
71
|
# A read model's gathered head. The keys must be symbols whichever way the
|
|
72
|
-
# declaration arrived, and `as` must be one too: it
|
|
72
|
+
# declaration arrived, and `as` must be one too: it names the reader the
|
|
73
73
|
# projection answers to, and `ReadModel#to_h` spells it `to_s`.
|
|
74
74
|
def head(row)
|
|
75
75
|
row.to_h { |key, value| [key.to_sym, key.to_sym == :as ? value.to_sym : value] }
|
|
@@ -118,8 +118,8 @@ module Hecks
|
|
|
118
118
|
|
|
119
119
|
# `Mutation#to_h` branches on the operation, so this does too.
|
|
120
120
|
#
|
|
121
|
-
# An
|
|
122
|
-
# Symbol, wearing its colon) or a
|
|
121
|
+
# An append binds several fields at once, each either an argument (a
|
|
122
|
+
# Symbol, wearing its colon) or a literal — the distinction that is the
|
|
123
123
|
# whole reason `append: { direction: "out" }` was once indistinguishable
|
|
124
124
|
# from an argument named `out`.
|
|
125
125
|
def mutation(change)
|
|
@@ -127,7 +127,7 @@ module Hecks
|
|
|
127
127
|
op = change[:op].to_sym
|
|
128
128
|
|
|
129
129
|
# `:delegate`/`:corrects` (CommandBuilder#delegates_to's and
|
|
130
|
-
# #corrects_impl's own comments) ride the
|
|
130
|
+
# #corrects_impl's own comments) ride the same multi-binding
|
|
131
131
|
# shape `:append` does.
|
|
132
132
|
return Mutation.new(target: target, op: op, source: appended(change[:fields])) if [:append, :delegate,
|
|
133
133
|
:corrects].include?(op)
|
|
@@ -139,7 +139,7 @@ module Hecks
|
|
|
139
139
|
Array(fields).to_h { |field, source| [field.to_sym, read(source)] }
|
|
140
140
|
end
|
|
141
141
|
|
|
142
|
-
# A
|
|
142
|
+
# A set reads one thing, and `classified_source` said which: an argument by
|
|
143
143
|
# name, or a literal by value.
|
|
144
144
|
def classified(source)
|
|
145
145
|
return nil if source.nil?
|
|
@@ -151,7 +151,7 @@ module Hecks
|
|
|
151
151
|
end
|
|
152
152
|
end
|
|
153
153
|
|
|
154
|
-
#
|
|
154
|
+
# Every literal field on the wire, read back — one spelling, one reader.
|
|
155
155
|
#
|
|
156
156
|
# A where-clause value, a saga's argument bindings, an append binding, a
|
|
157
157
|
# limit: all of them ride Literal's self-describing form, so all of them
|
|
@@ -159,7 +159,7 @@ module Hecks
|
|
|
159
159
|
# that disagreed about quoted strings and numbers, and which one a call
|
|
160
160
|
# site got was a coin toss the comments had to keep apologising for.
|
|
161
161
|
#
|
|
162
|
-
#
|
|
162
|
+
# An object literal is the one that bit. A saga leg binds `narrative: {
|
|
163
163
|
# text: "transfer out" }` — a value object's fields written inline — and
|
|
164
164
|
# `to_s` on a Hash used to be its inspect form, so it came back as text.
|
|
165
165
|
# Read as a string it reached the runtime as `"{:text=>\"transfer out\"}"`,
|
|
@@ -171,10 +171,10 @@ module Hecks
|
|
|
171
171
|
def read(value) = Literal.read(value)
|
|
172
172
|
|
|
173
173
|
# `target:` (ADR 0055) — read straight off the wire, unconverted:
|
|
174
|
-
# it's already the bare aggregate-name
|
|
174
|
+
# it's already the bare aggregate-name string `WhereClause#to_h`/
|
|
175
175
|
# `OrderBy#to_h`/`LimitSpec#to_h` wrote (`resolve_target`'s own
|
|
176
176
|
# `Naming.demodulise` already ran once, at DSL-build time; this is
|
|
177
|
-
# the
|
|
177
|
+
# the replay path every real boot actually goes through, reading
|
|
178
178
|
# that same wire shape back — see this class's own header). Absent
|
|
179
179
|
# from `clause`/`declared` entirely on older wire data that never
|
|
180
180
|
# declared `on:` — `clause[:target]`/`declared[:target]` reads
|
|
@@ -200,7 +200,7 @@ module Hecks
|
|
|
200
200
|
QuerySpecification::Common::LimitSpec.new(value: read(declared[:value]), target: declared[:target])
|
|
201
201
|
end
|
|
202
202
|
|
|
203
|
-
#
|
|
203
|
+
# Every other specification option, from one table.
|
|
204
204
|
#
|
|
205
205
|
# Each entry names the struct and which of its members carry a value that
|
|
206
206
|
# rode Literal's spelling rather than plain text. A
|
|
@@ -1,45 +1,31 @@
|
|
|
1
1
|
module Hecks
|
|
2
2
|
module Bluebook
|
|
3
3
|
class Assembly
|
|
4
|
-
#
|
|
4
|
+
# **The first specializer** — a projection of `contracts.rb`'s `fields:` table,
|
|
5
5
|
# derived from the language's own description of a category instead of
|
|
6
6
|
# hand-written beside it.
|
|
7
7
|
#
|
|
8
8
|
# `Plan` already reads `grammar_registry` to build the judge's walk ; this
|
|
9
|
-
# reads the same chapter to build the
|
|
10
|
-
# names as duplication — "
|
|
9
|
+
# reads the same chapter to build the other table this arc's own header
|
|
10
|
+
# names as duplication — "spelled as the IR spells them," field for field,
|
|
11
11
|
# for every category simple enough to say so.
|
|
12
12
|
#
|
|
13
|
-
#
|
|
13
|
+
# One case, proven, not the whole table. A field this can speak for is
|
|
14
14
|
# scalar and not a reference — every other field (a list, a reference, a
|
|
15
15
|
# fold like Lifecycle) is exactly what `contracts.rb`'s `reads:`/`derived:`
|
|
16
16
|
# exist to say, and stays hand-written until a later projection learns to
|
|
17
17
|
# derive readers and folds too. Restricting the claim to what can be
|
|
18
|
-
#
|
|
18
|
+
# proven correct — checked in spec/specializer_spec.rb against two
|
|
19
19
|
# independent categories — is the same discipline `derived:` itself
|
|
20
20
|
# enforces : a claim needs a kind, and this one's kind is "plain, checked."
|
|
21
21
|
module Specializer
|
|
22
22
|
module_function
|
|
23
23
|
|
|
24
|
-
# `position` IS THE FIRST FOLD THIS RUNS INTO, and it is a universal
|
|
25
|
-
# one : every category declares `attribute :position, Position` — for
|
|
26
|
-
# the JUDGE's own walk, `order_by :position` on its `DeclaredIn` ask —
|
|
27
|
-
# but no `*` constructor takes it as an argument. `contracts.rb`
|
|
28
|
-
# already says so, in the language every other derived field speaks :
|
|
29
|
-
# `derived: { position: :walk }`. The language says a category HAS a
|
|
30
|
-
# position ; it does not say a category's OWN constructor is handed
|
|
31
|
-
# one, and that second fact is exactly what `fields:` needs to answer.
|
|
32
|
-
# So this is not silently special-cased — it is the one fold named
|
|
33
|
-
# here because it is the one fold that is not a lucky accident of
|
|
34
|
-
# Policy or Handler, but a fact true of every category this arc will
|
|
35
|
-
# ever reach.
|
|
36
|
-
DERIVED_EVERYWHERE = %i[position].freeze
|
|
37
|
-
|
|
38
24
|
# S17, ADR 0026 — `Handler` is a genuine entity now, nested under
|
|
39
25
|
# `ProcessManager`, so `.aggregate` alone no longer finds it —
|
|
40
26
|
# it hangs off some aggregate's own `.entities` instead
|
|
41
27
|
# (searched recursively, the same reason `Value::Coercion#find_
|
|
42
|
-
# entity` does: a
|
|
28
|
+
# entity` does: a nested entity, like `Dispatch` inside
|
|
43
29
|
# `Handler`, is not a direct child of any aggregate either).
|
|
44
30
|
def construct_for(chapter, name)
|
|
45
31
|
chapter.aggregate(name) || chapter.aggregates.filter_map { |a| find_entity(a, name) }.first
|
|
@@ -55,11 +41,23 @@ module Hecks
|
|
|
55
41
|
nil
|
|
56
42
|
end
|
|
57
43
|
|
|
44
|
+
# `position` is the first fold this runs into : a category declares
|
|
45
|
+
# `attribute :position, Position` — for the judge's own walk,
|
|
46
|
+
# `order_by :position` on its `DeclaredIn` ask — but no `*`
|
|
47
|
+
# constructor takes it as an argument. `contracts.rb` already says so,
|
|
48
|
+
# in the language every other derived field speaks :
|
|
49
|
+
# `derived: { position: :walk }`. The language says a category has a
|
|
50
|
+
# position ; it does not say a category's own constructor is handed
|
|
51
|
+
# one, and that second fact is exactly what `fields:` needs to answer.
|
|
52
|
+
# So the skip reads the category's own walk claims (`Contract#walked`)
|
|
53
|
+
# rather than restating `position` here — Handler, which has no
|
|
54
|
+
# walk-minted position, skips nothing.
|
|
58
55
|
def fields_for(category)
|
|
59
56
|
language = construct_for(MetaValidator.grammar_registry.bluebook("Bluebook"), category.to_s)
|
|
57
|
+
walked = Assembly.contract(category).walked
|
|
60
58
|
language.attributes.each_with_object({}) do |attribute, fields|
|
|
61
59
|
next if attribute.list? || attribute.reference?
|
|
62
|
-
next if
|
|
60
|
+
next if walked.include?(attribute.name)
|
|
63
61
|
|
|
64
62
|
fields[attribute.name] = [attribute.name, :plain]
|
|
65
63
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module Hecks
|
|
2
2
|
module Bluebook
|
|
3
|
-
# A
|
|
3
|
+
# A graph built from declarations, rather than from DSL calls.
|
|
4
4
|
#
|
|
5
5
|
# This is the half that lets the language orchestrate. `Reconstruction` reads a
|
|
6
6
|
# chapter back out of the meta-domain, in declaration order, as plain
|
|
@@ -8,24 +8,24 @@ module Hecks
|
|
|
8
8
|
# into the graph the runtime runs: IR aggregates with their verbs, value
|
|
9
9
|
# objects, entities and asks, owned by the chapter that declares them.
|
|
10
10
|
#
|
|
11
|
-
# It takes a
|
|
11
|
+
# It takes a hash, not a runtime, on purpose. That makes it a pure inverse of
|
|
12
12
|
# `to_h` and testable without the meta-domain in the picture at all:
|
|
13
13
|
#
|
|
14
14
|
# Assembly.call(built.to_h).to_h == built.to_h
|
|
15
15
|
#
|
|
16
16
|
# which is the check `spec/assembly_spec` makes for every chapter in the tree.
|
|
17
17
|
# Feed it the reconstruction instead and the same code assembles what the
|
|
18
|
-
#
|
|
18
|
+
# language holds — the only difference being where the declarations came from.
|
|
19
19
|
#
|
|
20
|
-
#
|
|
20
|
+
# Every field is read from one table. There is no method per category here:
|
|
21
21
|
# `Contracts` names what the language cannot say about a construct, `Build`
|
|
22
22
|
# reads it, and the coverage gate holds the table to the language. The first
|
|
23
23
|
# draft of this file did have a method each, which is the shape the judge used
|
|
24
24
|
# to have — and the price of that shape was fourteen verbs the language declared
|
|
25
25
|
# and nothing ever offered.
|
|
26
26
|
#
|
|
27
|
-
# What stays hand-written is the
|
|
28
|
-
# That is not a field table. (The runtime
|
|
27
|
+
# What stays hand-written is the containment: which construct holds which.
|
|
28
|
+
# That is not a field table. (The runtime surface is no longer built here at
|
|
29
29
|
# all — the door is a per-boot projection, facade/surface.rb.)
|
|
30
30
|
class Assembly
|
|
31
31
|
def self.call(declaration) = new(declaration).bluebook
|
|
@@ -50,7 +50,7 @@ module Hecks
|
|
|
50
50
|
private
|
|
51
51
|
|
|
52
52
|
# Every reaction the chapter holds, and each one also handed back to the head
|
|
53
|
-
# that declared it — the builder keeps a policy in
|
|
53
|
+
# that declared it — the builder keeps a policy in both places, hoisting it onto
|
|
54
54
|
# the chapter where the runtime reads it while the head keeps its own list. The
|
|
55
55
|
# language records which head, so the assembly can put it back.
|
|
56
56
|
def reactions(aggregates)
|
|
@@ -72,10 +72,10 @@ module Hecks
|
|
|
72
72
|
dispatches: Array(row[:dispatches]).map { |leg| dispatch(leg) })
|
|
73
73
|
end
|
|
74
74
|
|
|
75
|
-
# `compensates` — a
|
|
75
|
+
# `compensates` — a plain hash on the declaration (`Reconstruction#
|
|
76
76
|
# dispatch`'s own comment for why), built into the real
|
|
77
77
|
# `DispatchSpec` its own field actually is by recursing through
|
|
78
|
-
#
|
|
78
|
+
# this same method, one level in — the identical move `handler`
|
|
79
79
|
# itself takes into `dispatches`, one level up. `nil` when there
|
|
80
80
|
# is nothing to compensate; `Build.call` never sees a
|
|
81
81
|
# `compensates:` key it does not know how to read either way, the
|
|
@@ -28,15 +28,15 @@ module Hecks
|
|
|
28
28
|
|
|
29
29
|
attr_reader :name, :type, :default, :pattern, :admits, :relationship
|
|
30
30
|
|
|
31
|
-
# A Reference is kept
|
|
31
|
+
# A Reference is kept as itself. Every other type is still a name, and
|
|
32
32
|
# crosses over as its construct does.
|
|
33
33
|
#
|
|
34
|
-
# `admits` names an
|
|
34
|
+
# `admits` names an already-declared closed set the value must belong
|
|
35
35
|
# to — `Vocabulary::QueryComparator` — spelled aggregate-qualified
|
|
36
|
-
# because the set is a value object
|
|
36
|
+
# because the set is a value object inside an aggregate, and the
|
|
37
37
|
# aggregate is the only thing `reference_to` can reach.
|
|
38
38
|
#
|
|
39
|
-
#
|
|
39
|
+
# On the wire, because it is a rule and not only a typing hint.
|
|
40
40
|
#
|
|
41
41
|
# It began as neither. The link existed so a generator could type
|
|
42
42
|
# `WhereClause.op` as `WhereOp` — a typing convenience, not worth
|
|
@@ -48,7 +48,7 @@ module Hecks
|
|
|
48
48
|
# refused "burnt" through one reading and emitted the event through
|
|
49
49
|
# another.
|
|
50
50
|
#
|
|
51
|
-
# The wire carries the
|
|
51
|
+
# The wire carries the name, not the members. A reader resolves it
|
|
52
52
|
# against the IR it holds, so the members are declared once and
|
|
53
53
|
# copied nowhere — which is the same reason `admits` exists at all.
|
|
54
54
|
def initialize(name:, type:, list: false, default: nil, optional: false, pattern: nil,
|
|
@@ -63,13 +63,13 @@ module Hecks
|
|
|
63
63
|
@relationship = relationship&.to_s
|
|
64
64
|
end
|
|
65
65
|
|
|
66
|
-
# A
|
|
66
|
+
# A bare constant in a bluebook is a name, even when Ruby has heard of it.
|
|
67
67
|
#
|
|
68
68
|
# `BluebookBuilder.build` says exactly this and installs a `const_missing`
|
|
69
69
|
# resolver that hands back the symbol — `attribute :target, Target` becomes
|
|
70
70
|
# the name "Target" and nothing looks Target up. That works only while the
|
|
71
|
-
# lookup
|
|
72
|
-
#
|
|
71
|
+
# lookup fails, and `Facade::Surface` installs every aggregate name as a
|
|
72
|
+
# top-level constant (its own comment, and `ConstShim`'s, both say so).
|
|
73
73
|
#
|
|
74
74
|
# So in one process: boot a domain with an aggregate named `Target`, then
|
|
75
75
|
# load a chapter whose own value object is called `Target`, and Ruby
|
|
@@ -81,7 +81,7 @@ module Hecks
|
|
|
81
81
|
# `QualityControl::Target` are both "Target". A plain class stays itself —
|
|
82
82
|
# `String` demodulises to "String" — so the ordinary case is untouched.
|
|
83
83
|
# This does not undo the constant leak; it makes the leak unable to change
|
|
84
|
-
# what a chapter
|
|
84
|
+
# what a chapter means, which is the part that has to hold.
|
|
85
85
|
def spell(type)
|
|
86
86
|
return type if type.is_a?(Reference)
|
|
87
87
|
return Naming.demodulise(type) if type.is_a?(Module)
|
|
@@ -3,14 +3,14 @@ require_relative "traits"
|
|
|
3
3
|
module Hecks
|
|
4
4
|
module Bluebook
|
|
5
5
|
module Behaviour
|
|
6
|
-
#
|
|
6
|
+
# What an aggregate does, as opposed to what it holds.
|
|
7
7
|
#
|
|
8
8
|
# The holding half — the field list, the readers, the emission — is
|
|
9
9
|
# the same list the language already declares in
|
|
10
10
|
# `language/bluebook/aggregate.bluebook`, said a second and third
|
|
11
11
|
# time in Ruby. This half is not: derived identity, the name
|
|
12
12
|
# indexes, the owner stamping and the finders are decisions about
|
|
13
|
-
#
|
|
13
|
+
# how the declared shape is used, and no grammar states them.
|
|
14
14
|
#
|
|
15
15
|
# Split so the holding half can be generated from the language
|
|
16
16
|
# without any of this being in the blast radius of a regeneration.
|
|
@@ -24,11 +24,11 @@ module Hecks
|
|
|
24
24
|
include Indexed
|
|
25
25
|
include Owns
|
|
26
26
|
|
|
27
|
-
# An aggregate is a
|
|
28
|
-
# where everything else is declared
|
|
27
|
+
# An aggregate is a member of its chapter's namespace — "Pizzas::Pizza" —
|
|
28
|
+
# where everything else is declared on its owner and joins with ".".
|
|
29
29
|
def hecks_separator = "::"
|
|
30
30
|
|
|
31
|
-
#
|
|
31
|
+
# The hook the generated constructor calls once every declared
|
|
32
32
|
# field is assigned. Nothing here is derivable from the
|
|
33
33
|
# declaration, which is exactly why it is not generated.
|
|
34
34
|
def settle
|
|
@@ -46,7 +46,7 @@ module Hecks
|
|
|
46
46
|
@commands_by_name = index_by_hecks_name(@commands)
|
|
47
47
|
@queries_by_name = index_by_hecks_name(@queries)
|
|
48
48
|
@ports_by_name = @ports.to_h { |port| [port.name, port] }
|
|
49
|
-
# S12, ADR 0025 — keyed by
|
|
49
|
+
# S12, ADR 0025 — keyed by symbol, the same convention
|
|
50
50
|
# `Indexed#attribute` already uses; `GuardState` asks for one
|
|
51
51
|
# by name at every dispatch, the rebuild sweep walks all of
|
|
52
52
|
# them once per pass.
|
|
@@ -55,18 +55,18 @@ module Hecks
|
|
|
55
55
|
|
|
56
56
|
def projected_field(named) = @projected_fields_by_name[named.to_sym]
|
|
57
57
|
|
|
58
|
-
# A value object is a
|
|
58
|
+
# A value object is a class now, so `name` is Ruby's answer (the constant
|
|
59
59
|
# path) and the declared name is `hecks_name`. This finder is on its way
|
|
60
|
-
# out — once an attribute's type
|
|
60
|
+
# out — once an attribute's type is the class there is nothing to find —
|
|
61
61
|
# but every consumer still asks by type string, so it stays until they
|
|
62
62
|
# stop.
|
|
63
63
|
def value_object(named) = @value_objects_by_name[named.to_s]
|
|
64
64
|
def port(named) = @ports_by_name[named.to_s]
|
|
65
65
|
|
|
66
|
-
# A
|
|
66
|
+
# A port is declared in the hecksagon, not the bluebook — the
|
|
67
67
|
# boundary between the domain and its adapters, in hexagonal terms,
|
|
68
|
-
# is exactly what a `.hecksagon` file already
|
|
69
|
-
# port (persistence, projection, ...). So this attaches
|
|
68
|
+
# is exactly what a `.hecksagon` file already is for every other
|
|
69
|
+
# port (persistence, projection, ...). So this attaches after the
|
|
70
70
|
# aggregate already exists and is registered — `HecksagonBuilder`
|
|
71
71
|
# calls it once per `port` declaration, having already stamped each
|
|
72
72
|
# operation's reference attributes with `declared_in = self`, since
|