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,172 @@
|
|
|
1
|
+
module Hecks
|
|
2
|
+
module Bluebook
|
|
3
|
+
module DSL
|
|
4
|
+
# THE THREE RESOLUTION PRIMITIVES the S10 given/invariant family's
|
|
5
|
+
# own "declared once, referenced by name" mechanism (ADR 0025)
|
|
6
|
+
# reduces to, at every scope this language has grown one so far
|
|
7
|
+
# (a command referencing its owner or a sibling piece's entity-wide
|
|
8
|
+
# pool; an aggregate referencing another aggregate chapter-wide; a
|
|
9
|
+
# value object referencing a sibling value object on the same
|
|
10
|
+
# aggregate) — extracted here, once, so the NEXT scope this family
|
|
11
|
+
# widens to (there will be one — see docs/resolution-rules/
|
|
12
|
+
# chapter-given.md's own "Known limitations" for two already named)
|
|
13
|
+
# reuses one of these three shapes instead of a fourth hand-written
|
|
14
|
+
# near-duplicate resolver.
|
|
15
|
+
#
|
|
16
|
+
# NOT ONE UNIFIED ALGORITHM — a real design question this file
|
|
17
|
+
# answers directly: the THREE existing resolvers are not
|
|
18
|
+
# superficially different, they are STRUCTURALLY different (a
|
|
19
|
+
# multi-pool fallback CHAIN; ONE pool keyed by declaring OWNER,
|
|
20
|
+
# needing disambiguation; a LIVE SCAN over already-built sibling
|
|
21
|
+
# objects with no separate pool at all) — forcing them into one
|
|
22
|
+
# shape would be a real behavior change (see `#lookup`, below, for
|
|
23
|
+
# which construct uses which), not the pure internal refactor this
|
|
24
|
+
# module is. `build_rule` is the one piece that WAS genuinely
|
|
25
|
+
# identical across all 7 declaring methods (`given`×3,
|
|
26
|
+
# `invariant`×3, `ensures`×1) before this file existed — extract
|
|
27
|
+
# predicate source, refuse if extraction failed, build the struct.
|
|
28
|
+
#
|
|
29
|
+
# `#lookup`/`#verify_resolves_via!` read WHICH construct uses which
|
|
30
|
+
# primitive off the self-hosted grammar table itself
|
|
31
|
+
# (`Keyword#resolves_via`, `syntax.bluebook`) — not a Ruby-only
|
|
32
|
+
# Hash cross-checked afterward (this file's OWN earlier shape, one
|
|
33
|
+
# round ago) — so a real domain's own boot, not just `bundle exec
|
|
34
|
+
# rspec`, fails loudly the moment the table and this file's own
|
|
35
|
+
# hand-written resolution methods disagree.
|
|
36
|
+
module RuleReference
|
|
37
|
+
module_function
|
|
38
|
+
|
|
39
|
+
# `struct_class` is `Given` or `Invariant` (both `Struct.new(
|
|
40
|
+
# :description, :canonical, :predicate, keyword_init: true)` —
|
|
41
|
+
# `Given` lives in command.rb, `Invariant` in value_object.rb).
|
|
42
|
+
# `owner_name`/`word` are ONLY for the refusal message's own
|
|
43
|
+
# wording. `extraction_failure` is the tail of that same
|
|
44
|
+
# message, and stays a REQUIRED parameter rather than one
|
|
45
|
+
# hardcoded string on purpose — `given` ("its source could not
|
|
46
|
+
# be read, so no other runtime could ever evaluate it"),
|
|
47
|
+
# `invariant` ("it would be a rule the IR cannot carry"), and
|
|
48
|
+
# `ensures` ("a postcondition is carried as text, and this one
|
|
49
|
+
# has none") each already had their OWN exact wording before
|
|
50
|
+
# this method existed; unifying them into one generic sentence
|
|
51
|
+
# would be a real (if small) behavior change this refactor is
|
|
52
|
+
# not making.
|
|
53
|
+
def build_rule(struct_class, description, predicate, owner_name:, word:, extraction_failure:)
|
|
54
|
+
canonical = Ports::Extraction.canonical(predicate)
|
|
55
|
+
|
|
56
|
+
if canonical.to_s.empty?
|
|
57
|
+
raise Malformed,
|
|
58
|
+
"#{owner_name}'s #{word} #{description.inspect} did not survive " \
|
|
59
|
+
"extraction — #{extraction_failure}"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
struct_class.new(description: description, canonical: canonical, predicate: predicate)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# PRIMITIVE 1 — an ORDERED CHAIN of flat `Hash[description] =>
|
|
66
|
+
# Rule` pools, first match wins. `CommandBuilder#given`'s own
|
|
67
|
+
# two-pool shape (its OWN owner's `named_givens`, then a sibling
|
|
68
|
+
# piece's entity-wide pool) is this with a 2-element chain — a
|
|
69
|
+
# future single-pool bare reference is the same primitive with a
|
|
70
|
+
# 1-element chain, not a separate "just look in one hash" method.
|
|
71
|
+
def resolve_hash_chain(pools, description)
|
|
72
|
+
pools.each { |pool| return pool[description] if pool.key?(description) }
|
|
73
|
+
nil
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# PRIMITIVE 2 — ONE pool keyed BY DECLARING OWNER,
|
|
77
|
+
# `Hash[description][owner] => Rule` — `AggregateBuilder#given`'s
|
|
78
|
+
# own chapter-wide shape, the only construct so far where the
|
|
79
|
+
# SAME description can mean two genuinely different predicates
|
|
80
|
+
# (docs/implemented/resolution-rules/chapter-given.md). Returns the full
|
|
81
|
+
# candidates Hash (0, 1, or many entries) — deliberately NOT
|
|
82
|
+
# raising here, so each caller keeps its own exact refusal
|
|
83
|
+
# wording for "none," "ambiguous," and "declared_by: named the
|
|
84
|
+
# wrong owner" rather than one generic message papering over all
|
|
85
|
+
# three.
|
|
86
|
+
def resolve_owner_keyed(pool, description)
|
|
87
|
+
pool[description] || {}
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# PRIMITIVE 3 — a LIVE SCAN over already-built SIBLING OBJECTS'
|
|
91
|
+
# own collections, not a separately-maintained pool at all —
|
|
92
|
+
# `ValueObjectBuilder#invariant`'s own shape: every sibling value
|
|
93
|
+
# object on the same aggregate has ALREADY been built by the time
|
|
94
|
+
# a later one references back (declaration order, the same
|
|
95
|
+
# constraint every scope in this family carries), so there is
|
|
96
|
+
# nothing to write through — just read their own already-declared
|
|
97
|
+
# rules directly. `reader` is the method name to call on each
|
|
98
|
+
# sibling (`:invariants` today; kept a parameter, not hardcoded,
|
|
99
|
+
# since a future sibling-scan scope might reference a different
|
|
100
|
+
# collection).
|
|
101
|
+
def resolve_sibling_scan(siblings, description, reader:)
|
|
102
|
+
siblings.flat_map { |sibling| sibling.public_send(reader) }
|
|
103
|
+
.find { |rule| rule.description == description }
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# WHICH CONSTRUCT USES WHICH PRIMITIVE — no longer a Ruby-only
|
|
107
|
+
# Hash (that WAS this constant's own shape, one round ago): the
|
|
108
|
+
# user's own correction — "my goal is that if they read the same
|
|
109
|
+
# table they behave identically" — means a table only Ruby ever
|
|
110
|
+
# reads cannot deliver that, no matter how faithfully it is
|
|
111
|
+
# cross-checked afterward. `Keyword#resolves_via`/`#disambiguator`
|
|
112
|
+
# (self-hosted, `syntax.bluebook`) is the REAL table now — the
|
|
113
|
+
# SAME generated data `rust/parser/src/keywords.rs` is generated
|
|
114
|
+
# from (`bin/project_parser_table`). `#lookup` reads it live.
|
|
115
|
+
#
|
|
116
|
+
# THE ONE UNAVOIDABLE EXCEPTION: the meta-domain's own bootstrap
|
|
117
|
+
# (`MetaValidator.load_grammar_into`) dispatches `given`/
|
|
118
|
+
# `invariant` on ITSELF 61 times while building the very grammar
|
|
119
|
+
# table that would answer "how does given/Aggregate resolve" —
|
|
120
|
+
# `MetaValidator.grammar_registry`/`SyntaxBoot.call` are not
|
|
121
|
+
# ready yet, and cannot be made ready without ALREADY having
|
|
122
|
+
# resolved a `given` somewhere upstream. `MetaValidator.
|
|
123
|
+
# bootstrapping?` is the SAME guard `MetaValidator.call` (the
|
|
124
|
+
# judge) already uses to skip self-judging during this exact
|
|
125
|
+
# window — `#lookup` uses it too, falling back to
|
|
126
|
+
# `BOOTSTRAP_FALLBACK` (below) ONLY while it's true. Every REAL
|
|
127
|
+
# domain (banking, pizzas, compliance, any future one) boots
|
|
128
|
+
# AFTER `grammar_registry` is fully built and memoized, so reads
|
|
129
|
+
# the real table, every time, no exception.
|
|
130
|
+
BOOTSTRAP_FALLBACK = {
|
|
131
|
+
%w[given Aggregate] => { resolves_via: "owner_keyed", disambiguator: "declared_by" },
|
|
132
|
+
%w[given Command] => { resolves_via: "hash_chain" },
|
|
133
|
+
%w[invariant ValueObject] => { resolves_via: "sibling_scan" }
|
|
134
|
+
}.freeze
|
|
135
|
+
|
|
136
|
+
def lookup(word, context)
|
|
137
|
+
if MetaValidator.bootstrapping?
|
|
138
|
+
BOOTSTRAP_FALLBACK[[word, context]] || {}
|
|
139
|
+
else
|
|
140
|
+
row = MetaValidator::SyntaxBoot.call[:keywords]
|
|
141
|
+
.find { |r| r[:word] == word && r[:context] == context }
|
|
142
|
+
return {} unless row
|
|
143
|
+
|
|
144
|
+
{ resolves_via: row[:resolves_via], disambiguator: row[:disambiguator] }
|
|
145
|
+
.transform_values { |value| value.to_s.empty? ? nil : value }
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# A LIVE CROSS-CHECK, not a spec-only one — every REAL domain's
|
|
150
|
+
# own boot (not just `bundle exec rspec`) now genuinely fails
|
|
151
|
+
# loudly if a construct's own hand-written resolution method
|
|
152
|
+
# ever disagrees with what the self-hosted grammar table claims
|
|
153
|
+
# for it. Each of the three `reference_named_*` methods below
|
|
154
|
+
# calls this FIRST, naming the primitive it is ABOUT to use —
|
|
155
|
+
# if `syntax.bluebook`'s own `resolves_via` for this exact
|
|
156
|
+
# (word, context) pair ever names something else, this is a
|
|
157
|
+
# real drift between the language's own self-description and
|
|
158
|
+
# its own implementation, caught at the next boot of ANYTHING,
|
|
159
|
+
# not just the next `rspec` run.
|
|
160
|
+
def verify_resolves_via!(word, context, expected_primitive)
|
|
161
|
+
actual = lookup(word, context)[:resolves_via]
|
|
162
|
+
return if actual == expected_primitive
|
|
163
|
+
|
|
164
|
+
raise "internal: syntax.bluebook says #{word}/#{context} resolves via " \
|
|
165
|
+
"#{actual.inspect}, but #{word}'s own Ruby builder is about to use " \
|
|
166
|
+
"#{expected_primitive.inspect} — the grammar table and the " \
|
|
167
|
+
"implementation have drifted"
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
require_relative "word_gate"
|
|
2
|
+
module Hecks
|
|
3
|
+
module Bluebook
|
|
4
|
+
module DSL
|
|
5
|
+
class TranslationAggregateBuilder
|
|
6
|
+
GRAMMAR_CONTEXT = "TranslationAggregate"
|
|
7
|
+
|
|
8
|
+
include WordGate
|
|
9
|
+
|
|
10
|
+
def initialize(name, was: nil)
|
|
11
|
+
raise Malformed, "an aggregate translation needs a name" if name.to_s.empty?
|
|
12
|
+
|
|
13
|
+
@name = name
|
|
14
|
+
@was = was
|
|
15
|
+
@renames = {}
|
|
16
|
+
@moves = []
|
|
17
|
+
@converts = []
|
|
18
|
+
@drops = []
|
|
19
|
+
@retypes = []
|
|
20
|
+
@computes = []
|
|
21
|
+
@rekeys = []
|
|
22
|
+
@backfills = []
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# RENAMED FROM `rename`/`move`/`convert`/`retype`/`compute`/
|
|
26
|
+
# `rekey`/`backfill` (all seven below) — item #13's full
|
|
27
|
+
# metaprogrammed dispatch (slice 4c). Not bootstrap-reachable
|
|
28
|
+
# (translation.bluebook describes ITS OWN structure with
|
|
29
|
+
# aggregate/entity/attribute, never with these — they're
|
|
30
|
+
# words for real, user-authored `.translation` files only,
|
|
31
|
+
# loaded after the grammar table exists), so none need a
|
|
32
|
+
# BOOTSTRAP_CALLS_FALLBACK entry.
|
|
33
|
+
def rename_impl(old_name, to:)
|
|
34
|
+
raise Malformed, "a rename needs a source name" if old_name.to_s.empty?
|
|
35
|
+
raise Malformed, "a rename needs a destination name (to:)" if to.to_s.empty?
|
|
36
|
+
|
|
37
|
+
@renames[old_name.to_sym] = to.to_sym
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def move_impl(old_path, to:)
|
|
41
|
+
raise Malformed, "a move needs a destination path (to:)" if to.to_s.empty?
|
|
42
|
+
raise Malformed, "a move needs a source path" if old_path.to_s.empty?
|
|
43
|
+
|
|
44
|
+
@moves << TranslationMove.new(old_path.to_s, to.to_s)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# A value with nothing structural in common with its replacement
|
|
48
|
+
# — declared as an exhaustive table, not computed, so every value
|
|
49
|
+
# that can appear in old data has a named destination. Paths
|
|
50
|
+
# follow `move`'s convention: dotted reaches a value-object member.
|
|
51
|
+
def convert_impl(old_path, to:, values:)
|
|
52
|
+
raise Malformed, "a convert needs a destination path (to:)" if to.to_s.empty?
|
|
53
|
+
raise Malformed, "a convert needs a source path" if old_path.to_s.empty?
|
|
54
|
+
raise Malformed, "a convert needs a values: table" if values.nil? || values.empty?
|
|
55
|
+
|
|
56
|
+
@converts << TranslationConvert.new(old_path.to_s, to.to_s, values)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# `drop` — item #13's full metaprogrammed dispatch, slice 2
|
|
60
|
+
# (whole-project table-unification survey): a declared,
|
|
61
|
+
# deliberate acknowledgment that an attribute's data does not
|
|
62
|
+
# survive the rename — the honest alternative to letting it
|
|
63
|
+
# vanish because nothing named it. A blank-guarded, kind-driven
|
|
64
|
+
# coerce-and-append with nothing else, now executed by
|
|
65
|
+
# `GenericDispatch`.
|
|
66
|
+
|
|
67
|
+
# A value object's or entity's own type name changed, member
|
|
68
|
+
# structure unchanged. The stored data never carries the type
|
|
69
|
+
# name, so nothing moves — this declares that the pair of names
|
|
70
|
+
# means the same shape, which is what lets the era diff accept it.
|
|
71
|
+
def retype_impl(old_type, to:)
|
|
72
|
+
raise Malformed, "a retype needs a source type name" if old_type.to_s.empty?
|
|
73
|
+
raise Malformed, "a retype needs a destination type name (to:)" if to.to_s.empty?
|
|
74
|
+
|
|
75
|
+
@retypes << TranslationRetype.new(old_type.to_s, to.to_s)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# A computed transform whose only implementation is the SQL
|
|
79
|
+
# expression itself — Postgres-only by construction. The scaffold
|
|
80
|
+
# never proposes one; a human writes it, and the audit's
|
|
81
|
+
# human-sampled review is its only verification.
|
|
82
|
+
def compute_impl(old_path, to:, sql:)
|
|
83
|
+
raise Malformed, "a compute needs a destination path (to:)" if to.to_s.empty?
|
|
84
|
+
raise Malformed, "a compute needs a source path" if old_path.to_s.empty?
|
|
85
|
+
raise Malformed, "a compute needs its sql: expression" if sql.to_s.empty?
|
|
86
|
+
|
|
87
|
+
@computes << TranslationCompute.new(old_path.to_s, to.to_s, sql.to_s)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# THE AGGREGATE'S OWN IDENTITY, changing what it's computed from —
|
|
91
|
+
# not a field crossing a boundary (`move`), not a value's own
|
|
92
|
+
# transform (`compute`): the record's key. No path arguments,
|
|
93
|
+
# unlike every rule above — nothing is consumed from or moved into
|
|
94
|
+
# `state`, only what identifies the record is recomputed. Same
|
|
95
|
+
# SQL-only, Postgres-only, human-reviewed-sample-is-the-only-
|
|
96
|
+
# verification shape `compute` already has, and for the same
|
|
97
|
+
# reason: there is nothing in-process to check this against.
|
|
98
|
+
def rekey_impl(sql:)
|
|
99
|
+
raise Malformed, "a rekey needs its sql: expression" if sql.to_s.empty?
|
|
100
|
+
|
|
101
|
+
@rekeys << TranslationRekey.new(sql.to_s)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# A NEWLY ADDED, required attribute — the addition-side sibling of
|
|
105
|
+
# `drop`. Nothing to rename, move, or convert FROM, since old data
|
|
106
|
+
# never held this field at all; `default` is what an existing
|
|
107
|
+
# record reads until the next command against it writes a real
|
|
108
|
+
# value. Adapter-agnostic, unlike `compute` — applied the same
|
|
109
|
+
# in-process way rename/move/drop already are
|
|
110
|
+
# (`Lineage#translate`), because there is nothing to compute here,
|
|
111
|
+
# only a value to declare. This is what
|
|
112
|
+
# `EraGuard.refuse_unsafe_addition!` asks for when a non-optional
|
|
113
|
+
# attribute with no default: could leave an existing record with
|
|
114
|
+
# the field genuinely absent.
|
|
115
|
+
def backfill_impl(name, default:)
|
|
116
|
+
raise Malformed, "a backfill needs a name" if name.to_s.empty?
|
|
117
|
+
raise Malformed, "a backfill needs a default: value" if default.nil?
|
|
118
|
+
|
|
119
|
+
@backfills << TranslationBackfill.new(name.to_sym, default)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# The scaffold writes this where it cannot decide; a file carrying
|
|
123
|
+
# one can only boot into this refusal — never a guess.
|
|
124
|
+
#
|
|
125
|
+
# RENAMED FROM `unresolved` — item #13's full metaprogrammed
|
|
126
|
+
# dispatch (slice 4). Builds its own message with real branching
|
|
127
|
+
# (empty vs. named candidates, a special :identity case), not a
|
|
128
|
+
# fixed string a boolean `refuses:` flag could express — reached
|
|
129
|
+
# through `calls:` instead, like `attribute`/`role`. NOT
|
|
130
|
+
# bootstrap-reachable: translation.bluebook (loaded during
|
|
131
|
+
# bootstrap, to describe the translation DSL itself) never
|
|
132
|
+
# writes `unresolved` — that word is only ever used by real,
|
|
133
|
+
# user-authored `.translation` files, loaded well after the
|
|
134
|
+
# grammar table exists — so no BOOTSTRAP_CALLS_FALLBACK entry is
|
|
135
|
+
# needed here (checked directly, not assumed).
|
|
136
|
+
def unresolved_impl(name, candidates: [])
|
|
137
|
+
raise Malformed, unresolved_message(name, candidates)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# `method_missing`/`respond_to_missing?` used to be hand-written
|
|
141
|
+
# here, giving a hand-typed "must be rename, move, convert, ..."
|
|
142
|
+
# list on every genuinely undefined call — WordGate (`include`d
|
|
143
|
+
# above) now answers the same question off the self-hosted
|
|
144
|
+
# grammar table instead, the exact "hardcoded legal-word list"
|
|
145
|
+
# this whole arc's item #13 exists to close. A word admitted
|
|
146
|
+
# elsewhere in the grammar but not in this context still gets a
|
|
147
|
+
# richer, table-driven refusal than the old generic one did.
|
|
148
|
+
|
|
149
|
+
def build
|
|
150
|
+
TranslationAggregate.new(
|
|
151
|
+
name: @name, was: @was, renames: @renames, moves: @moves, converts: @converts,
|
|
152
|
+
drops: @drops, retypes: @retypes, computes: @computes, rekeys: @rekeys, backfills: @backfills
|
|
153
|
+
)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
private
|
|
157
|
+
|
|
158
|
+
def unresolved_message(name, candidates)
|
|
159
|
+
return identity_unresolved_message if name.to_sym == :identity
|
|
160
|
+
|
|
161
|
+
rendered = Array(candidates).map { |candidate| render_path(candidate) }
|
|
162
|
+
if rendered.empty?
|
|
163
|
+
"#{@name}'s translation leaves #{render_path(name)} unresolved (no candidate matched — " \
|
|
164
|
+
"consider drop, or compute on Postgres) — replace unresolved with a real rule before booting."
|
|
165
|
+
else
|
|
166
|
+
"#{@name}'s translation leaves #{render_path(name)} unresolved (candidates: #{rendered.join(', ')}) — " \
|
|
167
|
+
"replace unresolved with a rename, move, convert, or drop before booting."
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def render_path(path)
|
|
172
|
+
path.to_s.include?(".") ? path.to_s.inspect : ":#{path}"
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# THE SCAFFOLD'S OWN HINT for the one drift it can detect but never
|
|
176
|
+
# resolve on its own — an aggregate's `identified_by` changed. Not
|
|
177
|
+
# a field to rename/move/drop, so none of the ordinary hints fit;
|
|
178
|
+
# `coverage_check.rb#check_identity_unchanged!` is the real gate,
|
|
179
|
+
# this only names the one rule that gets a legitimate mint through it.
|
|
180
|
+
def identity_unresolved_message
|
|
181
|
+
"#{@name}'s translation leaves its identity unresolved — identified_by changed since the held era. " \
|
|
182
|
+
"Declare a rekey rule (a rename/move/drop cannot fix this) before booting."
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
class TranslationBuilder
|
|
187
|
+
GRAMMAR_CONTEXT = "Translation"
|
|
188
|
+
|
|
189
|
+
include WordGate
|
|
190
|
+
|
|
191
|
+
def initialize(domain, from:, to:)
|
|
192
|
+
raise Malformed, "a translation names no domain" if domain.to_s.empty?
|
|
193
|
+
raise Malformed, "#{domain}'s translation says nothing about its origin era (from:)" if from.to_s.empty?
|
|
194
|
+
raise Malformed, "#{domain}'s translation says nothing about its destination era (to:)" if to.to_s.empty?
|
|
195
|
+
|
|
196
|
+
@domain = domain
|
|
197
|
+
@from = from
|
|
198
|
+
@to = to
|
|
199
|
+
@aggregates = []
|
|
200
|
+
@retired = []
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# RENAMED FROM `aggregate` — item #13's full metaprogrammed
|
|
204
|
+
# dispatch (slice 4c). Not bootstrap-reachable — this "Translation"
|
|
205
|
+
# -context `aggregate` (opens a TranslationAggregateBuilder) is a
|
|
206
|
+
# different (context, word) pair than "Bluebook"-context
|
|
207
|
+
# `aggregate` (the one translation.bluebook itself is described
|
|
208
|
+
# with), so it's never used to describe the language's own
|
|
209
|
+
# translation chapter.
|
|
210
|
+
def aggregate_impl(name, was: nil, &block)
|
|
211
|
+
builder = TranslationAggregateBuilder.new(name, was: was)
|
|
212
|
+
builder.instance_eval(&block) if block
|
|
213
|
+
@aggregates << builder.build
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
# `retired` — item #13's full metaprogrammed dispatch, slice 2
|
|
217
|
+
# (whole-project table-unification survey): an aggregate that is
|
|
218
|
+
# gone outright — not renamed. The deliberate alternative to a
|
|
219
|
+
# bogus `was:` claim on an unrelated aggregate. Same shape
|
|
220
|
+
# `TranslationAggregateBuilder#drop` is, now executed by
|
|
221
|
+
# `GenericDispatch`.
|
|
222
|
+
|
|
223
|
+
# `method_missing`/`respond_to_missing?` — same removal as
|
|
224
|
+
# TranslationAggregateBuilder's own, one level up: WordGate
|
|
225
|
+
# (`include`d above) answers off the self-hosted grammar table
|
|
226
|
+
# now instead of a hand-typed "it declares aggregate blocks and
|
|
227
|
+
# retired aggregates" message.
|
|
228
|
+
|
|
229
|
+
def build
|
|
230
|
+
MetaValidator.call_translation(
|
|
231
|
+
Translation.new(domain: @domain, from: @from, to: @to, aggregates: @aggregates, retired: @retired)
|
|
232
|
+
)
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def self.build(domain, from:, to:, &block)
|
|
236
|
+
builder = new(domain, from: from, to: to)
|
|
237
|
+
builder.instance_eval(&block) if block
|
|
238
|
+
builder.build
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
end
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
require_relative "word_gate"
|
|
2
|
+
module Hecks
|
|
3
|
+
module Bluebook
|
|
4
|
+
module DSL
|
|
5
|
+
class ValueObjectBuilder
|
|
6
|
+
GRAMMAR_CONTEXT = "ValueObject"
|
|
7
|
+
|
|
8
|
+
include AttributeCollector
|
|
9
|
+
include RuleReference
|
|
10
|
+
include WordGate
|
|
11
|
+
|
|
12
|
+
def initialize(name, owner_value_objects: [])
|
|
13
|
+
@name = name
|
|
14
|
+
@invariants = []
|
|
15
|
+
@members = []
|
|
16
|
+
@owner_value_objects = owner_value_objects
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# THE WRAPPER BLOCK IS GONE (ADR 0025, "Attributes" — "closed sets
|
|
20
|
+
# lose the wrapper block"). `member` lines are bare now, written
|
|
21
|
+
# directly in the `value_object` body with no `one_of do ... end`
|
|
22
|
+
# around them — `build`'s own `closed_set: @closed_set ||
|
|
23
|
+
# !@members.empty?` already treats a non-empty `@members` as closed,
|
|
24
|
+
# so nothing else has to change for that to work. A single-field set
|
|
25
|
+
# has an even shorter spelling: `attribute`'s own `one_of:` keyword
|
|
26
|
+
# (`AttributeCollector#install_inline_closed_set`, overridden below).
|
|
27
|
+
#
|
|
28
|
+
# This also removes a real, documented landmine: the block form
|
|
29
|
+
# collided with `AttributeCollector#one_of`'s own type-position
|
|
30
|
+
# method (`one_of("a", "b")`, different arity) the moment both were
|
|
31
|
+
# mixed into the same builder — a value_object could never actually
|
|
32
|
+
# use the inline form on one of its own attributes. One `one_of`
|
|
33
|
+
# method now, not two.
|
|
34
|
+
#
|
|
35
|
+
# LEGACY UNDER SHADOW-PARSING (S0a's own bridge) — frozen era text
|
|
36
|
+
# still writes the block form (2 locations in
|
|
37
|
+
# `examples/banking/data/eras/banking/1.bluebook`, duplicated once
|
|
38
|
+
# more in that era's own archive copy), so `EraGuard.shadow_parse`
|
|
39
|
+
# still needs to read it. `block_given?` is what tells the two
|
|
40
|
+
# calling shapes apart: the type-position form
|
|
41
|
+
# (`one_of("a", "b")`) never passes a block, only the wrapper does.
|
|
42
|
+
# RENAMED FROM `one_of` — item #13's full metaprogrammed dispatch
|
|
43
|
+
# (slice 5). SAME NAME as `AttributeCollector#one_of_impl`'s own
|
|
44
|
+
# — required for the `super(*values)` call below to keep
|
|
45
|
+
# resolving; see that method's own comment. Reached directly
|
|
46
|
+
# through its own "ValueObject"-context Keyword row (the
|
|
47
|
+
# block-wrapper form has its own row, distinct from "Type"'s),
|
|
48
|
+
# not through the Type-position fallback this word's OTHER
|
|
49
|
+
# context uses.
|
|
50
|
+
def one_of_impl(*values, &block)
|
|
51
|
+
unless block
|
|
52
|
+
# NO VALUES, NO BLOCK is the SCALAR spelling — nonsensical, not
|
|
53
|
+
# merely inert: it names a closed set with nothing in it. The
|
|
54
|
+
# original block form caught this by a side effect (`@closed_set
|
|
55
|
+
# = true` ran unconditionally, before the `if block`), and this
|
|
56
|
+
# keeps the same refusal rather than letting the call fall
|
|
57
|
+
# through and silently do nothing.
|
|
58
|
+
if values.empty?
|
|
59
|
+
raise Malformed,
|
|
60
|
+
"#{@name}'s one_of names no values — one_of(\"a\", \"b\") takes at least one, or " \
|
|
61
|
+
"give the attribute its own one_of: [...] for a named closed set"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# AttributeCollector's own `one_of(*values)` — Ruby's normal
|
|
65
|
+
# `super` reaches the included module's method from here.
|
|
66
|
+
return super(*values)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
unless MetaValidator.shadow_parsing?
|
|
70
|
+
raise Malformed,
|
|
71
|
+
"#{@name}'s one_of do ... end wrapper is gone — give the single attribute its " \
|
|
72
|
+
"own one_of: [...], or write bare member lines with no wrapper for a multi-field set"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
@closed_set = true
|
|
76
|
+
instance_eval(&block)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# RENAMED FROM `member` — item #13's full metaprogrammed dispatch
|
|
80
|
+
# (slice 4c). Bootstrap-reachable, in
|
|
81
|
+
# GenericDispatch::BOOTSTRAP_CALLS_FALLBACK.
|
|
82
|
+
def member_impl(**fields)
|
|
83
|
+
raise Malformed, "#{@name} declared an empty member" if fields.empty?
|
|
84
|
+
|
|
85
|
+
@members << fields
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# NO BLOCK is a REFERENCE, not a fresh declaration — the same
|
|
89
|
+
# move S10 already made for `CommandBuilder#given` (ADR 0025,
|
|
90
|
+
# "a precondition shared across commands is declared once... a
|
|
91
|
+
# command references it by name"), one level over: a rule
|
|
92
|
+
# shared across SIBLING value objects on the same aggregate,
|
|
93
|
+
# declared once, on the first one to need it. Real, live
|
|
94
|
+
# redundancy this closes: `Account`'s own `Money`/`PositiveMoney`
|
|
95
|
+
# both declared `invariant("a currency is a three-letter code")
|
|
96
|
+
# { currency.to_s.size == 3 }`, byte for byte. Declare it before
|
|
97
|
+
# the value objects that reference it — resolution happens at
|
|
98
|
+
# the referencing value object's own build time, against
|
|
99
|
+
# whatever sibling value objects the aggregate has already
|
|
100
|
+
# built, the same ordering rule `given` carries.
|
|
101
|
+
# RENAMED FROM `invariant` — item #13's full metaprogrammed
|
|
102
|
+
# dispatch (slice 4b). Bootstrap-reachable, in
|
|
103
|
+
# GenericDispatch::BOOTSTRAP_CALLS_FALLBACK.
|
|
104
|
+
def invariant_impl(description, &predicate)
|
|
105
|
+
return reference_named_invariant(description) unless predicate
|
|
106
|
+
|
|
107
|
+
# moved to the language: given "a rule says what it means", on Shape.Assert
|
|
108
|
+
|
|
109
|
+
@invariants << build_rule(Invariant, description, predicate, owner_name: @name, word: "invariant",
|
|
110
|
+
extraction_failure: "it would be a rule the IR cannot carry")
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
private
|
|
114
|
+
|
|
115
|
+
# PRIMITIVE 3 (RuleReference#resolve_sibling_scan) — see that
|
|
116
|
+
# method's own comment for why this is a live scan, not a pool.
|
|
117
|
+
def reference_named_invariant(description)
|
|
118
|
+
verify_resolves_via!("invariant", "ValueObject", "sibling_scan")
|
|
119
|
+
named = resolve_sibling_scan(@owner_value_objects, description, reader: :invariants) ||
|
|
120
|
+
raise(Malformed,
|
|
121
|
+
"#{@name}'s invariant #{description.inspect} names no rule a sibling value " \
|
|
122
|
+
"object on this aggregate declares — declare it once with a block, on the " \
|
|
123
|
+
"value object that needs it first, before the ones that reference it back")
|
|
124
|
+
|
|
125
|
+
@invariants << named
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
public
|
|
129
|
+
|
|
130
|
+
def build
|
|
131
|
+
if @inline_closed_set_field && attributes.size > 1
|
|
132
|
+
raise Malformed,
|
|
133
|
+
"#{@name}'s one_of: on :#{@inline_closed_set_field} only works when it is the " \
|
|
134
|
+
"value object's only attribute — #{attributes.size} declared here; write bare " \
|
|
135
|
+
"member lines instead for a multi-field set"
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
ValueObject.declare(
|
|
139
|
+
name: @name, attributes: attributes,
|
|
140
|
+
invariants: @invariants, members: @members,
|
|
141
|
+
closed_set: @closed_set || !@members.empty?
|
|
142
|
+
)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def self.build(name, owner_value_objects: [], &block)
|
|
146
|
+
builder = new(name, owner_value_objects: owner_value_objects)
|
|
147
|
+
builder.instance_eval(&block) if block
|
|
148
|
+
builder.build
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
private
|
|
152
|
+
|
|
153
|
+
# THE NEW SPELLING — `attribute :name, String, one_of: %w[...]`,
|
|
154
|
+
# overriding `AttributeCollector`'s own refusal (every OTHER
|
|
155
|
+
# includer has no meaningful use for this). PRIVATE, like the
|
|
156
|
+
# module's own version it overrides — it is a callback `attribute`
|
|
157
|
+
# invokes on itself, never a word a bluebook author calls by name.
|
|
158
|
+
# Refuses a SECOND attribute naming one_of: on the same value
|
|
159
|
+
# object outright — a single-field set names exactly one field, by
|
|
160
|
+
# construction; two would be structurally ambiguous about which
|
|
161
|
+
# field each member line belongs to. `build` refuses the OTHER
|
|
162
|
+
# half of that same rule (this attribute coexisting with unrelated
|
|
163
|
+
# ones on a multi-field object).
|
|
164
|
+
def install_inline_closed_set(field, values)
|
|
165
|
+
if @inline_closed_set_field && @inline_closed_set_field != field
|
|
166
|
+
raise Malformed,
|
|
167
|
+
"#{@name} declares one_of: on more than one attribute (:#{@inline_closed_set_field} " \
|
|
168
|
+
"and :#{field}) — a single-field closed set names exactly one"
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
@inline_closed_set_field = field
|
|
172
|
+
@closed_set = true
|
|
173
|
+
values.each { |value| member_impl(field => value.to_s) }
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|