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
|
@@ -1,35 +1,37 @@
|
|
|
1
|
+
require_relative "bootstrap_table"
|
|
2
|
+
|
|
1
3
|
module Hecks
|
|
2
4
|
module Bluebook
|
|
3
5
|
module DSL
|
|
4
|
-
#
|
|
6
|
+
# The three resolution primitives the S10 given/invariant family's
|
|
5
7
|
# own "declared once, referenced by name" mechanism (ADR 0025)
|
|
6
8
|
# reduces to, at every scope this language has grown one so far
|
|
7
9
|
# (a command referencing its owner or a sibling piece's entity-wide
|
|
8
10
|
# pool; an aggregate referencing another aggregate chapter-wide; a
|
|
9
11
|
# value object referencing a sibling value object on the same
|
|
10
|
-
# aggregate) — extracted here, once, so the
|
|
12
|
+
# aggregate) — extracted here, once, so the next scope this family
|
|
11
13
|
# widens to (there will be one — see docs/resolution-rules/
|
|
12
14
|
# chapter-given.md's own "Known limitations" for two already named)
|
|
13
15
|
# reuses one of these three shapes instead of a fourth hand-written
|
|
14
16
|
# near-duplicate resolver.
|
|
15
17
|
#
|
|
16
|
-
#
|
|
17
|
-
# answers directly: the
|
|
18
|
-
# superficially different, they are
|
|
19
|
-
# multi-pool fallback
|
|
20
|
-
# needing disambiguation; a
|
|
18
|
+
# **Not one unified algorithm** — a real design question this file
|
|
19
|
+
# answers directly: the three existing resolvers are not
|
|
20
|
+
# superficially different, they are structurally different (a
|
|
21
|
+
# multi-pool fallback chain; one pool keyed by declaring owner,
|
|
22
|
+
# needing disambiguation; a live scan over already-built sibling
|
|
21
23
|
# objects with no separate pool at all) — forcing them into one
|
|
22
24
|
# shape would be a real behavior change (see `#lookup`, below, for
|
|
23
25
|
# which construct uses which), not the pure internal refactor this
|
|
24
|
-
# module is. `build_rule` is the one piece that
|
|
26
|
+
# module is. `build_rule` is the one piece that was genuinely
|
|
25
27
|
# identical across all 7 declaring methods (`given`×3,
|
|
26
28
|
# `invariant`×3, `ensures`×1) before this file existed — extract
|
|
27
29
|
# predicate source, refuse if extraction failed, build the struct.
|
|
28
30
|
#
|
|
29
|
-
# `#lookup`/`#verify_resolves_via!` read
|
|
31
|
+
# `#lookup`/`#verify_resolves_via!` read which construct uses which
|
|
30
32
|
# primitive off the self-hosted grammar table itself
|
|
31
33
|
# (`Keyword#resolves_via`, `syntax.bluebook`) — not a Ruby-only
|
|
32
|
-
# Hash cross-checked afterward (this file's
|
|
34
|
+
# Hash cross-checked afterward (this file's own earlier shape, one
|
|
33
35
|
# round ago) — so a real domain's own boot, not just `bundle exec
|
|
34
36
|
# rspec`, fails loudly the moment the table and this file's own
|
|
35
37
|
# hand-written resolution methods disagree.
|
|
@@ -39,14 +41,14 @@ module Hecks
|
|
|
39
41
|
# `struct_class` is `Given` or `Invariant` (both `Struct.new(
|
|
40
42
|
# :description, :canonical, :predicate, keyword_init: true)` —
|
|
41
43
|
# `Given` lives in command.rb, `Invariant` in value_object.rb).
|
|
42
|
-
# `owner_name`/`word` are
|
|
44
|
+
# `owner_name`/`word` are only for the refusal message's own
|
|
43
45
|
# wording. `extraction_failure` is the tail of that same
|
|
44
|
-
# message, and stays a
|
|
46
|
+
# message, and stays a required parameter rather than one
|
|
45
47
|
# hardcoded string on purpose — `given` ("its source could not
|
|
46
48
|
# be read, so no other runtime could ever evaluate it"),
|
|
47
49
|
# `invariant` ("it would be a rule the IR cannot carry"), and
|
|
48
50
|
# `ensures` ("a postcondition is carried as text, and this one
|
|
49
|
-
# has none") each already had their
|
|
51
|
+
# has none") each already had their own exact wording before
|
|
50
52
|
# this method existed; unifying them into one generic sentence
|
|
51
53
|
# would be a real (if small) behavior change this refactor is
|
|
52
54
|
# not making.
|
|
@@ -64,9 +66,9 @@ module Hecks
|
|
|
64
66
|
struct_class.new(description: description, canonical: canonical, predicate: predicate, ast: ast)
|
|
65
67
|
end
|
|
66
68
|
|
|
67
|
-
#
|
|
69
|
+
# Primitive 1 — an ordered chain of flat `Hash[description] =>
|
|
68
70
|
# Rule` pools, first match wins. `CommandBuilder#given`'s own
|
|
69
|
-
# two-pool shape (its
|
|
71
|
+
# two-pool shape (its own owner's `named_givens`, then a sibling
|
|
70
72
|
# piece's entity-wide pool) is this with a 2-element chain — a
|
|
71
73
|
# future single-pool bare reference is the same primitive with a
|
|
72
74
|
# 1-element chain, not a separate "just look in one hash" method.
|
|
@@ -75,12 +77,12 @@ module Hecks
|
|
|
75
77
|
nil
|
|
76
78
|
end
|
|
77
79
|
|
|
78
|
-
#
|
|
80
|
+
# Primitive 2 — one pool keyed by declaring owner,
|
|
79
81
|
# `Hash[description][owner] => Rule` — `AggregateBuilder#given`'s
|
|
80
82
|
# own chapter-wide shape, the only construct so far where the
|
|
81
|
-
#
|
|
83
|
+
# same description can mean two genuinely different predicates
|
|
82
84
|
# (docs/implemented/resolution-rules/chapter-given.md). Returns the full
|
|
83
|
-
# candidates Hash (0, 1, or many entries) — deliberately
|
|
85
|
+
# candidates Hash (0, 1, or many entries) — deliberately not
|
|
84
86
|
# raising here, so each caller keeps its own exact refusal
|
|
85
87
|
# wording for "none," "ambiguous," and "declared_by: named the
|
|
86
88
|
# wrong owner" rather than one generic message papering over all
|
|
@@ -89,10 +91,10 @@ module Hecks
|
|
|
89
91
|
pool[description] || {}
|
|
90
92
|
end
|
|
91
93
|
|
|
92
|
-
#
|
|
94
|
+
# Primitive 3 — a live scan over already-built sibling objects'
|
|
93
95
|
# own collections, not a separately-maintained pool at all —
|
|
94
96
|
# `ValueObjectBuilder#invariant`'s own shape: every sibling value
|
|
95
|
-
# object on the same aggregate has
|
|
97
|
+
# object on the same aggregate has already been built by the time
|
|
96
98
|
# a later one references back (declaration order, the same
|
|
97
99
|
# constraint every scope in this family carries), so there is
|
|
98
100
|
# nothing to write through — just read their own already-declared
|
|
@@ -105,36 +107,36 @@ module Hecks
|
|
|
105
107
|
.find { |rule| rule.description == description }
|
|
106
108
|
end
|
|
107
109
|
|
|
108
|
-
#
|
|
109
|
-
# Hash (that
|
|
110
|
+
# **Which construct uses which primitive** — no longer a Ruby-only
|
|
111
|
+
# Hash (that was this constant's own shape, one round ago): the
|
|
110
112
|
# user's own correction — "my goal is that if they read the same
|
|
111
113
|
# table they behave identically" — means a table only Ruby ever
|
|
112
114
|
# reads cannot deliver that, no matter how faithfully it is
|
|
113
115
|
# cross-checked afterward. `Keyword#resolves_via`/`#disambiguator`
|
|
114
|
-
# (self-hosted, `syntax.bluebook`) is the
|
|
115
|
-
#
|
|
116
|
+
# (self-hosted, `syntax.bluebook`) is the real table now — the
|
|
117
|
+
# same generated data `rust/parser/src/keywords.rs` is generated
|
|
116
118
|
# from (`bin/project_parser_table`). `#lookup` reads it live.
|
|
117
119
|
#
|
|
118
|
-
#
|
|
120
|
+
# **The one unavoidable exception**: the meta-domain's own bootstrap
|
|
119
121
|
# (`MetaValidator.load_grammar_into`) dispatches `given`/
|
|
120
|
-
# `invariant` on
|
|
122
|
+
# `invariant` on itself 61 times while building the very grammar
|
|
121
123
|
# table that would answer "how does given/Aggregate resolve" —
|
|
122
124
|
# `MetaValidator.grammar_registry`/`SyntaxBoot.call` are not
|
|
123
|
-
# ready yet, and cannot be made ready without
|
|
125
|
+
# ready yet, and cannot be made ready without already having
|
|
124
126
|
# resolved a `given` somewhere upstream. `MetaValidator.
|
|
125
|
-
# bootstrapping?` is the
|
|
127
|
+
# bootstrapping?` is the same guard `MetaValidator.call` (the
|
|
126
128
|
# judge) already uses to skip self-judging during this exact
|
|
127
129
|
# window — `#lookup` uses it too, falling back to
|
|
128
|
-
# `BOOTSTRAP_FALLBACK` (below)
|
|
130
|
+
# `BOOTSTRAP_FALLBACK` (below) only while it's true. Every real
|
|
129
131
|
# domain (banking, pizzas, compliance, any future one) boots
|
|
130
|
-
#
|
|
132
|
+
# after `grammar_registry` is fully built and memoized, so reads
|
|
131
133
|
# the real table, every time, no exception.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
134
|
+
#
|
|
135
|
+
# No longer kept in sync by hand — the same `resolves_via`/
|
|
136
|
+
# `disambiguator` columns, projected ahead of time into the
|
|
137
|
+
# committed lib/hecks/bluebook/dsl/bootstrap_table.rb
|
|
138
|
+
# (bin/project_bootstrap_table, pinned by spec/bootstrap_table_spec.rb).
|
|
139
|
+
BOOTSTRAP_FALLBACK = BootstrapTable::RESOLVES
|
|
138
140
|
|
|
139
141
|
def lookup(word, context)
|
|
140
142
|
if MetaValidator.bootstrapping?
|
|
@@ -149,16 +151,16 @@ module Hecks
|
|
|
149
151
|
end
|
|
150
152
|
end
|
|
151
153
|
|
|
152
|
-
# A
|
|
154
|
+
# A live cross-check, not a spec-only one — every real domain's
|
|
153
155
|
# own boot (not just `bundle exec rspec`) now genuinely fails
|
|
154
156
|
# loudly if a construct's own hand-written resolution method
|
|
155
157
|
# ever disagrees with what the self-hosted grammar table claims
|
|
156
158
|
# for it. Each of the three `reference_named_*` methods below
|
|
157
|
-
# calls this
|
|
159
|
+
# calls this first, naming the primitive it is about to use —
|
|
158
160
|
# if `syntax.bluebook`'s own `resolves_via` for this exact
|
|
159
161
|
# (word, context) pair ever names something else, this is a
|
|
160
162
|
# real drift between the language's own self-description and
|
|
161
|
-
# its own implementation, caught at the next boot of
|
|
163
|
+
# its own implementation, caught at the next boot of anything,
|
|
162
164
|
# not just the next `rspec` run.
|
|
163
165
|
def verify_resolves_via!(word, context, expected_primitive)
|
|
164
166
|
actual = lookup(word, context)[:resolves_via]
|
|
@@ -28,10 +28,10 @@ module Hecks
|
|
|
28
28
|
@backfills = []
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
#
|
|
31
|
+
# Renamed from `rename`/`move`/`convert`/`retype`/`compute`/
|
|
32
32
|
# `rekey`/`backfill` (all seven below) — item #13's full
|
|
33
33
|
# metaprogrammed dispatch (slice 4c). Not bootstrap-reachable
|
|
34
|
-
# (translation.bluebook describes
|
|
34
|
+
# (translation.bluebook describes its own structure with
|
|
35
35
|
# aggregate/entity/attribute, never with these — they're
|
|
36
36
|
# words for real, user-authored `.translation` files only,
|
|
37
37
|
# loaded after the grammar table exists), so none need a
|
|
@@ -93,7 +93,7 @@ module Hecks
|
|
|
93
93
|
@computes << TranslationCompute.new(old_path.to_s, to.to_s, sql.to_s)
|
|
94
94
|
end
|
|
95
95
|
|
|
96
|
-
#
|
|
96
|
+
# The aggregate's own identity, changing what it's computed from —
|
|
97
97
|
# not a field crossing a boundary (`move`), not a value's own
|
|
98
98
|
# transform (`compute`): the record's key. No path arguments,
|
|
99
99
|
# unlike every rule above — nothing is consumed from or moved into
|
|
@@ -107,8 +107,8 @@ module Hecks
|
|
|
107
107
|
@rekeys << TranslationRekey.new(sql.to_s)
|
|
108
108
|
end
|
|
109
109
|
|
|
110
|
-
# A
|
|
111
|
-
# `drop`. Nothing to rename, move, or convert
|
|
110
|
+
# A newly added, required attribute — the addition-side sibling of
|
|
111
|
+
# `drop`. Nothing to rename, move, or convert from, since old data
|
|
112
112
|
# never held this field at all; `default` is what an existing
|
|
113
113
|
# record reads until the next command against it writes a real
|
|
114
114
|
# value. Adapter-agnostic, unlike `compute` — applied the same
|
|
@@ -128,11 +128,11 @@ module Hecks
|
|
|
128
128
|
# The scaffold writes this where it cannot decide; a file carrying
|
|
129
129
|
# one can only boot into this refusal — never a guess.
|
|
130
130
|
#
|
|
131
|
-
#
|
|
131
|
+
# Renamed from `unresolved` — item #13's full metaprogrammed
|
|
132
132
|
# dispatch (slice 4). Builds its own message with real branching
|
|
133
133
|
# (empty vs. named candidates, a special :identity case), not a
|
|
134
134
|
# fixed string a boolean `refuses:` flag could express — reached
|
|
135
|
-
# through `calls:` instead, like `attribute`/`role`.
|
|
135
|
+
# through `calls:` instead, like `attribute`/`role`. Not
|
|
136
136
|
# bootstrap-reachable: translation.bluebook (loaded during
|
|
137
137
|
# bootstrap, to describe the translation DSL itself) never
|
|
138
138
|
# writes `unresolved` — that word is only ever used by real,
|
|
@@ -178,7 +178,7 @@ module Hecks
|
|
|
178
178
|
path.to_s.include?(".") ? path.to_s.inspect : ":#{path}"
|
|
179
179
|
end
|
|
180
180
|
|
|
181
|
-
#
|
|
181
|
+
# The scaffold's own hint for the one drift it can detect but never
|
|
182
182
|
# resolve on its own — an aggregate's `identified_by` changed. Not
|
|
183
183
|
# a field to rename/move/drop, so none of the ordinary hints fit;
|
|
184
184
|
# `coverage_check.rb#check_identity_unchanged!` is the real gate,
|
|
@@ -211,7 +211,7 @@ module Hecks
|
|
|
211
211
|
@retired = []
|
|
212
212
|
end
|
|
213
213
|
|
|
214
|
-
#
|
|
214
|
+
# Renamed from `aggregate` — item #13's full metaprogrammed
|
|
215
215
|
# dispatch (slice 4c). Not bootstrap-reachable — this "Translation"
|
|
216
216
|
# -context `aggregate` (opens a TranslationAggregateBuilder) is a
|
|
217
217
|
# different (context, word) pair than "Bluebook"-context
|
|
@@ -23,7 +23,7 @@ module Hecks
|
|
|
23
23
|
@owner_value_objects = owner_value_objects
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
#
|
|
26
|
+
# The wrapper block is gone (ADR 0025, "Attributes" — "closed sets
|
|
27
27
|
# lose the wrapper block"). `member` lines are bare now, written
|
|
28
28
|
# directly in the `value_object` body with no `one_of do ... end`
|
|
29
29
|
# around them — `build`'s own `closed_set: @closed_set ||
|
|
@@ -39,24 +39,24 @@ module Hecks
|
|
|
39
39
|
# use the inline form on one of its own attributes. One `one_of`
|
|
40
40
|
# method now, not two.
|
|
41
41
|
#
|
|
42
|
-
#
|
|
42
|
+
# Legacy under shadow-parsing (S0a's own bridge) — frozen era text
|
|
43
43
|
# still writes the block form (2 locations in
|
|
44
44
|
# `examples/banking/data/eras/banking/1.bluebook`, duplicated once
|
|
45
45
|
# more in that era's own archive copy), so `EraGuard.shadow_parse`
|
|
46
46
|
# still needs to read it. `block_given?` is what tells the two
|
|
47
47
|
# calling shapes apart: the type-position form
|
|
48
48
|
# (`one_of("a", "b")`) never passes a block, only the wrapper does.
|
|
49
|
-
#
|
|
50
|
-
# (slice 5).
|
|
49
|
+
# Renamed from `one_of` — item #13's full metaprogrammed dispatch
|
|
50
|
+
# (slice 5). Same name as `AttributeCollector#one_of_impl`'s own
|
|
51
51
|
# — required for the `super(*values)` call below to keep
|
|
52
52
|
# resolving; see that method's own comment. Reached directly
|
|
53
53
|
# through its own "ValueObject"-context Keyword row (the
|
|
54
54
|
# block-wrapper form has its own row, distinct from "Type"'s),
|
|
55
|
-
# not through the Type-position fallback this word's
|
|
55
|
+
# not through the Type-position fallback this word's other
|
|
56
56
|
# context uses.
|
|
57
57
|
def one_of_impl(*values, &block)
|
|
58
58
|
unless block
|
|
59
|
-
#
|
|
59
|
+
# No values, no block is the scalar spelling — nonsensical, not
|
|
60
60
|
# merely inert: it names a closed set with nothing in it. The
|
|
61
61
|
# original block form caught this by a side effect (`@closed_set
|
|
62
62
|
# = true` ran unconditionally, before the `if block`), and this
|
|
@@ -83,7 +83,7 @@ module Hecks
|
|
|
83
83
|
instance_eval(&block)
|
|
84
84
|
end
|
|
85
85
|
|
|
86
|
-
#
|
|
86
|
+
# Renamed from `member` — item #13's full metaprogrammed dispatch
|
|
87
87
|
# (slice 4c). Bootstrap-reachable, in
|
|
88
88
|
# GenericDispatch::BOOTSTRAP_CALLS_FALLBACK.
|
|
89
89
|
def member_impl(**fields)
|
|
@@ -92,11 +92,11 @@ module Hecks
|
|
|
92
92
|
@members << fields
|
|
93
93
|
end
|
|
94
94
|
|
|
95
|
-
#
|
|
95
|
+
# No block is a reference, not a fresh declaration — the same
|
|
96
96
|
# move S10 already made for `CommandBuilder#given` (ADR 0025,
|
|
97
97
|
# "a precondition shared across commands is declared once... a
|
|
98
98
|
# command references it by name"), one level over: a rule
|
|
99
|
-
# shared across
|
|
99
|
+
# shared across sibling value objects on the same aggregate,
|
|
100
100
|
# declared once, on the first one to need it. Real, live
|
|
101
101
|
# redundancy this closes: `Account`'s own `Money`/`PositiveMoney`
|
|
102
102
|
# both declared `invariant("a currency is a three-letter code")
|
|
@@ -105,7 +105,7 @@ module Hecks
|
|
|
105
105
|
# the referencing value object's own build time, against
|
|
106
106
|
# whatever sibling value objects the aggregate has already
|
|
107
107
|
# built, the same ordering rule `given` carries.
|
|
108
|
-
#
|
|
108
|
+
# Renamed from `invariant` — item #13's full metaprogrammed
|
|
109
109
|
# dispatch (slice 4b). Bootstrap-reachable, in
|
|
110
110
|
# GenericDispatch::BOOTSTRAP_CALLS_FALLBACK.
|
|
111
111
|
def invariant_impl(description, &predicate)
|
|
@@ -119,7 +119,7 @@ module Hecks
|
|
|
119
119
|
|
|
120
120
|
private
|
|
121
121
|
|
|
122
|
-
#
|
|
122
|
+
# Primitive 3 (RuleReference#resolve_sibling_scan) — see that
|
|
123
123
|
# method's own comment for why this is a live scan, not a pool.
|
|
124
124
|
def reference_named_invariant(description)
|
|
125
125
|
verify_resolves_via!("invariant", "ValueObject", "sibling_scan")
|
|
@@ -157,15 +157,15 @@ module Hecks
|
|
|
157
157
|
|
|
158
158
|
private
|
|
159
159
|
|
|
160
|
-
#
|
|
161
|
-
# overriding `AttributeCollector`'s own refusal (every
|
|
162
|
-
# includer has no meaningful use for this).
|
|
160
|
+
# **The new spelling** — `attribute :name, String, one_of: %w[...]`,
|
|
161
|
+
# overriding `AttributeCollector`'s own refusal (every other
|
|
162
|
+
# includer has no meaningful use for this). Private, like the
|
|
163
163
|
# module's own version it overrides — it is a callback `attribute`
|
|
164
164
|
# invokes on itself, never a word a bluebook author calls by name.
|
|
165
|
-
# Refuses a
|
|
165
|
+
# Refuses a second attribute naming one_of: on the same value
|
|
166
166
|
# object outright — a single-field set names exactly one field, by
|
|
167
167
|
# construction; two would be structurally ambiguous about which
|
|
168
|
-
# field each member line belongs to. `build` refuses the
|
|
168
|
+
# field each member line belongs to. `build` refuses the other
|
|
169
169
|
# half of that same rule (this attribute coexisting with unrelated
|
|
170
170
|
# ones on a multi-field object).
|
|
171
171
|
def install_inline_closed_set(field, values)
|
|
@@ -2,46 +2,49 @@ require_relative "generic_dispatch"
|
|
|
2
2
|
module Hecks
|
|
3
3
|
module Bluebook
|
|
4
4
|
module DSL
|
|
5
|
-
#
|
|
5
|
+
# The Ruby-side `word_gate` (`rust/parser/src/parse/mod.rs`'s own,
|
|
6
6
|
# read there first — this is the same job, one level up: Rust's own
|
|
7
|
-
# gate refuses a mistyped/inadmissible
|
|
8
|
-
# moment it reads a line of `.bluebook`
|
|
7
|
+
# gate refuses a mistyped/inadmissible word directly, at the
|
|
8
|
+
# moment it reads a line of `.bluebook` source text, before any
|
|
9
9
|
# per-construct parsing runs. Ruby never lexes source text — a
|
|
10
|
-
# `.bluebook` file
|
|
10
|
+
# `.bluebook` file is Ruby, so `given("x")` is already a real
|
|
11
11
|
# method call by the time any of this code runs, and Ruby's own
|
|
12
|
-
# method dispatch already refuses an
|
|
13
|
-
#
|
|
14
|
-
# is consult the self-hosted grammar table
|
|
12
|
+
# method dispatch already refuses an arity mismatch on an
|
|
13
|
+
# existing method for free. What Ruby's own dispatch does not do
|
|
14
|
+
# is consult the self-hosted grammar table at all — a mistyped
|
|
15
15
|
# word (`giv3n("x")`) or a word used in the wrong context
|
|
16
16
|
# (`identified_by` inside a `command` block) just raises Ruby's
|
|
17
17
|
# own generic `NoMethodError`, naming nothing about what the
|
|
18
18
|
# language actually admits. This module closes that gap.
|
|
19
19
|
#
|
|
20
|
-
#
|
|
20
|
+
# ## What reaches this module
|
|
21
|
+
#
|
|
22
|
+
# `method_missing`/`respond_to_missing?` only — a word this
|
|
21
23
|
# builder class already answers with an ordinary `def` (or a
|
|
22
|
-
# shared mixin
|
|
24
|
+
# method a shared mixin such as `AttributeCollector` defines) never
|
|
23
25
|
# reaches this module at all; Ruby's own method lookup finds it
|
|
24
|
-
# first, and
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
# item #13's full metaprogrammed dispatch
|
|
28
|
-
# table-unification survey)
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
# is genuinely unchanged.
|
|
26
|
+
# first, and not every word has had its hand-written method
|
|
27
|
+
# removed. A word the grammar admits whose builder has no
|
|
28
|
+
# hand-written method executes for real here, via `GenericDispatch`
|
|
29
|
+
# (item #13's full metaprogrammed dispatch, whole-project
|
|
30
|
+
# table-unification survey) — see that module's own header for
|
|
31
|
+
# exactly which ones, and the full account of what was verified
|
|
32
|
+
# before each was migrated. A mistyped or wrongly-contexted word
|
|
33
|
+
# gets the same real, helpful, table-driven refusal Rust's own
|
|
34
|
+
# `word_gate` already gives, instead of Ruby's own generic
|
|
35
|
+
# `NoMethodError`.
|
|
36
|
+
#
|
|
37
|
+
# ## `GRAMMAR_CONTEXT`
|
|
37
38
|
#
|
|
38
39
|
# `self.class::GRAMMAR_CONTEXT` — each including class names which
|
|
39
40
|
# row of the self-hosted `Context` closed set it corresponds to
|
|
40
41
|
# (`AggregateBuilder::GRAMMAR_CONTEXT = "Aggregate"`, etc.) — the
|
|
41
|
-
#
|
|
42
|
+
# same string `word_gate`'s own `context` parameter already is on
|
|
42
43
|
# the Rust side, read off the identical table.
|
|
43
44
|
#
|
|
44
|
-
#
|
|
45
|
+
# ## Bootstrapping
|
|
46
|
+
#
|
|
47
|
+
# Bootstrapping gated, the same reason `RuleReference#lookup`
|
|
45
48
|
# already is (`rule_reference.rb`'s own comment has the full
|
|
46
49
|
# story) — the meta-domain's own bootstrap calls dozens of
|
|
47
50
|
# keywords on itself before its own grammar table exists to
|
|
@@ -52,28 +55,31 @@ module Hecks
|
|
|
52
55
|
# is deliberately no fallback covering the whole ~200-row table —
|
|
53
56
|
# that would defeat the entire point.
|
|
54
57
|
#
|
|
55
|
-
#
|
|
56
|
-
#
|
|
57
|
-
# `GenericDispatch::BOOTSTRAP_CALLS_FALLBACK`,
|
|
58
|
-
#
|
|
59
|
-
# `calls:` column
|
|
60
|
-
#
|
|
61
|
-
#
|
|
58
|
+
# One narrow exception (item #13's full metaprogrammed dispatch,
|
|
59
|
+
# slice 3, whole-project table-unification survey):
|
|
60
|
+
# `GenericDispatch::BOOTSTRAP_CALLS_FALLBACK`, an explicit table
|
|
61
|
+
# naming the same (context, word) -> method pairs the real
|
|
62
|
+
# `calls:` column carries, projected ahead of time into the
|
|
63
|
+
# committed `bootstrap_table.rb` — it matters only for words both
|
|
64
|
+
# migrated to the `calls:` shape and bootstrap-reachable
|
|
65
|
+
# (`attribute`, for one). This is the one place in this whole arc a
|
|
62
66
|
# bootstrap fallback was worth building despite `RuleReference`'s
|
|
63
|
-
# own precedent against it: it duplicates
|
|
64
|
-
#
|
|
67
|
+
# own precedent against it: it duplicates no logic, only a method
|
|
68
|
+
# name — `attribute_impl`'s own real, hand-written body is called
|
|
65
69
|
# either way, bootstrap or not, so there is nothing here that can
|
|
66
70
|
# drift the way a full behavioral duplicate could.
|
|
67
71
|
#
|
|
68
|
-
#
|
|
72
|
+
# ## `word_gate_dispatch` and the type-position fallback
|
|
73
|
+
#
|
|
74
|
+
# Two further pieces, both slice 5:
|
|
69
75
|
# - `word_gate_dispatch` is the same admission+dispatch logic
|
|
70
76
|
# `method_missing` below runs, factored out so a class with
|
|
71
|
-
# its
|
|
77
|
+
# its own class-level `method_missing` (`HecksagonBuilder`'s/
|
|
72
78
|
# `WorldBuilder`'s genuinely open-ended verb vocabulary) can
|
|
73
79
|
# call it directly and fall back to its own open-verb handling
|
|
74
80
|
# only when this returns `NOT_ADMITTED` — a class-level `def`
|
|
75
81
|
# always wins over an included module's in Ruby's own method
|
|
76
|
-
# resolution, so their
|
|
82
|
+
# resolution, so their own `method_missing` is the only one
|
|
77
83
|
# that ever runs for them, and this is what lets a real,
|
|
78
84
|
# closed-set word (`port`/`realm`/`latest`) still reach
|
|
79
85
|
# `GenericDispatch` despite that.
|
|
@@ -84,7 +90,7 @@ module Hecks
|
|
|
84
90
|
# "Type" builder `self.class::GRAMMAR_CONTEXT` could ever
|
|
85
91
|
# name. See that method's own comment.
|
|
86
92
|
module WordGate
|
|
87
|
-
# A caller with its
|
|
93
|
+
# A caller with its own class-level `method_missing`
|
|
88
94
|
# (`HecksagonBuilder`/`WorldBuilder` — see `word_gate_dispatch`'s
|
|
89
95
|
# own header) checks for this to tell "not a word the grammar
|
|
90
96
|
# admits at all" apart from every other outcome below (a real
|
|
@@ -92,7 +98,7 @@ module Hecks
|
|
|
92
98
|
# caller can fall through to its own open-ended handling instead.
|
|
93
99
|
NOT_ADMITTED = Object.new.freeze
|
|
94
100
|
|
|
95
|
-
#
|
|
101
|
+
# Private, matching Ruby's own convention for both (`Object`
|
|
96
102
|
# defines them private too) — and load-bearing here, not just
|
|
97
103
|
# style: `spec/syntax_conformance_spec.rb`'s "declares every
|
|
98
104
|
# word X answers" check walks `public_instance_methods`, and a
|
|
@@ -129,23 +135,23 @@ module Hecks
|
|
|
129
135
|
result
|
|
130
136
|
end
|
|
131
137
|
|
|
132
|
-
#
|
|
138
|
+
# The core admission+dispatch logic, factored out of
|
|
133
139
|
# `method_missing` — item #13's full metaprogrammed dispatch
|
|
134
140
|
# (slice 5, whole-project table-unification survey) — so a
|
|
135
|
-
# class with its
|
|
141
|
+
# class with its own class-level `method_missing`
|
|
136
142
|
# (`HecksagonBuilder`'s/`WorldBuilder`'s genuinely open-ended
|
|
137
143
|
# verb vocabulary, `persisted_by "Heki"`/`posted_by "Carrier"`,
|
|
138
|
-
# can never
|
|
139
|
-
#
|
|
144
|
+
# can never be a closed table) can still route a word the
|
|
145
|
+
# grammar admits through here first, falling back to its own
|
|
140
146
|
# open-verb handling only for what this doesn't recognize at
|
|
141
147
|
# all — unblocking `Hecksagon#port`/`World#realm`/`World#latest`,
|
|
142
148
|
# each a real, closed-set word that happened to sit on a class
|
|
143
149
|
# whose own `method_missing` a class-level `def` always wins
|
|
144
150
|
# over Ruby's own module-inclusion order.
|
|
145
151
|
#
|
|
146
|
-
#
|
|
152
|
+
# Never raises "not admitted" — returns `NOT_ADMITTED` instead,
|
|
147
153
|
# so the caller (this module's own `method_missing`, or one of
|
|
148
|
-
# the two above) decides what that means for it.
|
|
154
|
+
# the two above) decides what that means for it. Does still
|
|
149
155
|
# raise the richer, table-driven refusals below once a word is
|
|
150
156
|
# admitted-but-unimplemented, or admitted-somewhere-else-only —
|
|
151
157
|
# those are real, useful refusals regardless of which
|
|
@@ -161,16 +167,16 @@ module Hecks
|
|
|
161
167
|
keywords = rows[:keywords]
|
|
162
168
|
admitted = keywords.select { |row| row[:context] == context && (row[:word] == word.to_s || row[:was] == word.to_s) }
|
|
163
169
|
|
|
164
|
-
#
|
|
170
|
+
# **The type-position fallback** — item #13's full metaprogrammed
|
|
165
171
|
# dispatch (slice 5). `one_of`/`list_of`, called inside an
|
|
166
172
|
# attribute's own type argument (`attribute :x,
|
|
167
173
|
# one_of("a","b")`), run with `self` as whatever builder is
|
|
168
|
-
#
|
|
174
|
+
# currently instance_eval'ing — there is no dedicated "Type"
|
|
169
175
|
# builder of its own; every attribute()-taking builder answers
|
|
170
176
|
# these identically, through the shared `AttributeCollector`
|
|
171
|
-
# mixin. `self.class::GRAMMAR_CONTEXT` can never actually
|
|
177
|
+
# mixin. `self.class::GRAMMAR_CONTEXT` can never actually be
|
|
172
178
|
# "Type", so a word admitted only there would otherwise look
|
|
173
|
-
# inadmissible everywhere. Checked only once
|
|
179
|
+
# inadmissible everywhere. Checked only once this context has
|
|
174
180
|
# already come up empty, so a context with its own same-named
|
|
175
181
|
# row (`ValueObject`'s own `one_of`, the block-wrapper form)
|
|
176
182
|
# keeps using that instead, unaffected.
|
|
@@ -190,11 +196,11 @@ module Hecks
|
|
|
190
196
|
"'#{word}' is not a word #{context} admits — legal words here: #{legal.join(', ')}"
|
|
191
197
|
end
|
|
192
198
|
|
|
193
|
-
#
|
|
199
|
+
# Item #13's full metaprogrammed dispatch — the word is
|
|
194
200
|
# admitted here, and this builder has no hand-written method
|
|
195
201
|
# left for it; before falling through to the "not yet
|
|
196
202
|
# implemented" refusal every word without one still gets,
|
|
197
|
-
# offer it to GenericDispatch — the
|
|
203
|
+
# offer it to GenericDispatch — the safe, verified subset of
|
|
198
204
|
# words whose whole behavior is now executed off this same
|
|
199
205
|
# table, not just checked against it.
|
|
200
206
|
dispatched = GenericDispatch.try(self, context, word.to_s, args, kwargs, block, rows)
|
|
@@ -215,13 +221,13 @@ module Hecks
|
|
|
215
221
|
super
|
|
216
222
|
end
|
|
217
223
|
|
|
218
|
-
# A word admitted
|
|
224
|
+
# A word admitted somewhere, just not in this context, still
|
|
219
225
|
# falls through to Ruby's own `NoMethodError` rather than this
|
|
220
226
|
# module's own richer refusal — `method_missing` fires for
|
|
221
227
|
# every typo in the whole codebase (this class's own genuinely
|
|
222
228
|
# private helper methods included), not just DSL keyword calls;
|
|
223
|
-
# only raise the
|
|
224
|
-
# least
|
|
229
|
+
# only raise the rich, table-driven message when the word is at
|
|
230
|
+
# least something the grammar knows about, anywhere, so an
|
|
225
231
|
# unrelated Ruby-level typo inside a builder's own private code
|
|
226
232
|
# keeps its own ordinary, unconfusing `NoMethodError`.
|
|
227
233
|
def admitted_anywhere?(rows, word)
|