hecks 0.2.0 → 0.3.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 +5 -5
- data/lib/hecks/adapters/driven/claude_code.adapter +3 -0
- data/lib/hecks/adapters/driven/claude_code.rb +127 -0
- data/lib/hecks/adapters/driven/d1.adapter +12 -0
- data/lib/hecks/adapters/driven/d1.rb +403 -0
- data/lib/hecks/adapters/driven/folder.adapter +3 -0
- data/lib/hecks/adapters/driven/folder.rb +199 -0
- data/lib/hecks/adapters/driven/google_authentication.adapter +3 -0
- data/lib/hecks/adapters/driven/google_authentication.rb +100 -0
- data/lib/hecks/adapters/driven/governance_authorization.adapter +3 -0
- data/lib/hecks/adapters/driven/governance_authorization.rb +62 -0
- data/lib/hecks/adapters/driven/heki/journal.rb +51 -0
- data/lib/hecks/adapters/driven/heki/saga_store.rb +0 -0
- data/lib/hecks/adapters/driven/heki/snapshot.rb +38 -0
- data/lib/hecks/adapters/driven/heki.adapter +4 -0
- data/lib/hecks/adapters/driven/heki.rb +148 -0
- data/lib/hecks/adapters/driven/identity_registry.adapter +3 -0
- data/lib/hecks/adapters/driven/identity_registry.rb +26 -0
- data/lib/hecks/adapters/driven/in_memory_ordering.rb +51 -0
- data/lib/hecks/adapters/driven/lambda/client.rb +63 -0
- data/lib/hecks/adapters/driven/lambda.adapter +4 -0
- data/lib/hecks/adapters/driven/lambda.rb +131 -0
- data/lib/hecks/adapters/driven/memory.adapter +3 -0
- data/lib/hecks/adapters/driven/memory.rb +103 -0
- data/lib/hecks/adapters/driven/mock_stripe_adapter.adapter +3 -0
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +28 -0
- data/lib/hecks/adapters/driven/postgres/codec.rb +80 -0
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +168 -0
- data/lib/hecks/adapters/driven/postgres.adapter +5 -0
- data/lib/hecks/adapters/driven/postgres.rb +391 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/era_store.rb +171 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/field_cache.rb +190 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/head_compiler.rb +429 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/mint_transaction.rb +166 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/provisioning.rb +286 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/resumable_backfill.rb +168 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/tail_merge.rb +163 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage/transform_installer.rb +114 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage.rb +137 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/coverage_check.rb +89 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/era_resolver.rb +82 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/merge_coordinator.rb +43 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager/minter.rb +132 -0
- data/lib/hecks/adapters/driven/postgres_era/lineage_manager.rb +74 -0
- data/lib/hecks/adapters/driven/postgres_era.adapter +6 -0
- data/lib/hecks/adapters/driven/postgres_era.rb +671 -0
- data/lib/hecks/adapters/driven/prism.adapter +3 -0
- data/lib/hecks/adapters/driven/prism.rb +80 -0
- data/lib/hecks/adapters/driven/secure_random_identity.adapter +3 -0
- data/lib/hecks/adapters/driven/secure_random_identity.rb +14 -0
- data/lib/hecks/adapters/driven/sql_query_builder.rb +221 -0
- data/lib/hecks/adapters/driven/sqlite/codec.rb +63 -0
- data/lib/hecks/adapters/driven/sqlite/projection.rb +105 -0
- data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +180 -0
- data/lib/hecks/adapters/driven/sqlite.adapter +9 -0
- data/lib/hecks/adapters/driven/sqlite.rb +285 -0
- data/lib/hecks/adapters/driven/system_clock.adapter +3 -0
- data/lib/hecks/adapters/driven/system_clock.rb +14 -0
- data/lib/hecks/adapters/driven.rb +36 -0
- data/lib/hecks/adapters.rb +6 -0
- data/lib/hecks/behaviors/dsl.rb +96 -0
- data/lib/hecks/behaviors/expectations.rb +280 -0
- data/lib/hecks/behaviors/ir.rb +31 -0
- data/lib/hecks/behaviors/rspec.rb +42 -0
- data/lib/hecks/behaviors/runner.rb +96 -0
- data/lib/hecks/behaviors.rb +25 -0
- data/lib/hecks/bluebook/aggregate.rb +108 -0
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +134 -0
- data/lib/hecks/bluebook/assembly/build.rb +48 -0
- data/lib/hecks/bluebook/assembly/contract.rb +112 -0
- data/lib/hecks/bluebook/assembly/contracts.rb +409 -0
- data/lib/hecks/bluebook/assembly/marks.rb +227 -0
- data/lib/hecks/bluebook/assembly/specializer.rb +70 -0
- data/lib/hecks/bluebook/assembly.rb +78 -0
- data/lib/hecks/bluebook/attribute.rb +96 -0
- data/lib/hecks/bluebook/behaviour/aggregate.rb +83 -0
- data/lib/hecks/bluebook/behaviour/attribute.rb +27 -0
- data/lib/hecks/bluebook/behaviour/chapter.rb +72 -0
- data/lib/hecks/bluebook/behaviour/command.rb +116 -0
- data/lib/hecks/bluebook/behaviour/domain_port.rb +25 -0
- data/lib/hecks/bluebook/behaviour/entity.rb +59 -0
- data/lib/hecks/bluebook/behaviour/hexagon.rb +50 -0
- data/lib/hecks/bluebook/behaviour/lifecycle.rb +51 -0
- data/lib/hecks/bluebook/behaviour/policy.rb +52 -0
- data/lib/hecks/bluebook/behaviour/process_manager.rb +38 -0
- data/lib/hecks/bluebook/behaviour/query.rb +10 -0
- data/lib/hecks/bluebook/behaviour/read_model.rb +29 -0
- data/lib/hecks/bluebook/behaviour/traits.rb +81 -0
- data/lib/hecks/bluebook/behaviour/value_object.rb +33 -0
- data/lib/hecks/bluebook/chapter.rb +68 -0
- data/lib/hecks/bluebook/command.rb +124 -0
- data/lib/hecks/bluebook/domain_port.rb +102 -0
- data/lib/hecks/bluebook/dsl/adapter_builder.rb +34 -0
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +906 -0
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +327 -0
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +71 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +1018 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +626 -0
- data/lib/hecks/bluebook/dsl/const_shim.rb +81 -0
- data/lib/hecks/bluebook/dsl/domain_port_builder.rb +79 -0
- data/lib/hecks/bluebook/dsl/entity_builder.rb +305 -0
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +366 -0
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +163 -0
- data/lib/hecks/bluebook/dsl/identity_declaration.rb +191 -0
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +44 -0
- data/lib/hecks/bluebook/dsl/malformed.rb +7 -0
- data/lib/hecks/bluebook/dsl/policy_builder.rb +120 -0
- data/lib/hecks/bluebook/dsl/port_builder.rb +30 -0
- data/lib/hecks/bluebook/dsl/port_operation_builder.rb +142 -0
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +207 -0
- data/lib/hecks/bluebook/dsl/query_builder.rb +113 -0
- data/lib/hecks/bluebook/dsl/read_model_builder.rb +233 -0
- data/lib/hecks/bluebook/dsl/rule_reference.rb +172 -0
- data/lib/hecks/bluebook/dsl/translation_builder.rb +243 -0
- data/lib/hecks/bluebook/dsl/value_object_builder.rb +178 -0
- data/lib/hecks/bluebook/dsl/word_gate.rb +221 -0
- data/lib/hecks/bluebook/dsl/world_builder.rb +77 -0
- data/lib/hecks/bluebook/dsl.rb +45 -0
- data/lib/hecks/bluebook/entity.rb +103 -0
- data/lib/hecks/bluebook/expression/canonical_form.rb +55 -0
- data/lib/hecks/bluebook/expression/evaluator.rb +261 -0
- data/lib/hecks/bluebook/expression/projection.json +170 -0
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +233 -0
- data/lib/hecks/bluebook/expression/resolver.rb +630 -0
- data/lib/hecks/bluebook/expression.rb +13 -0
- data/lib/hecks/bluebook/hexagon.rb +60 -0
- data/lib/hecks/bluebook/lifecycle.rb +42 -0
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +54 -0
- data/lib/hecks/bluebook/meta_validator/judge.rb +559 -0
- data/lib/hecks/bluebook/meta_validator/plan.rb +332 -0
- data/lib/hecks/bluebook/meta_validator/port_judge.rb +47 -0
- data/lib/hecks/bluebook/meta_validator/readings.rb +350 -0
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +312 -0
- data/lib/hecks/bluebook/meta_validator/shapes.rb +246 -0
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +255 -0
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +138 -0
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +78 -0
- data/lib/hecks/bluebook/meta_validator.rb +452 -0
- data/lib/hecks/bluebook/model_check.rb +318 -0
- data/lib/hecks/bluebook/pattern_subset.rb +120 -0
- data/lib/hecks/bluebook/policy.rb +41 -0
- data/lib/hecks/bluebook/process_manager.rb +86 -0
- data/lib/hecks/bluebook/project_discovery.rb +30 -0
- data/lib/hecks/bluebook/project_loader.rb +40 -0
- data/lib/hecks/bluebook/project_register.rb +82 -0
- data/lib/hecks/bluebook/query.rb +61 -0
- data/lib/hecks/bluebook/read_model.rb +109 -0
- data/lib/hecks/bluebook/reference.rb +74 -0
- data/lib/hecks/bluebook/smoke_test.rb +166 -0
- data/lib/hecks/bluebook/synthesizer.rb +95 -0
- data/lib/hecks/bluebook/translation.rb +92 -0
- data/lib/hecks/bluebook/value_object.rb +58 -0
- data/lib/hecks/bluebook.rb +74 -0
- data/lib/hecks/codemod.rb +342 -0
- data/lib/hecks/construct.rb +71 -0
- data/lib/hecks/deploy/bluebook/deploy.bluebook +219 -0
- data/lib/hecks/deploy/bluebook/deploy.hecksagon +4 -0
- data/lib/hecks/deploy/oidc.json +18 -0
- data/lib/hecks/doc/reference.rb +389 -0
- data/lib/hecks/embryonaut_bluebook.rb +75 -0
- data/lib/hecks/facade/cli_door.rb +116 -0
- data/lib/hecks/facade/cli_runner.rb +190 -0
- data/lib/hecks/facade/command_request.rb +105 -0
- data/lib/hecks/facade/handle.rb +173 -0
- data/lib/hecks/facade/json_door.rb +154 -0
- data/lib/hecks/facade/surface/aggregate_door.rb +185 -0
- data/lib/hecks/facade/surface/chapter.rb +107 -0
- data/lib/hecks/facade/surface.rb +48 -0
- data/lib/hecks/facade.rb +44 -0
- data/lib/hecks/forms/app.rb +300 -0
- data/lib/hecks/forms/command_form_renderer.rb +113 -0
- data/lib/hecks/forms/examples/banking_console.bluebook +3 -0
- data/lib/hecks/forms/field_renderer.rb +170 -0
- data/lib/hecks/forms/field_shape.rb +232 -0
- data/lib/hecks/forms/html.rb +53 -0
- data/lib/hecks/forms/index_renderer.rb +35 -0
- data/lib/hecks/forms/page.rb +157 -0
- data/lib/hecks/forms/params.rb +132 -0
- data/lib/hecks/forms/query_form_renderer.rb +114 -0
- data/lib/hecks/forms/record_renderer.rb +115 -0
- data/lib/hecks/forms/record_table.rb +63 -0
- data/lib/hecks/forms/reference_options.rb +30 -0
- data/lib/hecks/forms/value_object_shape.rb +46 -0
- data/lib/hecks/forms.rb +54 -0
- data/lib/hecks/fqn.rb +94 -0
- data/lib/hecks/framework/bluebook/compliance.bluebook +1 -0
- data/lib/hecks/framework/bluebook/console_settings.bluebook +489 -0
- data/lib/hecks/framework/bluebook/framework.hecksagon +32 -0
- data/lib/hecks/framework/bluebook/governance.bluebook +130 -0
- data/lib/hecks/framework/bluebook/identity.bluebook +90 -0
- data/lib/hecks/framework/oidc.json +39 -0
- data/lib/hecks/framework.rb +90 -0
- data/lib/hecks/freezer.rb +67 -0
- data/lib/hecks/fuzzing/invalid_value_generator.rb +86 -0
- data/lib/hecks/fuzzing/isolated_boot.rb +92 -0
- data/lib/hecks/fuzzing/properties.rb +1146 -0
- data/lib/hecks/fuzzing/replay.rb +635 -0
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +93 -0
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +54 -0
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +96 -0
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +185 -0
- data/lib/hecks/fuzzing/sequence_generator.rb +130 -0
- data/lib/hecks/fuzzing/value_generator.rb +177 -0
- data/lib/hecks/fuzzing.rb +12 -0
- data/lib/hecks/grammar/evolve.rb +291 -0
- data/lib/hecks/grammar/expression.bluebook +417 -0
- data/lib/hecks/grammar/expression_operators.json +1152 -0
- data/lib/hecks/grammar/grammar.hecksagon +20 -0
- data/lib/hecks/grammar/oidc.json +69 -0
- data/lib/hecks/grammar/translation.bluebook +203 -0
- data/lib/hecks/grammar.rb +178 -0
- data/lib/hecks/ir.rb +126 -0
- data/lib/hecks/language/adapter.bluebook +116 -0
- data/lib/hecks/language/bluebook/aggregate.bluebook +581 -0
- data/lib/hecks/language/bluebook/attaches/paging.bluebook +76 -0
- data/lib/hecks/language/bluebook/bluebook.bluebook +256 -0
- data/lib/hecks/language/bluebook/bluebook.hecksagon +24 -0
- data/lib/hecks/language/bluebook/command.bluebook +437 -0
- data/lib/hecks/language/bluebook/entity.bluebook +316 -0
- data/lib/hecks/language/bluebook/policy.bluebook +172 -0
- data/lib/hecks/language/bluebook/process_manager.bluebook +264 -0
- data/lib/hecks/language/bluebook/projection.bluebook +267 -0
- data/lib/hecks/language/bluebook/query.bluebook +245 -0
- data/lib/hecks/language/bluebook/shape.bluebook +292 -0
- data/lib/hecks/language/bluebook/syntax.bluebook +447 -0
- data/lib/hecks/language/bluebook/vocabulary.bluebook +364 -0
- data/lib/hecks/language/hecksagon/adapter_binding.bluebook +51 -0
- data/lib/hecks/language/hecksagon/domain_port.bluebook +76 -0
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +131 -0
- data/lib/hecks/language/hecksagon/port_operation.bluebook +102 -0
- data/lib/hecks/language/oidc.json +313 -0
- data/lib/hecks/language/port.bluebook +92 -0
- data/lib/hecks/language/translation/translation.bluebook +110 -0
- data/lib/hecks/language/translation/translation_aggregate.bluebook +267 -0
- data/lib/hecks/language/world/wiring.bluebook +62 -0
- data/lib/hecks/language/world/world.bluebook +84 -0
- data/lib/hecks/literal.rb +125 -0
- data/lib/hecks/naming.rb +121 -0
- data/lib/hecks/ports/access_control.port +4 -0
- data/lib/hecks/ports/access_control.rb +62 -0
- data/lib/hecks/ports/agent/answers.rb +104 -0
- data/lib/hecks/ports/agent.port +4 -0
- data/lib/hecks/ports/agent.rb +167 -0
- data/lib/hecks/ports/authentication.port +4 -0
- data/lib/hecks/ports/authentication.rb +50 -0
- data/lib/hecks/ports/authorization.port +4 -0
- data/lib/hecks/ports/authorization.rb +59 -0
- data/lib/hecks/ports/clock.port +4 -0
- data/lib/hecks/ports/clock.rb +62 -0
- data/lib/hecks/ports/extraction.port +4 -0
- data/lib/hecks/ports/extraction.rb +37 -0
- data/lib/hecks/ports/identity_assignment.port +4 -0
- data/lib/hecks/ports/identity_assignment.rb +45 -0
- data/lib/hecks/ports/identity_generation.port +4 -0
- data/lib/hecks/ports/identity_generation.rb +49 -0
- data/lib/hecks/ports/identity_resolution.port +4 -0
- data/lib/hecks/ports/identity_resolution.rb +40 -0
- data/lib/hecks/ports/loading.port +4 -0
- data/lib/hecks/ports/loading.rb +13 -0
- data/lib/hecks/ports/persistence/append_only.rb +102 -0
- data/lib/hecks/ports/persistence/binding_policy.rb +56 -0
- data/lib/hecks/ports/persistence/execution.rb +18 -0
- data/lib/hecks/ports/persistence/lineage.rb +277 -0
- data/lib/hecks/ports/persistence/null_saga_store.rb +25 -0
- data/lib/hecks/ports/persistence/remote_runtime.rb +42 -0
- data/lib/hecks/ports/persistence/repository_factory.rb +30 -0
- data/lib/hecks/ports/persistence.port +4 -0
- data/lib/hecks/ports/persistence.rb +39 -0
- data/lib/hecks/ports/projection.port +4 -0
- data/lib/hecks/ports/projection.rb +76 -0
- data/lib/hecks/ports/query/in_memory.rb +60 -0
- data/lib/hecks/ports/query/ordering.rb +41 -0
- data/lib/hecks/ports/query.rb +36 -0
- data/lib/hecks/ports.rb +27 -0
- data/lib/hecks/projections/diagrams.rb +413 -0
- data/lib/hecks/projections/ir.rb +18 -0
- data/lib/hecks/projections/model/deviations.rb +98 -0
- data/lib/hecks/projections/model.rb +145 -0
- data/lib/hecks/projections/oidc.rb +110 -0
- data/lib/hecks/projections/parser_table.rb +159 -0
- data/lib/hecks/projections/reference.rb +38 -0
- data/lib/hecks/projections/shape.rb +31 -0
- data/lib/hecks/projections/statements.rb +110 -0
- data/lib/hecks/projections/vocabulary.rb +100 -0
- data/lib/hecks/projections.rb +32 -0
- data/lib/hecks/projector/cli_projector.rb +437 -0
- data/lib/hecks/projector/docs_projector.rb +321 -0
- data/lib/hecks/projector/exporter.rb +141 -0
- data/lib/hecks/projector/ir_projector.rb +18 -0
- data/lib/hecks/projector/narrate_projector.rb +243 -0
- data/lib/hecks/projector/target.rb +97 -0
- data/lib/hecks/projector.rb +186 -0
- data/lib/hecks/query_ir.rb +392 -0
- data/lib/hecks/query_specification/common/authorization_spec.rb +9 -0
- data/lib/hecks/query_specification/common/comparators.rb +25 -0
- data/lib/hecks/query_specification/common/comparison.rb +174 -0
- data/lib/hecks/query_specification/common/cursor_spec.rb +9 -0
- data/lib/hecks/query_specification/common/dsl.rb +58 -0
- data/lib/hecks/query_specification/common/inspection_spec.rb +9 -0
- data/lib/hecks/query_specification/common/limit_spec.rb +9 -0
- data/lib/hecks/query_specification/common/null_policy.rb +80 -0
- data/lib/hecks/query_specification/common/null_semantics.rb +11 -0
- data/lib/hecks/query_specification/common/offset_spec.rb +9 -0
- data/lib/hecks/query_specification/common/options.rb +32 -0
- data/lib/hecks/query_specification/common/order_by.rb +9 -0
- data/lib/hecks/query_specification/common/specification.rb +10 -0
- data/lib/hecks/query_specification/common/where_clause.rb +9 -0
- data/lib/hecks/query_specification/field_path.rb +89 -0
- data/lib/hecks/query_specification/hop_path.rb +130 -0
- data/lib/hecks/query_specification/read_model/specification.rb +18 -0
- data/lib/hecks/query_specification.rb +14 -0
- data/lib/hecks/rendering.rb +48 -0
- data/lib/hecks/router/namespace_installer.rb +157 -0
- data/lib/hecks/router.rb +70 -0
- data/lib/hecks/runtime/caller.rb +50 -0
- data/lib/hecks/runtime/capability_graph.rb +44 -0
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +124 -0
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +248 -0
- data/lib/hecks/runtime/command_interpreter.rb +413 -0
- data/lib/hecks/runtime/command_rules/admissibility.rb +307 -0
- data/lib/hecks/runtime/command_rules/arithmetic.rb +254 -0
- data/lib/hecks/runtime/command_rules/authorization.rb +64 -0
- data/lib/hecks/runtime/command_rules/emission.rb +34 -0
- data/lib/hecks/runtime/command_rules/references.rb +181 -0
- data/lib/hecks/runtime/command_rules.rb +28 -0
- data/lib/hecks/runtime/dependency_planning.rb +231 -0
- data/lib/hecks/runtime/dispatcher.rb +286 -0
- data/lib/hecks/runtime/entity_element.rb +253 -0
- data/lib/hecks/runtime/entity_interpreter.rb +228 -0
- data/lib/hecks/runtime/era_check.rb +136 -0
- data/lib/hecks/runtime/era_guard/shape_diff.rb +128 -0
- data/lib/hecks/runtime/era_guard.rb +193 -0
- data/lib/hecks/runtime/era_tamper.rb +61 -0
- data/lib/hecks/runtime/errors.rb +100 -0
- data/lib/hecks/runtime/event.rb +51 -0
- data/lib/hecks/runtime/identity.rb +128 -0
- data/lib/hecks/runtime/instance.rb +120 -0
- data/lib/hecks/runtime/interpreting.rb +69 -0
- data/lib/hecks/runtime/loader.rb +143 -0
- data/lib/hecks/runtime/policy_interpreter.rb +366 -0
- data/lib/hecks/runtime/port_operation_interpreter.rb +210 -0
- data/lib/hecks/runtime/query_interpreter.rb +254 -0
- data/lib/hecks/runtime/reaction_invocation.rb +245 -0
- data/lib/hecks/runtime/read_model_interpreter.rb +266 -0
- data/lib/hecks/runtime/rebuild_sweep.rb +74 -0
- data/lib/hecks/runtime/reference_hop.rb +99 -0
- data/lib/hecks/runtime/refusal_wording.rb +124 -0
- data/lib/hecks/runtime/registry/saga_persistence.rb +70 -0
- data/lib/hecks/runtime/registry/verification.rb +158 -0
- data/lib/hecks/runtime/registry.rb +218 -0
- data/lib/hecks/runtime/remote_dispatcher.rb +143 -0
- data/lib/hecks/runtime/routing.rb +96 -0
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +97 -0
- data/lib/hecks/runtime/saga_interpreter.rb +301 -0
- data/lib/hecks/runtime/storage_shape.rb +120 -0
- data/lib/hecks/runtime/tenant_check.rb +84 -0
- data/lib/hecks/runtime/tenant_scope.rb +55 -0
- data/lib/hecks/runtime/value/admission.rb +112 -0
- data/lib/hecks/runtime/value/coercion.rb +500 -0
- data/lib/hecks/runtime/value/invariant_violation.rb +5 -0
- data/lib/hecks/runtime/value.rb +125 -0
- data/lib/hecks/runtime.rb +95 -0
- data/lib/hecks/translation/audit/approval_digest.rb +31 -0
- data/lib/hecks/translation/audit/layer_one.rb +37 -0
- data/lib/hecks/translation/audit/layer_two.rb +77 -0
- data/lib/hecks/translation/audit/unfed_report.rb +42 -0
- data/lib/hecks/translation/audit.rb +70 -0
- data/lib/hecks/translation/reattest.rb +72 -0
- data/lib/hecks/translation/rule_compiler.rb +120 -0
- data/lib/hecks/translation/scaffold/differ.rb +183 -0
- data/lib/hecks/translation/scaffold/renderer.rb +41 -0
- data/lib/hecks/translation/scaffold/writer.rb +28 -0
- data/lib/hecks/translation/scaffold.rb +30 -0
- data/lib/hecks/translation.rb +11 -0
- data/lib/hecks/version.rb +16 -0
- data/lib/hecks/vocabulary.rb +213 -0
- data/lib/hecks.rb +118 -6
- metadata +401 -222
- data/bin/hecks +0 -7
- data/bin/hecks-package +0 -65
- data/bin/hecks_console +0 -12
- data/bin/hecks_serverless +0 -6
- data/lib/cli/build.rb +0 -14
- data/lib/cli/command_runner.rb +0 -28
- data/lib/cli/console.rb +0 -10
- data/lib/cli/generate.rb +0 -37
- data/lib/cli/hecks-cli.rb +0 -27
- data/lib/cli/test.rb +0 -57
- data/lib/console/commands.rb +0 -8
- data/lib/console/hecks-console.rb +0 -1
- data/lib/packager/README.md +0 -0
- data/lib/packager/app_runner.rb +0 -21
- data/lib/packager/args.rb +0 -26
- data/lib/packager/compatibility/fixnum.rb +0 -6
- data/lib/packager/hecks.rb +0 -39
- data/lib/packager/query_runner.rb +0 -21
- data/lib/packager/resources/Dockerfile +0 -11
- data/lib/packager/resources/app_binary +0 -7
- data/lib/packager/resources/bundle_config +0 -3
- data/lib/packager/resources/traveling-ruby-20150715-2.2.2-linux-x86_64.tar.gz +0 -0
- data/lib/packager/resources/traveling-ruby-20150715-2.2.2-osx.tar.gz +0 -0
- data/lib/serverless/Domain +0 -32
- data/lib/serverless/cli.rb +0 -75
- data/lib/serverless/resources/command_name.js +0 -5
- data/lib/serverless/resources/environment.js +0 -7
- data/lib/serverless/resources/handler.js.tt +0 -28
- data/lib/serverless/resources/run_binary.js +0 -22
- data/lib/serverless/resources/serverless.yml +0 -20
|
@@ -0,0 +1,626 @@
|
|
|
1
|
+
require_relative "word_gate"
|
|
2
|
+
module Hecks
|
|
3
|
+
module Bluebook
|
|
4
|
+
module DSL
|
|
5
|
+
class CommandBuilder
|
|
6
|
+
GRAMMAR_CONTEXT = "Command"
|
|
7
|
+
|
|
8
|
+
include AttributeCollector
|
|
9
|
+
include RuleReference
|
|
10
|
+
include WordGate
|
|
11
|
+
|
|
12
|
+
# Vendored addition, not (yet) upstream hecks (migration plan
|
|
13
|
+
# task 4): a sentinel for "this keyword was never passed", distinct
|
|
14
|
+
# from Ruby's own nil/false. `then_set`'s ORIGINAL default (`to:
|
|
15
|
+
# nil`) could not tell "not given" apart from "given, and the
|
|
16
|
+
# value IS false" — `to || from` silently treats `to: false` the
|
|
17
|
+
# same as an absent `to:` and falls through to `from` (also
|
|
18
|
+
# absent), so `then_set :accepted, to: false` raised "names no
|
|
19
|
+
# operation" for the one value most likely to be written that way
|
|
20
|
+
# (a boolean flip). Confirmed real, live: miette's
|
|
21
|
+
# dream_interpretation.bluebook (`then_set :accepted, to: false`)
|
|
22
|
+
# and transparency.bluebook (`then_set :always, to: false`). TODO
|
|
23
|
+
# upstream via bin/evolve.
|
|
24
|
+
UNSET = Object.new.freeze
|
|
25
|
+
private_constant :UNSET
|
|
26
|
+
|
|
27
|
+
def initialize(name, owner: nil, from: nil, named_givens: {}, owner_attributes: [], owner_constructs: [],
|
|
28
|
+
entity_shared_givens: {})
|
|
29
|
+
@name = name
|
|
30
|
+
@owner = owner
|
|
31
|
+
@givens = []
|
|
32
|
+
@ensures = []
|
|
33
|
+
@mutations = []
|
|
34
|
+
@emits = []
|
|
35
|
+
@named_givens = named_givens
|
|
36
|
+
@owner_attributes = owner_attributes
|
|
37
|
+
@owner_constructs = owner_constructs
|
|
38
|
+
# THE AGGREGATE-WIDE cross-entity pool — see
|
|
39
|
+
# `AggregateBuilder#entity`'s own comment and `EntityBuilder#
|
|
40
|
+
# given`'s. Empty (never populated) for an AGGREGATE-owned
|
|
41
|
+
# command, which already checks its own owner's `named_givens`
|
|
42
|
+
# directly and has no siblings to reach across; real only for
|
|
43
|
+
# an ENTITY-owned command's own bare reference.
|
|
44
|
+
@entity_shared_givens = entity_shared_givens
|
|
45
|
+
# NORMALIZED the exact same way `StateTransition#from` already
|
|
46
|
+
# is — one state or several, a single spelling either way,
|
|
47
|
+
# both read back through `Array(...)` at check time.
|
|
48
|
+
@from = case from
|
|
49
|
+
when Array then from.map(&:to_s)
|
|
50
|
+
when nil then nil
|
|
51
|
+
else from.to_s
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# A command carries ONE responsibility role — the language never
|
|
56
|
+
# declared an OR between two roles, so a second `role` call would
|
|
57
|
+
# otherwise silently win while the first still looked declared,
|
|
58
|
+
# exactly the failure mode `reference_to`'s own duplicate guard
|
|
59
|
+
# (below) already exists to prevent for a command's root.
|
|
60
|
+
#
|
|
61
|
+
# RENAMED FROM `role` — item #13's full metaprogrammed dispatch
|
|
62
|
+
# (slice 4). This is a uniqueness gate on PRIOR STATE (`@role`
|
|
63
|
+
# already set), not a pure function of the argument's own value —
|
|
64
|
+
# a genuinely different shape than a plain fill, so it stays
|
|
65
|
+
# hand-written and is reached through `calls:` like `attribute`
|
|
66
|
+
# was in slice 3. Bootstrap-reachable (every self-hosted command
|
|
67
|
+
# declares a role), so also named in
|
|
68
|
+
# `GenericDispatch::BOOTSTRAP_CALLS_FALLBACK`.
|
|
69
|
+
def role_impl(value)
|
|
70
|
+
raise Malformed,
|
|
71
|
+
"#{@name} declares role twice — a command carries ONE " \
|
|
72
|
+
"responsibility; the second would silently win and the " \
|
|
73
|
+
"first would still look declared" if @role
|
|
74
|
+
|
|
75
|
+
@role = value
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def goal(value) = @goal = value
|
|
79
|
+
|
|
80
|
+
# See AggregateBuilder#provenance's own comment — identical shape,
|
|
81
|
+
# one level down.
|
|
82
|
+
# RENAMED FROM `provenance` — item #13's full metaprogrammed
|
|
83
|
+
# dispatch (slice 4c). Bootstrap-reachable, in
|
|
84
|
+
# GenericDispatch::BOOTSTRAP_CALLS_FALLBACK.
|
|
85
|
+
def provenance_impl(from:) = @provenance = from
|
|
86
|
+
|
|
87
|
+
# `optional:` rides here as well as on a plain attribute : `as:` makes a
|
|
88
|
+
# reference into a NAMED ARGUMENT, and a named argument is exactly the kind
|
|
89
|
+
# of fact that may or may not be given. The meta-domain's Verb.Declare
|
|
90
|
+
# points at the Entity a command belongs to — and most commands belong to no
|
|
91
|
+
# entity at all.
|
|
92
|
+
# RENAMED FROM `reference_to` — item #13's full metaprogrammed
|
|
93
|
+
# dispatch (slice 4b). Bootstrap-reachable, in
|
|
94
|
+
# GenericDispatch::BOOTSTRAP_CALLS_FALLBACK.
|
|
95
|
+
def reference_to_impl(type, as: nil, optional: false)
|
|
96
|
+
demodulised = Naming.demodulise(type)
|
|
97
|
+
# moved to the language: given "a command names what it acts on", on Verb.ActsOn
|
|
98
|
+
|
|
99
|
+
# `as:` MEANS "a named attribute", not "the root I act on" — so a command
|
|
100
|
+
# can point at another instance of its OWN kind. Without this,
|
|
101
|
+
# `reference_to Aggregate, as: :points_at` on a command owned by Aggregate
|
|
102
|
+
# read as a second self-reference and was refused as naming two roots,
|
|
103
|
+
# which is how the meta-domain's own Aggregate.Reference could not say the
|
|
104
|
+
# one thing it exists to say. Transfer has said
|
|
105
|
+
# `reference_to Account, as: :source` for as long as banking has existed;
|
|
106
|
+
# this is the same sentence when the target happens to be the owner.
|
|
107
|
+
return cross_reference(demodulised, as, optional) if as || demodulised.to_s != @owner.to_s
|
|
108
|
+
|
|
109
|
+
if @references
|
|
110
|
+
raise Malformed,
|
|
111
|
+
"#{@name} references #{@owner} twice — a command acts on ONE " \
|
|
112
|
+
"root ; the second would silently win and the first would " \
|
|
113
|
+
"still look declared"
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
@references = demodulised
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
private
|
|
120
|
+
|
|
121
|
+
def cross_reference(target, as, optional = false)
|
|
122
|
+
attribute_impl(as || default_reference_name(target), Reference.new(target), optional: optional)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
public
|
|
126
|
+
|
|
127
|
+
# NO BLOCK is a REFERENCE, not a fresh declaration (S10, ADR
|
|
128
|
+
# 0025 — "a precondition shared across commands is declared
|
|
129
|
+
# once. An aggregate declares it by name and commands
|
|
130
|
+
# reference it"): the SAME word, the SAME shape
|
|
131
|
+
# (`AggregateBuilder#given`, block required there), so naming a
|
|
132
|
+
# precondition back is spelled exactly like declaring one would
|
|
133
|
+
# be, minus the block — one idea, one word, never a second
|
|
134
|
+
# spelling ("requires"/"precondition") for "use the one already
|
|
135
|
+
# named". Resolved against whatever the OWNING aggregate has
|
|
136
|
+
# declared so far — see `AggregateBuilder#command`'s own
|
|
137
|
+
# comment on why that means declaration order matters here.
|
|
138
|
+
# RENAMED FROM `given` — item #13's full metaprogrammed dispatch
|
|
139
|
+
# (slice 4b), same reasoning as reference_to_impl above.
|
|
140
|
+
def given_impl(description, &predicate)
|
|
141
|
+
return reference_named_given(description) unless predicate
|
|
142
|
+
|
|
143
|
+
# moved to the language: given "a rule says what it means", on Verb.Rule
|
|
144
|
+
|
|
145
|
+
@givens << build_rule(Given, description, predicate, owner_name: @name, word: "given",
|
|
146
|
+
extraction_failure: "its source could not be read, so no other runtime could ever evaluate it")
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
private
|
|
150
|
+
|
|
151
|
+
# PRIMITIVE 1 (RuleReference#resolve_hash_chain) — FIRST this
|
|
152
|
+
# command's own owner (as always), THEN — only for a piece-owned
|
|
153
|
+
# command, where it is real — a SIBLING piece's own entity-level
|
|
154
|
+
# declaration under the SAME aggregate (`@entity_shared_givens`,
|
|
155
|
+
# threaded from `EntityBuilder#given`'s own write-through).
|
|
156
|
+
# "customer is active" declared once on `Visit`, referenced bare
|
|
157
|
+
# by `KeyIssuance.Return` — two different pieces, same aggregate,
|
|
158
|
+
# same predicate — is exactly the shape this second pool exists
|
|
159
|
+
# for.
|
|
160
|
+
def reference_named_given(description)
|
|
161
|
+
verify_resolves_via!("given", "Command", "hash_chain")
|
|
162
|
+
named = resolve_hash_chain([@named_givens, @entity_shared_givens], description) ||
|
|
163
|
+
raise(Malformed,
|
|
164
|
+
"#{@name}'s given #{description.inspect} names no precondition " \
|
|
165
|
+
"#{@owner} declares, and no sibling piece under the same " \
|
|
166
|
+
"aggregate declares it either — declare it once with a block " \
|
|
167
|
+
"(#{@owner}'s own given(#{description.inspect}) { ... }), before " \
|
|
168
|
+
"the commands that reference it")
|
|
169
|
+
|
|
170
|
+
@givens << named
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
public
|
|
174
|
+
|
|
175
|
+
# The POSTCONDITION — a given for the far side of the mutations,
|
|
176
|
+
# evaluated against the settled record with `old` naming the state
|
|
177
|
+
# as it stood before them: `ensures("...") { old.balance.cents ==
|
|
178
|
+
# balance.cents + amount.cents }`. Same extraction, same Rule
|
|
179
|
+
# shape, same refusal form; EnsuresNotMet instead of GivenNotMet.
|
|
180
|
+
def ensures(description, &predicate)
|
|
181
|
+
@ensures << build_rule(Given, description, predicate, owner_name: @name, word: "ensures",
|
|
182
|
+
extraction_failure: "a postcondition is carried as text, and this one has none")
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# `sets` is the word; `then_set` is the spelling every existing
|
|
186
|
+
# bluebook was written under (Syntax::Keyword carries the rename as
|
|
187
|
+
# `was:`), and it stays answered here forever — a renamed word's old
|
|
188
|
+
# era keeps booting, which is the whole point of the rename column.
|
|
189
|
+
#
|
|
190
|
+
# Vendored addition, not (yet) upstream hecks: `then_set
|
|
191
|
+
# :target, from: :source_field` (hecks_conception/miette, found
|
|
192
|
+
# live in body/doctor/bluebook/doctor.bluebook) -- semantically
|
|
193
|
+
# identical to `to:` (copy this argument/field into the target),
|
|
194
|
+
# different word. TODO upstream via bin/evolve (migration plan
|
|
195
|
+
# task 7): decide whether `from:` or `to:` becomes the canonical
|
|
196
|
+
# spelling.
|
|
197
|
+
#
|
|
198
|
+
# Vendored addition, not (yet) upstream hecks (migration plan
|
|
199
|
+
# task 4, i106 in-DSL math): `multiply:`/`clamp:` -- per-tick organ
|
|
200
|
+
# math (miette's body/organs/bluebook: strength decays ×0.98,
|
|
201
|
+
# weight/strength clamp to [0, 1]) that used to be shell-side awk
|
|
202
|
+
# and moved into the bluebook itself. `multiply:` mirrors
|
|
203
|
+
# increment/decrement's shape exactly (a Numeric amount, applied
|
|
204
|
+
# by CommandRules::Arithmetic -- see that file's own comment on
|
|
205
|
+
# the matching Float-support widening this required). `clamp:`
|
|
206
|
+
# is a genuinely different shape -- its source is always a literal
|
|
207
|
+
# `[min, max]` pair, never an argument reference, and it bounds
|
|
208
|
+
# the CURRENT value rather than combining it with an amount -- so
|
|
209
|
+
# it does not reuse `arithmetic`/`arithmetic_value_object` at all;
|
|
210
|
+
# see MutationApplier#apply's own `:clamp` branch.
|
|
211
|
+
#
|
|
212
|
+
# `remove:` -- vendored addition, not (yet) upstream hecks
|
|
213
|
+
# (migration plan task 4): the list-removal counterpart to
|
|
214
|
+
# `append:` (plan.bluebook's own RemoveDependency/DeactivateSprint
|
|
215
|
+
# commands: "the runtime list-remove primitive (then_set remove:)
|
|
216
|
+
# drops it from the list element-wise, with no read-modify-write
|
|
217
|
+
# -- so a concurrent Add can never be lost"). Matches an element
|
|
218
|
+
# by VALUE equality against `mutation.source` (resolved and
|
|
219
|
+
# Value-coerced the same way increment/decrement/multiply already
|
|
220
|
+
# coerce their own amount -- see MutationApplier#removed).
|
|
221
|
+
#
|
|
222
|
+
# `sets :field, true` -- vendored addition, not (yet) upstream
|
|
223
|
+
# hecks (migration plan task 8): a bare positional literal
|
|
224
|
+
# instead of `to:` -- 14 occurrences across hecks_nursury
|
|
225
|
+
# (oceanography.bluebook/volcanology.bluebook and others),
|
|
226
|
+
# always a boolean shorthand (`sets :deployed, true`, never
|
|
227
|
+
# a string/number positional -- checked directly, zero non-
|
|
228
|
+
# boolean occurrences of the bare-positional-second-arg shape
|
|
229
|
+
# anywhere in the corpus). Folded into `to:` itself rather than
|
|
230
|
+
# given its own mutation op -- semantically identical, same
|
|
231
|
+
# UNSET-sentinel discipline the `to: false` fix already
|
|
232
|
+
# established (a positional `false` must read as "set to
|
|
233
|
+
# false," not "absent," same as the keyword form). Only applied
|
|
234
|
+
# when `to:` itself was NOT also given, so an explicit `to:`
|
|
235
|
+
# keyword always wins over a stray positional.
|
|
236
|
+
#
|
|
237
|
+
# `sets` is the word (ADR 0025 reverts `then_set` — the grammar
|
|
238
|
+
# already declared `sets`, `was: "then_set"`, and 143 of 143 live
|
|
239
|
+
# call sites are `then_set`, so this method was the one thing
|
|
240
|
+
# still backwards). `to:` is OMITTABLE when it would only repeat
|
|
241
|
+
# the target — `sets :number` alone already means `to: :number`
|
|
242
|
+
# — and the REDUNDANT explicit spelling is refused outright
|
|
243
|
+
# (principle 1, "one idea, one spelling": `sets :number, to:
|
|
244
|
+
# :number` says nothing `sets :number` doesn't). `from:` — a
|
|
245
|
+
# pure synonym for `to:` the language's own refusal message had
|
|
246
|
+
# already forgotten about — is gone; write `to:`.
|
|
247
|
+
# THE OP EACH KWARG SELECTS — `spec/syntax_conformance_spec.rb`'s own
|
|
248
|
+
# "selects the same op..." check holds this constant to the self-
|
|
249
|
+
# hosted table's own `Argument#selects` column (`"op=set"`,
|
|
250
|
+
# `"op=append"`, ...; whole-project table-unification survey, item
|
|
251
|
+
# #1), the same field `rust/parser/src/keywords.rs`'s `ArgumentRow.
|
|
252
|
+
# selects` already carries. `to:` is the one kwarg whose own name
|
|
253
|
+
# differs from the op it selects — every other kwarg selects the op
|
|
254
|
+
# of its own name.
|
|
255
|
+
KWARG_TO_OP = { to: :set, append: :append, increment: :increment, decrement: :decrement,
|
|
256
|
+
multiply: :multiply, clamp: :clamp, remove: :remove }.freeze
|
|
257
|
+
|
|
258
|
+
# RENAMED FROM `sets` — item #13's full metaprogrammed dispatch
|
|
259
|
+
# (slice 4c). The `KWARG_TO_OP` op-selection mapping is already
|
|
260
|
+
# table-verified (`Argument#selects`), but the REST (UNSET-
|
|
261
|
+
# sentinel discipline, redundant-spelling refusal, omittable-
|
|
262
|
+
# `to:` fallback, one-mutation-only refusal, the position-
|
|
263
|
+
# preserving `resolve_*!` reinsertion) is keyed off RUNTIME
|
|
264
|
+
# STATE, not a pure function of a static row — stays hand-
|
|
265
|
+
# written, reached through `calls:` like everything else here.
|
|
266
|
+
# Bootstrap-reachable, in BOOTSTRAP_CALLS_FALLBACK.
|
|
267
|
+
def sets_impl(target, positional_to = UNSET, to: UNSET, append: UNSET,
|
|
268
|
+
increment: UNSET, decrement: UNSET, multiply: UNSET, clamp: UNSET, remove: UNSET)
|
|
269
|
+
# moved to the language: given "a mutation names a target", on Verb.Change
|
|
270
|
+
|
|
271
|
+
to = positional_to if to.equal?(UNSET) && !positional_to.equal?(UNSET)
|
|
272
|
+
|
|
273
|
+
# `to:` only ever REPEATS the target when it's a Symbol naming a
|
|
274
|
+
# field — a literal (`to: false`, the bare positional-boolean
|
|
275
|
+
# shorthand, a String, ...) is a VALUE, never a redundant name,
|
|
276
|
+
# so it never has `.to_sym` to compare in the first place.
|
|
277
|
+
if to.is_a?(Symbol) && to == target.to_sym
|
|
278
|
+
raise Malformed,
|
|
279
|
+
"#{@name}'s sets :#{target}, to: :#{target} repeats the target — " \
|
|
280
|
+
"sets :#{target} alone already means the same"
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
given = { to: to, append: append, increment: increment, decrement: decrement,
|
|
284
|
+
multiply: multiply, clamp: clamp, remove: remove }
|
|
285
|
+
.reject { |_, source| source.equal?(UNSET) }
|
|
286
|
+
named = given.to_h { |kwarg, source| [KWARG_TO_OP.fetch(kwarg), source] }
|
|
287
|
+
|
|
288
|
+
# THE OMITTABLE CASE. No operation was named at all — not even a
|
|
289
|
+
# bare `to:` — so this is `sets :field` alone, which means
|
|
290
|
+
# exactly what the redundant, refused spelling above would have.
|
|
291
|
+
named = { set: target } if named.empty?
|
|
292
|
+
|
|
293
|
+
if named.size > 1
|
|
294
|
+
raise Malformed,
|
|
295
|
+
"#{@name}'s sets :#{target} tries to #{named.keys.join(' and ')} " \
|
|
296
|
+
"at once — one mutation, one meaning"
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
op, source = named.first
|
|
300
|
+
@mutations << Mutation.new(target: target.to_sym, op: op, source: source)
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
# LEGACY UNDER SHADOW-PARSING (S0a's own bridge) — frozen era text
|
|
304
|
+
# minted before this rename still parses; live source refuses it,
|
|
305
|
+
# naming the replacement.
|
|
306
|
+
# RENAMED FROM `then_set` — item #13's full metaprogrammed
|
|
307
|
+
# dispatch (slice 5). Not bootstrap-reachable. Now has its own
|
|
308
|
+
# dedicated, `status: "deprecated"` Keyword row (syntax.bluebook)
|
|
309
|
+
# rather than living only as `sets`'s own `was:` — see that
|
|
310
|
+
# row's own comment for why.
|
|
311
|
+
def then_set_impl(target, positional_to = UNSET, **kwargs)
|
|
312
|
+
return legacy_then_set(target, positional_to, **kwargs) if MetaValidator.shadow_parsing?
|
|
313
|
+
|
|
314
|
+
raise Malformed, "#{@name}'s then_set is gone — sets is the word now"
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
# No raise here. "an event is named" is declared in the language itself —
|
|
318
|
+
# language/bluebook/behavior.bluebook, on Command.Announce — and MetaValidator is what
|
|
319
|
+
# enforces it. This is the first rule to move ACROSS rather than be
|
|
320
|
+
# duplicated : delete the declaration and an unnamed event is accepted,
|
|
321
|
+
# which is what makes the meta-domain load-bearing rather than decorative.
|
|
322
|
+
def emits(event_name)
|
|
323
|
+
@emits << event_name.to_s
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
# THE RECORD'S OWN VALUE AS A MUTATION SOURCE — `sets :positions,
|
|
327
|
+
# append: { ply: state(:ply), knights: state(:knights) }` copies
|
|
328
|
+
# what the record holds NOW into the new element; `sets :last,
|
|
329
|
+
# to: state(:current)` copies one field onto another. A bare
|
|
330
|
+
# Symbol always names an argument (see `resolve_append_fields!`),
|
|
331
|
+
# so without this a command could not snapshot its own state at
|
|
332
|
+
# all. `Literal::StateRef`'s own comment has the wire spelling.
|
|
333
|
+
def state(name) = StateRef.new(name.to_sym)
|
|
334
|
+
|
|
335
|
+
# THE SYNCHRONOUS COUSIN OF `trigger` — an AGGREGATE-level command
|
|
336
|
+
# that hands its own dispatch to ONE nested entity command, checked
|
|
337
|
+
# and applied within the SAME atomic dispatch rather than a second
|
|
338
|
+
# one. Built because `trigger`/`saga`'s own dispatch (`Dispatcher
|
|
339
|
+
# #reenter`) is a REACTION — the triggering command has already
|
|
340
|
+
# committed by the time it runs, and both `PolicyInterpreter#deliver`
|
|
341
|
+
# and `SagaInterpreter#deliver_saga_dispatch` rescue a target's own
|
|
342
|
+
# refusal and RECORD it rather than raising it back to the original
|
|
343
|
+
# caller. That is correct for what those two exist for (an
|
|
344
|
+
# eventually-consistent process that can compensate), and wrong for
|
|
345
|
+
# a caller who needs a synchronous yes/no on whether the thing they
|
|
346
|
+
# asked for actually happened — a chess move's own legality, for
|
|
347
|
+
# instance, checked live building `domain/chess` in a downstream
|
|
348
|
+
# project. `delegates_to` fills exactly that gap: the target
|
|
349
|
+
# entity command's own `given`/`ensures` are enforced as real,
|
|
350
|
+
# unrescued Ruby exceptions, so a refusal deep in the entity's own
|
|
351
|
+
# rules is the DELEGATING command's own refusal too, and nothing
|
|
352
|
+
# from either side is saved unless both sides pass.
|
|
353
|
+
#
|
|
354
|
+
# `target` is always ONE hop, `"Entity.Command"` — an aggregate
|
|
355
|
+
# names the entity it owns directly, same reach a bare `given`
|
|
356
|
+
# reference already has (see `Knight`'s own comment on this
|
|
357
|
+
# domain's shared givens), not a multi-segment dispatch chain.
|
|
358
|
+
# `with:` resolves the SAME way `sets ..., append: {...}`'s own
|
|
359
|
+
# field map and a policy's own `trigger ..., with: {...}` already
|
|
360
|
+
# do: each value names one of THIS command's own declared/implicit
|
|
361
|
+
# arguments, read at dispatch time and handed to the target under
|
|
362
|
+
# its own key.
|
|
363
|
+
#
|
|
364
|
+
# MUTUALLY EXCLUSIVE with `sets`/`emits` on the SAME command — a
|
|
365
|
+
# delegating command is a pure passthrough by design (see this
|
|
366
|
+
# method's own header), so it declares no OTHER mutation or event of
|
|
367
|
+
# its own; its result IS whatever the delegated entity command's own
|
|
368
|
+
# `sets`/`emits` produced. Enforced in `build`, once every builder
|
|
369
|
+
# call has already run, so declaration order does not matter.
|
|
370
|
+
#
|
|
371
|
+
# STORED AS A MUTATION, not a new Command field — a real, deliberate
|
|
372
|
+
# choice, not a shortcut. `Command`'s own shape (givens/ensures/
|
|
373
|
+
# mutations/emits/...) is not just Ruby: it round-trips through this
|
|
374
|
+
# language's OWN self-hosted meta-domain (`Bluebook::MetaValidator`
|
|
375
|
+
# dispatches every declaration into a "Bluebook" domain describing
|
|
376
|
+
# itself, then REBUILDS the real runtime graph from what THAT domain
|
|
377
|
+
# holds — `Hecks.bluebook` registers what `MetaValidator.call`
|
|
378
|
+
# returns, never the builder's own object graph directly, confirmed
|
|
379
|
+
# by reading `meta_validator.rb`'s own `self.call`/`self.hold`).
|
|
380
|
+
# A genuinely NEW top-level Command field needs the meta-domain's
|
|
381
|
+
# own grammar (`language/bluebook/behavior.bluebook` or wherever
|
|
382
|
+
# Verb.Rule/Ensure/Change live) taught to carry it too — the same
|
|
383
|
+
# scale of change as the real "item #13" migration this file's own
|
|
384
|
+
# comments document throughout. A NEW MUTATION OP does not: `sets`'s
|
|
385
|
+
# own `mutations:` field is ALREADY a fully round-tripped part of
|
|
386
|
+
# that contract (`Assembly::CONTRACTS["Command"].fields[:mutations]`),
|
|
387
|
+
# and an append-shaped mutation ALREADY carries a multi-key `fields:`
|
|
388
|
+
# hash the exact shape `with:` needs — so `delegates_to` rides that
|
|
389
|
+
# existing, already-correct wire format under a new `op: :delegate`
|
|
390
|
+
# instead of inventing a parallel one. `MutationOp`'s own closed set
|
|
391
|
+
# (vocabulary.bluebook) gained `"delegate"` alongside `"append"`
|
|
392
|
+
# for exactly this reason, and the THREE meta-domain touch points
|
|
393
|
+
# that hard-coded `op == "append"` for the multi-binding shape
|
|
394
|
+
# (`meta_validator/readings.rb#mutation_rows`,
|
|
395
|
+
# `meta_validator/shapes.rb#mutation`, `assembly/marks.rb#mutation`)
|
|
396
|
+
# now check for `:delegate` alongside it, each with a comment
|
|
397
|
+
# pointing back here.
|
|
398
|
+
# RENAMED FROM `delegates_to` to `delegates_to_impl` on declaration
|
|
399
|
+
# — matches `sets_impl`/`given_impl`/`reference_to_impl`'s own
|
|
400
|
+
# convention (language/bluebook/syntax.bluebook's own Keyword row
|
|
401
|
+
# for this word names `calls: "delegates_to_impl"`), the same
|
|
402
|
+
# `word`-vs-`_impl` split every hand-written (not yet item-#13-
|
|
403
|
+
# generic-dispatch-migrated) DSL word here already follows.
|
|
404
|
+
def delegates_to_impl(target, with: {})
|
|
405
|
+
entity_name, _dot, command_name = target.to_s.rpartition(".")
|
|
406
|
+
if entity_name.empty? || command_name.empty?
|
|
407
|
+
raise Malformed,
|
|
408
|
+
"#{@name}'s delegates_to #{target.inspect} does not name an entity and a command " \
|
|
409
|
+
"(\"Entity.Command\") — the same one-hop shape a bare given reference already uses"
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
@mutations << Mutation.new(target: target.to_s, op: :delegate, source: with)
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
def build
|
|
416
|
+
resolve_implicit_attributes!
|
|
417
|
+
|
|
418
|
+
delegation = @mutations.find { |mutation| mutation.op == :delegate }
|
|
419
|
+
if delegation && (@mutations.size > 1 || @emits.any?)
|
|
420
|
+
raise Malformed,
|
|
421
|
+
"#{@name} both delegates_to #{delegation.target} and declares its own " \
|
|
422
|
+
"sets/emits — a delegating command is a pure passthrough (see delegates_to's " \
|
|
423
|
+
"own comment); its result is the delegated command's own"
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
Command.declare(
|
|
427
|
+
name: @name,
|
|
428
|
+
role: @role,
|
|
429
|
+
goal: @goal,
|
|
430
|
+
attributes: attributes,
|
|
431
|
+
givens: @givens,
|
|
432
|
+
ensures: @ensures,
|
|
433
|
+
mutations: @mutations,
|
|
434
|
+
emits: @emits,
|
|
435
|
+
references: @references,
|
|
436
|
+
from: @from,
|
|
437
|
+
provenance: @provenance
|
|
438
|
+
)
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
def self.build(name, owner: nil, from: nil, named_givens: {}, owner_attributes: [], owner_constructs: [],
|
|
442
|
+
entity_shared_givens: {}, &block)
|
|
443
|
+
builder = new(name, owner: owner, from: from, named_givens: named_givens,
|
|
444
|
+
owner_attributes: owner_attributes, owner_constructs: owner_constructs,
|
|
445
|
+
entity_shared_givens: entity_shared_givens)
|
|
446
|
+
builder.instance_eval(&block) if block
|
|
447
|
+
builder.build
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
private
|
|
451
|
+
|
|
452
|
+
# RESOLUTION RULES — see `docs/resolution-rules/README.md` for the
|
|
453
|
+
# precise, language-agnostic algorithm each of `resolve_bare_set!`/
|
|
454
|
+
# `resolve_append_fields!` implements (`implicit-command-attributes.md`
|
|
455
|
+
# / `implicit-append-fields.md`) — the contract a Rust mirror is
|
|
456
|
+
# written from, not inferred from this comment.
|
|
457
|
+
#
|
|
458
|
+
# `sets :field` ALONE (S5's own bare form — no `to:`, meaning
|
|
459
|
+
# `to: :field`) already says the command accepts an argument
|
|
460
|
+
# named `:field`; requiring a SEPARATE `attribute :field, Type`
|
|
461
|
+
# line that retypes what the owning aggregate/entity already
|
|
462
|
+
# declared is the same redundancy S10's `given` reference already
|
|
463
|
+
# killed for preconditions ("a precondition shared across
|
|
464
|
+
# commands is declared once... a command references it by
|
|
465
|
+
# name"). Same move here, one level down: when the command
|
|
466
|
+
# hasn't declared its own `:field`, import the OWNER's
|
|
467
|
+
# already-built `Attribute` verbatim (same type, pattern,
|
|
468
|
+
# optional, admits) instead of retyping it.
|
|
469
|
+
#
|
|
470
|
+
# Only the exact self-referential shape qualifies — `sets
|
|
471
|
+
# :field, to: :other` names a genuinely different source and
|
|
472
|
+
# stays exactly as explicit as it always was; `sets :field, to:
|
|
473
|
+
# false` (or any other literal) isn't naming an argument at all.
|
|
474
|
+
# Comparing as text rather than identity handles both sides
|
|
475
|
+
# (`source` carries whatever `target` was passed as; `target`
|
|
476
|
+
# itself is always symbolized) without caring which.
|
|
477
|
+
#
|
|
478
|
+
# Declaration order matters here the same way it already does
|
|
479
|
+
# for `identified_by`/`given` — the owner's own attribute must
|
|
480
|
+
# exist by the time THIS builder's `build` runs, which every
|
|
481
|
+
# real bluebook already satisfies (the aggregate/entity always
|
|
482
|
+
# declares its attributes before the commands that act on them).
|
|
483
|
+
def resolve_implicit_attributes!
|
|
484
|
+
@mutations.each do |mutation|
|
|
485
|
+
case mutation.op
|
|
486
|
+
when :set then resolve_bare_set!(mutation)
|
|
487
|
+
when :append then resolve_append_fields!(mutation)
|
|
488
|
+
end
|
|
489
|
+
refuse_unknown_state_sources!(mutation)
|
|
490
|
+
end
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
# `state(:name)` names one of the OWNER'S OWN fields — a snapshot
|
|
494
|
+
# of something the record actually holds. Refused at build, by
|
|
495
|
+
# name, the way an unknown `given` reference is; nothing here can
|
|
496
|
+
# read a field the aggregate never declared.
|
|
497
|
+
def refuse_unknown_state_sources!(mutation)
|
|
498
|
+
sources = mutation.source.is_a?(Hash) ? mutation.source.values : [mutation.source]
|
|
499
|
+
sources.grep(StateRef).each do |ref|
|
|
500
|
+
next if @owner_attributes.any? { |attr| attr.name == ref.name }
|
|
501
|
+
|
|
502
|
+
raise Malformed, "#{@name}'s sets :#{mutation.target} reads state(:#{ref.name}), " \
|
|
503
|
+
"which the owner does not declare"
|
|
504
|
+
end
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
def resolve_bare_set!(mutation)
|
|
508
|
+
# A SYMBOL naming its own target — never a literal that merely
|
|
509
|
+
# spells the same word. `sets :moved, to: "moved"` (a chess rook
|
|
510
|
+
# recording that it has moved, into a closed set whose member is
|
|
511
|
+
# literally "moved") used to read as the shorthand and import
|
|
512
|
+
# the owner's `moved` attribute onto the command — a phantom
|
|
513
|
+
# argument nothing ever passes, harmless at runtime only
|
|
514
|
+
# because the owner's default filled it, and a real, silent
|
|
515
|
+
# divergence for every projection that reads the command's
|
|
516
|
+
# declared arguments.
|
|
517
|
+
return unless mutation.source.is_a?(Symbol) && mutation.source.to_s == mutation.target.to_s
|
|
518
|
+
return if attributes.any? { |attr| attr.name == mutation.target }
|
|
519
|
+
|
|
520
|
+
owner_attr = @owner_attributes.find { |attr| attr.name == mutation.target }
|
|
521
|
+
attributes << owner_attr if owner_attr
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
# ONE HOP DEEPER than `resolve_bare_set!` — an `append:` mutation
|
|
525
|
+
# (`sets :ledger, append: { narrative: :narrative, ... }`) builds
|
|
526
|
+
# a NEW element of a LIST field, not the command's own root
|
|
527
|
+
# record, so a bare self-referential field inside it (the hash
|
|
528
|
+
# key equals its own value, same shorthand `resolve_bare_set!`
|
|
529
|
+
# already reads) can't resolve against `@owner_attributes` — the
|
|
530
|
+
# aggregate itself never stores `:narrative`, only the list
|
|
531
|
+
# element's own construct does (`attribute :ledger,
|
|
532
|
+
# list_of(LedgerEntry)`, and `LedgerEntry` is what actually
|
|
533
|
+
# declares `:narrative`). Resolves the list field's own element
|
|
534
|
+
# TYPE first (`element_type_for`), then that construct's own
|
|
535
|
+
# attribute of the same name — same verbatim-import, one level
|
|
536
|
+
# further down the same reasoning `resolve_bare_set!`'s own
|
|
537
|
+
# comment already gives.
|
|
538
|
+
#
|
|
539
|
+
# A non-self-referential value (`direction: { value: "credit" }`,
|
|
540
|
+
# a nested literal) is untouched — only a bare symbol equal to
|
|
541
|
+
# its own key ever qualifies, identical to `resolve_bare_set!`'s
|
|
542
|
+
# own target/source text comparison.
|
|
543
|
+
#
|
|
544
|
+
# POSITION-PRESERVING, not appended at the end — the exported IR
|
|
545
|
+
# is array-order-sensitive (attributes carry their own declared
|
|
546
|
+
# order onto the wire), so an append's fields are resolved as
|
|
547
|
+
# ONE CONTIGUOUS GROUP, in the mutation's own hash order,
|
|
548
|
+
# reinserted at whichever position the group's leftmost STILL-
|
|
549
|
+
# DECLARED member already occupies (or the end, if every member
|
|
550
|
+
# of the group is resolved). A plain `attributes << owner_attr`
|
|
551
|
+
# here would only ever reproduce the original order when the
|
|
552
|
+
# missing field happened to already be last — real, live
|
|
553
|
+
# evidence: `Keyword#was`/`Argument#variadic` (both genuinely
|
|
554
|
+
# last in their own append hash) round-tripped correctly under
|
|
555
|
+
# the naive append; every OTHER field in the same hash did not,
|
|
556
|
+
# caught by this codemod's own reboot-and-diff safety net rather
|
|
557
|
+
# than silently landing wrong.
|
|
558
|
+
def resolve_append_fields!(mutation)
|
|
559
|
+
return unless mutation.source.is_a?(Hash)
|
|
560
|
+
|
|
561
|
+
element = element_type_for(mutation.target)
|
|
562
|
+
return unless element
|
|
563
|
+
|
|
564
|
+
self_ref_fields = mutation.source.select { |field, value| value.is_a?(Symbol) && value.to_s == field.to_s }.keys
|
|
565
|
+
return if self_ref_fields.empty?
|
|
566
|
+
|
|
567
|
+
present = self_ref_fields.filter_map { |field| attributes.find { |attr| attr.name == field } }
|
|
568
|
+
return if present.size == self_ref_fields.size # already fully declared — nothing to resolve
|
|
569
|
+
|
|
570
|
+
anchor = present.empty? ? attributes.length : present.map { |attr| attributes.index(attr) }.min
|
|
571
|
+
attributes.reject! { |attr| present.include?(attr) }
|
|
572
|
+
|
|
573
|
+
group = self_ref_fields.filter_map do |field|
|
|
574
|
+
present.find { |attr| attr.name == field } || element.attributes.find { |attr| attr.name == field }
|
|
575
|
+
end
|
|
576
|
+
attributes.insert(anchor, *group)
|
|
577
|
+
end
|
|
578
|
+
|
|
579
|
+
# The owner's own LIST attribute names its element type as TEXT
|
|
580
|
+
# (`Attribute#type`, unwrapped from `list_of(...)` at declare
|
|
581
|
+
# time) — resolved against `@owner_constructs` (the owner's own
|
|
582
|
+
# value objects and entities, the only two kinds an element can
|
|
583
|
+
# be) by `hecks_name`, the same lookup
|
|
584
|
+
# `AttributeCollector#resolve_identity_field!` already uses for
|
|
585
|
+
# a value object's own name.
|
|
586
|
+
def element_type_for(list_field)
|
|
587
|
+
list_attr = @owner_attributes.find { |attr| attr.name == list_field && attr.list? }
|
|
588
|
+
return nil unless list_attr
|
|
589
|
+
|
|
590
|
+
@owner_constructs.find { |construct| construct.hecks_name.to_s == list_attr.type.to_s }
|
|
591
|
+
end
|
|
592
|
+
|
|
593
|
+
# LEGACY — see `then_set`'s own comment. The ORIGINAL implementation,
|
|
594
|
+
# verbatim: `from:` still a synonym for `to:`, no omittable-`to:`
|
|
595
|
+
# shorthand, no refusal for the redundant `to: target` spelling —
|
|
596
|
+
# frozen era text was minted under this reading, and a legacy
|
|
597
|
+
# grammar exists precisely so re-parsing it never silently changes
|
|
598
|
+
# what it meant.
|
|
599
|
+
def legacy_then_set(target, positional_to = UNSET, to: UNSET, from: UNSET, append: UNSET,
|
|
600
|
+
increment: UNSET, decrement: UNSET, multiply: UNSET, clamp: UNSET, remove: UNSET)
|
|
601
|
+
to = positional_to if to.equal?(UNSET) && !positional_to.equal?(UNSET)
|
|
602
|
+
set_source = to.equal?(UNSET) ? from : to
|
|
603
|
+
|
|
604
|
+
named = { set: set_source, append: append, increment: increment, decrement: decrement,
|
|
605
|
+
multiply: multiply, clamp: clamp, remove: remove }
|
|
606
|
+
.reject { |_, source| source.equal?(UNSET) }
|
|
607
|
+
|
|
608
|
+
if named.empty?
|
|
609
|
+
raise Malformed,
|
|
610
|
+
"#{@name}'s then_set :#{target} names no operation — " \
|
|
611
|
+
"give it to:, append:, increment:, decrement:, multiply:, clamp:, or remove:"
|
|
612
|
+
end
|
|
613
|
+
|
|
614
|
+
if named.size > 1
|
|
615
|
+
raise Malformed,
|
|
616
|
+
"#{@name}'s then_set :#{target} tries to #{named.keys.join(' and ')} " \
|
|
617
|
+
"at once — one mutation, one meaning"
|
|
618
|
+
end
|
|
619
|
+
|
|
620
|
+
op, source = named.first
|
|
621
|
+
@mutations << Mutation.new(target: target.to_sym, op: op, source: source)
|
|
622
|
+
end
|
|
623
|
+
end
|
|
624
|
+
end
|
|
625
|
+
end
|
|
626
|
+
end
|