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,81 @@
|
|
|
1
|
+
module Hecks
|
|
2
|
+
module Bluebook
|
|
3
|
+
module DSL
|
|
4
|
+
module ConstShim
|
|
5
|
+
class << self
|
|
6
|
+
attr_accessor :resolver
|
|
7
|
+
|
|
8
|
+
def with(resolver)
|
|
9
|
+
previous = @resolver
|
|
10
|
+
@resolver = resolver
|
|
11
|
+
yield
|
|
12
|
+
ensure
|
|
13
|
+
@resolver = previous
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def active? = !@resolver.nil?
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# THE SCOPED-CONSTANT BRIDGE (ADR 0025, docs/dsl-work-slices.md's
|
|
20
|
+
# S0b) — a Symbol cannot answer `::`, so `Account::Debit` and
|
|
21
|
+
# `admits: Account::LedgerDirection` could never resolve past
|
|
22
|
+
# their FIRST segment while `Account` returned a bare Symbol
|
|
23
|
+
# (`resolver = ->(const) { const }`, bluebook_builder.rb's own
|
|
24
|
+
# comment on why that was right for a BARE name): Ruby's `::`
|
|
25
|
+
# operator raises `TypeError` on the returned value before any
|
|
26
|
+
# DSL code runs at all, unless that value is itself a Module.
|
|
27
|
+
#
|
|
28
|
+
# A REAL `Module` subclass, not a decorated Symbol, for exactly
|
|
29
|
+
# that reason — nothing else answers `::`. Every existing
|
|
30
|
+
# consumer keeps working duck-typed, not because nothing
|
|
31
|
+
# changed: `Attribute#spell`'s `type.is_a?(Module)` branch now
|
|
32
|
+
# fires where it used to fall to `type.to_s`, and
|
|
33
|
+
# `Naming.demodulise` (`path.split("::").last`) gives the
|
|
34
|
+
# IDENTICAL string either way for a single segment — the two
|
|
35
|
+
# branches were already equivalent for a name with no `::` in
|
|
36
|
+
# it, which is every bareword before this.
|
|
37
|
+
class ScopedConstant < Module
|
|
38
|
+
def self.for(path) = new(path.to_s)
|
|
39
|
+
|
|
40
|
+
def initialize(path)
|
|
41
|
+
super()
|
|
42
|
+
@path = path
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# ONE MORE SEGMENT, the same way an unresolved const anywhere
|
|
46
|
+
# else does — `Account::Debit::Anything` keeps chaining rather
|
|
47
|
+
# than refusing, since nothing here knows how deep a reference
|
|
48
|
+
# is meant to go; the DSL keyword that finally reads `.to_s`
|
|
49
|
+
# is the one place that does.
|
|
50
|
+
def const_missing(name) = ScopedConstant.for("#{@path}::#{name}")
|
|
51
|
+
|
|
52
|
+
def to_s = @path
|
|
53
|
+
def to_sym = @path.to_sym
|
|
54
|
+
def inspect = @path
|
|
55
|
+
def hecks_path = @path
|
|
56
|
+
|
|
57
|
+
def ==(other) = other.is_a?(ScopedConstant) ? @path == other.hecks_path : @path.to_sym == other
|
|
58
|
+
alias eql? ==
|
|
59
|
+
def hash = @path.hash
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# A SCOPED NAME IS WRITTEN AS TEXT, NOT AS A CONSTANT PATH — see the
|
|
63
|
+
# note on `admits:` in AttributeCollector. A resolver returning a
|
|
64
|
+
# Module (so that `Vocabulary::QueryComparator` reaches a second
|
|
65
|
+
# `const_missing`) was tried and cannot be made to hold : `Facade::
|
|
66
|
+
# Surface` installs EVERY aggregate name as a top-level constant, so
|
|
67
|
+
# once any facade is built, `Vocabulary` resolves to that real module
|
|
68
|
+
# and never reaches this hook at all. A spelling that works only
|
|
69
|
+
# before a facade exists is worse than one that always works.
|
|
70
|
+
module Hook
|
|
71
|
+
def const_missing(name)
|
|
72
|
+
resolver = ConstShim.resolver
|
|
73
|
+
resolver ? resolver.call(name) : super
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
Object.singleton_class.prepend(Hecks::Bluebook::DSL::ConstShim::Hook)
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
require_relative "word_gate"
|
|
2
|
+
module Hecks
|
|
3
|
+
module Bluebook
|
|
4
|
+
module DSL
|
|
5
|
+
class DomainPortBuilder
|
|
6
|
+
GRAMMAR_CONTEXT = "DomainPort"
|
|
7
|
+
|
|
8
|
+
include WordGate
|
|
9
|
+
|
|
10
|
+
def initialize(name, owner: nil)
|
|
11
|
+
@name = name
|
|
12
|
+
@owner = owner
|
|
13
|
+
@operations = []
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# WHAT THE OUTSIDE TELLS US — an external fact arriving, translated
|
|
17
|
+
# into this domain's own word for it. Spelled `operation` before it
|
|
18
|
+
# had a twin, and `operation` still works: the corpus is full of it,
|
|
19
|
+
# and renaming a word costs every chapter that uses it for no gain a
|
|
20
|
+
# reader can feel.
|
|
21
|
+
#
|
|
22
|
+
# RENAMED FROM `tells` — item #13's full metaprogrammed dispatch
|
|
23
|
+
# (slice 4c). `operation`/`tells` are TWO separate Keyword rows
|
|
24
|
+
# (a word admitting two forms) that both name `calls: "tells_impl"`
|
|
25
|
+
# — the routing between the two spellings now lives in the table,
|
|
26
|
+
# not in a Ruby `alias`. Not bootstrap-reachable (checked
|
|
27
|
+
# directly), so no BOOTSTRAP_CALLS_FALLBACK entry needed.
|
|
28
|
+
def tells_impl(name, to: nil, &block)
|
|
29
|
+
@operations << PortOperationBuilder.build(name, to: to, owner: @owner, direction: :inbound, &block)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# WHAT WE ASK OF THE OUTSIDE — the direction this language did not
|
|
33
|
+
# have. Before this, a domain could be CALLED by an adapter and never
|
|
34
|
+
# call one. An `asks` is dispatched like any other port operation, so
|
|
35
|
+
# a `policy` can trigger it off an event, and it comes back as one of
|
|
36
|
+
# the two events it named — which is what makes the outside world
|
|
37
|
+
# something the model can reason about rather than a place exceptions
|
|
38
|
+
# come from.
|
|
39
|
+
#
|
|
40
|
+
# RENAMED FROM `asks` — item #13's full metaprogrammed dispatch
|
|
41
|
+
# (slice 4c), same reasoning as tells_impl above.
|
|
42
|
+
def asks_impl(name, to: nil, &block)
|
|
43
|
+
@operations << PortOperationBuilder.build(name, to: to, owner: @owner, direction: :outbound, &block)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# THE DRIVEN HALF OF THE SAME WORD. `operation`/`emits` translates an
|
|
47
|
+
# inbound fact into this domain's own event vocabulary — there is no
|
|
48
|
+
# channel back to a caller beyond the events it emits. `verb` is the
|
|
49
|
+
# opposite direction: the domain calling OUT to a swappable adapter
|
|
50
|
+
# and getting a real value back (a checkout URL, a fetched document),
|
|
51
|
+
# exactly what `Hecks.port "name" do verb "x" end` already builds —
|
|
52
|
+
# this is that same `Port`, reached from the same `port` call
|
|
53
|
+
# `operation` already lives under, so a project's own resource ports
|
|
54
|
+
# read next to their binding instead of in a separate file. One port,
|
|
55
|
+
# one shape or the other — never both.
|
|
56
|
+
# `verb` — item #13's full metaprogrammed dispatch, slice 1
|
|
57
|
+
# (whole-project table-unification survey): a bare, kind-driven
|
|
58
|
+
# coerce-and-assign with nothing else, now executed by
|
|
59
|
+
# `GenericDispatch`.
|
|
60
|
+
|
|
61
|
+
def build
|
|
62
|
+
raise Malformed, "#{@name} declares both a verb and operations — a port is one or the other, not both" if @verb && !@operations.empty?
|
|
63
|
+
|
|
64
|
+
return Port.new(name: @name, verb: @verb, signal: :reply) if @verb
|
|
65
|
+
|
|
66
|
+
raise Malformed, "#{@name} declares no verb and no operations" if @operations.empty?
|
|
67
|
+
|
|
68
|
+
DomainPort.new(name: @name, operations: @operations)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def self.build(name, owner: nil, &block)
|
|
72
|
+
builder = new(name, owner: owner)
|
|
73
|
+
builder.instance_eval(&block) if block
|
|
74
|
+
builder.build
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
require_relative "word_gate"
|
|
2
|
+
module Hecks
|
|
3
|
+
module Bluebook
|
|
4
|
+
module DSL
|
|
5
|
+
class EntityBuilder
|
|
6
|
+
GRAMMAR_CONTEXT = "Entity"
|
|
7
|
+
|
|
8
|
+
include AttributeCollector
|
|
9
|
+
include IdentityDeclaration
|
|
10
|
+
include RuleReference
|
|
11
|
+
include WordGate
|
|
12
|
+
|
|
13
|
+
def initialize(name, owner_value_objects: [], owner_named_givens: {},
|
|
14
|
+
identity_name_prefix: nil, identity_value_object_installer: nil)
|
|
15
|
+
@name = name
|
|
16
|
+
@commands = []
|
|
17
|
+
@queries = []
|
|
18
|
+
@entities = []
|
|
19
|
+
@named_givens = {}
|
|
20
|
+
@invariants = []
|
|
21
|
+
@owner_value_objects = owner_value_objects
|
|
22
|
+
@identity_name_prefix = identity_name_prefix || Naming.demodulise(name)
|
|
23
|
+
@identity_value_object_installer = identity_value_object_installer
|
|
24
|
+
# THE AGGREGATE-WIDE cross-entity given pool — ONE hash, the
|
|
25
|
+
# SAME object, threaded unchanged through every piece nested
|
|
26
|
+
# under one aggregate however deep (the identical shape
|
|
27
|
+
# `@owner_value_objects` already threads — see this class'
|
|
28
|
+
# own `entity` comment). `given`'s own block form writes
|
|
29
|
+
# through to it; a SIBLING piece's bare command-level
|
|
30
|
+
# reference reads from it via `CommandBuilder#
|
|
31
|
+
# reference_named_given`.
|
|
32
|
+
@owner_named_givens = owner_named_givens
|
|
33
|
+
# DEFERRED CONSTRUCTION — see `AggregateBuilder#drain_pending!`'s
|
|
34
|
+
# own comment; the identical mechanism, one level down, so a
|
|
35
|
+
# nested piece's own commands (Dispatch inside Handler) see
|
|
36
|
+
# every SIBLING entity/command/query this piece goes on to
|
|
37
|
+
# declare, not just whatever came before it textually.
|
|
38
|
+
@pending_entities = []
|
|
39
|
+
@pending_commands = []
|
|
40
|
+
@pending_queries = []
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def description(value) = @description = value
|
|
44
|
+
|
|
45
|
+
# THE SAME FIELD AggregateBuilder's OWN reference_to BUILDS — a
|
|
46
|
+
# piece can hold a reference to another root exactly the way its
|
|
47
|
+
# own head can (Card.assignee_id, a Team's own id), just never
|
|
48
|
+
# to another PIECE, since there's no cross-piece addressing
|
|
49
|
+
# anywhere in this language to resolve one against.
|
|
50
|
+
# RENAMED FROM `reference_to` — item #13's full metaprogrammed
|
|
51
|
+
# dispatch (slice 4b). Bootstrap-reachable, in
|
|
52
|
+
# GenericDispatch::BOOTSTRAP_CALLS_FALLBACK.
|
|
53
|
+
def reference_to_impl(type, as: nil, optional: false)
|
|
54
|
+
target = Naming.demodulise(type)
|
|
55
|
+
relationship_attribute(target, :reference_to,
|
|
56
|
+
as || default_reference_name(target), optional: optional)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# has_many_impl/has_one_impl are DSL declaration keywords a domain
|
|
60
|
+
# author writes as bare has_many/has_one (matching belongs_to_impl
|
|
61
|
+
# alongside them) — not real predicates, so renaming to many?/one?
|
|
62
|
+
# per Naming/PredicatePrefix would break every bluebook that
|
|
63
|
+
# declares one. New on Entity (Wave 6, identity-and-relationships
|
|
64
|
+
# arc) — pieces never had relationship words before; named
|
|
65
|
+
# `*_impl` to match AggregateBuilder's own siblings, item #13's
|
|
66
|
+
# full metaprogrammed dispatch convention.
|
|
67
|
+
# rubocop:disable Naming/PredicatePrefix
|
|
68
|
+
def has_many_impl(type, as: nil, **options)
|
|
69
|
+
unless options.empty?
|
|
70
|
+
raise Malformed, "#{@name}.has_many takes no #{options.keys.first}: — an empty list already means none"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
plural = Naming.demodulise(type)
|
|
74
|
+
relationship_attribute(Naming.singularize(plural), :has_many,
|
|
75
|
+
as || Naming.snake(plural).to_sym, list: true)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def has_one_impl(type, as: nil, optional: false)
|
|
79
|
+
target = Naming.demodulise(type)
|
|
80
|
+
relationship_attribute(target, :has_one, as || Naming.snake(target).to_sym, optional: optional)
|
|
81
|
+
end
|
|
82
|
+
# rubocop:enable Naming/PredicatePrefix
|
|
83
|
+
|
|
84
|
+
def belongs_to_impl(type, as: nil, optional: false)
|
|
85
|
+
target = Naming.demodulise(type)
|
|
86
|
+
relationship_attribute(target, :belongs_to, as || Naming.snake(target).to_sym, optional: optional)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# A PIECE is known by a field, not by a whole value object.
|
|
90
|
+
# `identified_by :sequence` names the SCALAR inside it, which is
|
|
91
|
+
# what an id actually is — a LedgerEntry is entry 3, not entry
|
|
92
|
+
# {"value":3}. `identified_by` itself is AttributeCollector's own
|
|
93
|
+
# shared method (S9) — the two constructs cannot drift apart in
|
|
94
|
+
# how they spell an identity, including composite
|
|
95
|
+
# (`identified_by :branch_code, :box_number`), which a piece may
|
|
96
|
+
# declare for the same reason a head may.
|
|
97
|
+
|
|
98
|
+
# `from:` — see `AggregateBuilder#command`'s own comment; the
|
|
99
|
+
# SAME guard, checked against this PIECE's own lifecycle field
|
|
100
|
+
# (S10, ADR 0025 — a piece's own state machine is checkable the
|
|
101
|
+
# same way a head's is).
|
|
102
|
+
# RENAMED FROM `command`/`query`/`entity`/`lifecycle` (all below)
|
|
103
|
+
# — item #13's full metaprogrammed dispatch (slice 4c), same
|
|
104
|
+
# reasoning as AggregateBuilder's own siblings: bootstrap-
|
|
105
|
+
# reachable, in BOOTSTRAP_CALLS_FALLBACK.
|
|
106
|
+
def command_impl(name, from: nil, &block)
|
|
107
|
+
@pending_commands << [name, from, block]
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def query_impl(name, &block)
|
|
111
|
+
@pending_queries << [name, block]
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# S17, ADR 0026 — A PIECE NESTED INSIDE A PIECE. "A `Dispatch`
|
|
115
|
+
# [has] no life outside its `Handler`" (the ADR's own words) —
|
|
116
|
+
# the same reason `Member` nests inside `ValueObject`, one level
|
|
117
|
+
# further in. `owner_value_objects` passes straight through
|
|
118
|
+
# unchanged, not re-derived from this entity's own attributes —
|
|
119
|
+
# a piece mints no value objects of its own at any depth, so a
|
|
120
|
+
# NESTED piece's bare `identified_by :field` still resolves
|
|
121
|
+
# against the SAME root aggregate's value objects an outer
|
|
122
|
+
# piece's already does (`AggregateBuilder#entity`'s own comment
|
|
123
|
+
# names this pool ; there is exactly one of them, however deep
|
|
124
|
+
# the nesting goes).
|
|
125
|
+
def entity_impl(name, &block)
|
|
126
|
+
@pending_entities << [name, block]
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def lifecycle_impl(field, default:, &block)
|
|
130
|
+
@lifecycle = LifecycleBuilder.build(field, default: default, &block)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# A PRECONDITION SHARED ACROSS THIS PIECE'S OWN COMMANDS, DECLARED
|
|
134
|
+
# ONCE — the same move `AggregateBuilder#given` already makes,
|
|
135
|
+
# one level down. Real, live redundancy this closes: banking's
|
|
136
|
+
# own `LedgerEntry.Amend`/`LedgerEntry.Reverse` each repeated
|
|
137
|
+
# `given("customer is active") { parent.customer.status ==
|
|
138
|
+
# "active" }` and `given("account is open") { parent.status ==
|
|
139
|
+
# "open" }`, byte for byte, because a piece had no way to declare
|
|
140
|
+
# either once and reference it back — only the AGGREGATE could.
|
|
141
|
+
# DECLARE BEFORE THE COMMANDS THAT REFERENCE IT, the same
|
|
142
|
+
# ordering `AggregateBuilder#given`'s own comment names — though
|
|
143
|
+
# since ADR 0028, `command` only queues a descriptor and actually
|
|
144
|
+
# builds at `#drain_pending!` time, well after this whole block
|
|
145
|
+
# (including every `given` in it) has already run, so textual
|
|
146
|
+
# order within the block no longer actually matters here; named
|
|
147
|
+
# for the reader anyway, since `given`'s own resolution logic
|
|
148
|
+
# (`CommandBuilder#reference_named_given`) still reads whatever
|
|
149
|
+
# `@named_givens` holds AT THE COMMAND'S OWN BUILD TIME, not by
|
|
150
|
+
# magic.
|
|
151
|
+
# RENAMED FROM `given` — item #13's full metaprogrammed dispatch
|
|
152
|
+
# (slice 4b), same reasoning as reference_to_impl above.
|
|
153
|
+
def given_impl(description, &predicate)
|
|
154
|
+
named = build_rule(Given, description, predicate, owner_name: @name, word: "given",
|
|
155
|
+
extraction_failure: "its source could not be read, so no other runtime could ever evaluate it")
|
|
156
|
+
@named_givens[description] = named
|
|
157
|
+
# WRITE-THROUGH, first-declared-wins (`||=`) — a SECOND piece
|
|
158
|
+
# under the same aggregate independently declaring the exact
|
|
159
|
+
# same description stays purely local to itself (no silent
|
|
160
|
+
# overwrite of whatever the first piece already shared;
|
|
161
|
+
# real, live case a fuzzer or a future codemod could easily
|
|
162
|
+
# surface: two pieces phrasing an UNRELATED rule identically
|
|
163
|
+
# by coincidence, same as an aggregate-level given already
|
|
164
|
+
# tolerates today).
|
|
165
|
+
@owner_named_givens[description] ||= named
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# A PIECE'S OWN SHAPE RULE (S10, ADR 0025's own "Rules" shape,
|
|
169
|
+
# one level down from `ValueObjectBuilder#invariant`, whose
|
|
170
|
+
# extraction/error pattern this mirrors) — checked against
|
|
171
|
+
# EVERY INSTANCE of this piece the aggregate holds, not once
|
|
172
|
+
# against the aggregate's own flat state
|
|
173
|
+
# (`Admissibility#enforce_invariants`'s own recursive walk).
|
|
174
|
+
# No reference-by-name form (unlike `given`) — no known corpus
|
|
175
|
+
# need for a piece's own invariant to be shared with a SIBLING
|
|
176
|
+
# piece yet; if that need shows up, it is `given`'s own
|
|
177
|
+
# cross-entity write-through pattern to extend, not a reason to
|
|
178
|
+
# invent a second one here speculatively.
|
|
179
|
+
# RENAMED FROM `invariant` — item #13's full metaprogrammed
|
|
180
|
+
# dispatch (slice 4b), same reasoning as given_impl above.
|
|
181
|
+
def invariant_impl(description, &predicate)
|
|
182
|
+
@invariants << build_rule(Invariant, description, predicate, owner_name: @name, word: "invariant",
|
|
183
|
+
extraction_failure: "it would be a rule the IR cannot carry")
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def build
|
|
187
|
+
drain_pending!
|
|
188
|
+
resolve_pending_identity!
|
|
189
|
+
seal_lifecycle_guards
|
|
190
|
+
install_closed_sets!
|
|
191
|
+
Entity.declare(
|
|
192
|
+
name: @name,
|
|
193
|
+
description: @description,
|
|
194
|
+
identified_by: @identity_paths,
|
|
195
|
+
attributes: attributes,
|
|
196
|
+
commands: @commands,
|
|
197
|
+
queries: @queries,
|
|
198
|
+
entities: @entities,
|
|
199
|
+
preconditions: @named_givens.values,
|
|
200
|
+
invariants: @invariants,
|
|
201
|
+
lifecycle: @lifecycle
|
|
202
|
+
)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def self.build(name, owner_value_objects: [], owner_named_givens: {},
|
|
206
|
+
identity_name_prefix: nil, identity_value_object_installer: nil, &block)
|
|
207
|
+
builder = new(name, owner_value_objects: owner_value_objects, owner_named_givens: owner_named_givens,
|
|
208
|
+
identity_name_prefix: identity_name_prefix,
|
|
209
|
+
identity_value_object_installer: identity_value_object_installer)
|
|
210
|
+
builder.instance_eval(&block) if block
|
|
211
|
+
builder.build
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
private
|
|
215
|
+
|
|
216
|
+
# A PIECE'S OWN `one_of` LANDS ON ITS AGGREGATE. A type-position
|
|
217
|
+
# `one_of("never_moved", "moved")` on an entity attribute
|
|
218
|
+
# synthesizes a closed-set value object — and until this, that
|
|
219
|
+
# object was built and then DROPPED: `Entity.declare` carries no
|
|
220
|
+
# value objects, so the synthesized set existed nowhere in the
|
|
221
|
+
# finished graph. The attribute stayed typed "Moved" with nothing
|
|
222
|
+
# to resolve it: runtime admission had no closed set to enforce
|
|
223
|
+
# (the one_of was decorative), and the fuzzer's ValueGenerator
|
|
224
|
+
# crashed every run on the first domain to declare one — a chess
|
|
225
|
+
# King/Rook's own castling flag — with `does not know primitive
|
|
226
|
+
# type "Moved"`. Installed through the SAME hook an entity's own
|
|
227
|
+
# identity value object already rides to the aggregate
|
|
228
|
+
# (`identity_value_object_installer`, threaded unchanged through
|
|
229
|
+
# nested pieces). Two sibling pieces synthesizing the same set
|
|
230
|
+
# (King's and Rook's own `moved`) install it once; the same NAME
|
|
231
|
+
# with a DIFFERENT member list is refused as the collision it is,
|
|
232
|
+
# never first-wins silently.
|
|
233
|
+
def install_closed_sets!
|
|
234
|
+
return unless @identity_value_object_installer
|
|
235
|
+
|
|
236
|
+
closed_sets.each do |value_object|
|
|
237
|
+
existing = @owner_value_objects.find { |candidate| candidate.hecks_name == value_object.hecks_name }
|
|
238
|
+
if existing
|
|
239
|
+
next if existing.to_h == value_object.to_h
|
|
240
|
+
|
|
241
|
+
raise Malformed,
|
|
242
|
+
"#{@name}'s one_of synthesizes #{value_object.hecks_name.inspect}, but the aggregate already " \
|
|
243
|
+
"holds a different #{value_object.hecks_name.inspect} — name the closed set's field differently"
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
@identity_value_object_installer.call(value_object)
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
# See `AggregateBuilder#drain_pending!`'s own comment — the
|
|
251
|
+
# identical mechanism, one level down. Entities first and fully
|
|
252
|
+
# built (so a nested command's own `append:` resolution can read
|
|
253
|
+
# a sibling piece's `.attributes`), then commands, then queries.
|
|
254
|
+
def drain_pending!
|
|
255
|
+
@entities = @pending_entities.map do |name, block|
|
|
256
|
+
EntityBuilder.build(name, owner_value_objects: @owner_value_objects,
|
|
257
|
+
owner_named_givens: @owner_named_givens,
|
|
258
|
+
identity_name_prefix: "#{@identity_name_prefix}#{Naming.demodulise(name)}",
|
|
259
|
+
identity_value_object_installer: @identity_value_object_installer,
|
|
260
|
+
&block)
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
@commands = @pending_commands.map do |name, from, block|
|
|
264
|
+
CommandBuilder.build(name, owner: @name, from: from, named_givens: @named_givens,
|
|
265
|
+
owner_attributes: attributes,
|
|
266
|
+
owner_constructs: @owner_value_objects + @entities,
|
|
267
|
+
entity_shared_givens: @owner_named_givens, &block)
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
@queries = @pending_queries.map do |name, block|
|
|
271
|
+
QueryBuilder.build(name, owner_attributes: attributes, &block)
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
# See `AggregateBuilder#seal_lifecycle_guards`'s own comment —
|
|
276
|
+
# the identical check, one level down.
|
|
277
|
+
def seal_lifecycle_guards
|
|
278
|
+
return if @lifecycle
|
|
279
|
+
|
|
280
|
+
@commands.each do |command|
|
|
281
|
+
next unless command.from
|
|
282
|
+
|
|
283
|
+
raise Malformed,
|
|
284
|
+
"#{@name}.#{command.hecks_name} guards from: #{Array(command.from).inspect}, but " \
|
|
285
|
+
"#{@name} declares no lifecycle — from: checks a lifecycle field, and there is " \
|
|
286
|
+
"none here to check"
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
# `identified_by`'s own resolution pool (AttributeCollector#resolve_
|
|
291
|
+
# pending_identity!'s hook, S9) — a piece mints no value objects of
|
|
292
|
+
# its own, so a bare field's own type resolves against its OWNER
|
|
293
|
+
# aggregate's, passed in at declaration (`AggregateBuilder#entity`).
|
|
294
|
+
def identity_pool = @owner_value_objects
|
|
295
|
+
|
|
296
|
+
def identity_value_object_name = "#{@identity_name_prefix}Identity"
|
|
297
|
+
|
|
298
|
+
def install_identity_value_object!(value_object)
|
|
299
|
+
@identity_value_object_installer&.call(value_object)
|
|
300
|
+
@owner_value_objects << value_object unless @owner_value_objects.include?(value_object)
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
end
|