hecks 0.2.0 → 1.0.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 +427 -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 +101 -0
- data/lib/hecks/adapters/driven/heki/journal.rb +56 -0
- data/lib/hecks/adapters/driven/heki/saga_store.rb +99 -0
- data/lib/hecks/adapters/driven/heki/snapshot.rb +65 -0
- data/lib/hecks/adapters/driven/heki.adapter +4 -0
- data/lib/hecks/adapters/driven/heki.rb +179 -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 +145 -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 +88 -0
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +207 -0
- data/lib/hecks/adapters/driven/postgres.adapter +5 -0
- data/lib/hecks/adapters/driven/postgres.rb +438 -0
- data/lib/hecks/adapters/driven/postgres_era.adapter +17 -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 +80 -0
- data/lib/hecks/adapters/driven/sqlite/projection.rb +172 -0
- data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +192 -0
- data/lib/hecks/adapters/driven/sqlite.adapter +9 -0
- data/lib/hecks/adapters/driven/sqlite.rb +306 -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 +54 -0
- data/lib/hecks/adapters.rb +6 -0
- data/lib/hecks/behaviors/dsl.rb +125 -0
- data/lib/hecks/behaviors/expectations.rb +340 -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 +438 -0
- data/lib/hecks/bluebook/assembly/marks.rb +228 -0
- data/lib/hecks/bluebook/assembly/specializer.rb +70 -0
- data/lib/hecks/bluebook/assembly.rb +91 -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 +68 -0
- data/lib/hecks/bluebook/behaviour/policy.rb +52 -0
- data/lib/hecks/bluebook/behaviour/process_manager.rb +51 -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 +78 -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 +1018 -0
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +348 -0
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +71 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +1087 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +714 -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 +430 -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 +135 -0
- data/lib/hecks/bluebook/dsl/port_builder.rb +39 -0
- data/lib/hecks/bluebook/dsl/port_operation_builder.rb +142 -0
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +306 -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 +173 -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 +228 -0
- data/lib/hecks/bluebook/dsl/world_builder.rb +117 -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 +123 -0
- data/lib/hecks/bluebook/expression/evaluator.rb +304 -0
- data/lib/hecks/bluebook/expression/projection.json +218 -0
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +233 -0
- data/lib/hecks/bluebook/expression/resolver.rb +781 -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 +621 -0
- data/lib/hecks/bluebook/meta_validator/plan.rb +332 -0
- data/lib/hecks/bluebook/meta_validator/port_judge.rb +51 -0
- data/lib/hecks/bluebook/meta_validator/readings.rb +360 -0
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +351 -0
- data/lib/hecks/bluebook/meta_validator/shapes.rb +266 -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 +542 -0
- data/lib/hecks/bluebook/model_check.rb +445 -0
- data/lib/hecks/bluebook/pattern_subset.rb +184 -0
- data/lib/hecks/bluebook/policy.rb +41 -0
- data/lib/hecks/bluebook/process_manager.rb +128 -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 +66 -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 +410 -0
- data/lib/hecks/embryonaut_bluebook.rb +75 -0
- data/lib/hecks/facade/cli_door.rb +119 -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 +166 -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 +341 -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 +177 -0
- data/lib/hecks/forms/field_shape.rb +232 -0
- data/lib/hecks/forms/html.rb +84 -0
- data/lib/hecks/forms/index_renderer.rb +35 -0
- data/lib/hecks/forms/page.rb +157 -0
- data/lib/hecks/forms/params.rb +161 -0
- data/lib/hecks/forms/port_argument.rb +46 -0
- data/lib/hecks/forms/query_form_renderer.rb +114 -0
- data/lib/hecks/forms/record_renderer.rb +119 -0
- data/lib/hecks/forms/record_table.rb +68 -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 +145 -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/bounded_exhaustive_expressions.rb +527 -0
- data/lib/hecks/fuzzing/invalid_value_generator.rb +86 -0
- data/lib/hecks/fuzzing/isolated_boot.rb +286 -0
- data/lib/hecks/fuzzing/properties.rb +1192 -0
- data/lib/hecks/fuzzing/replay.rb +668 -0
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +93 -0
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +80 -0
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +96 -0
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +250 -0
- data/lib/hecks/fuzzing/sequence_generator.rb +131 -0
- data/lib/hecks/fuzzing/value_generator.rb +200 -0
- data/lib/hecks/fuzzing.rb +12 -0
- data/lib/hecks/grammar/evolve.rb +324 -0
- data/lib/hecks/grammar/expression.bluebook +420 -0
- data/lib/hecks/grammar/expression_operators.json +1648 -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 +471 -0
- data/lib/hecks/language/bluebook/entity.bluebook +392 -0
- data/lib/hecks/language/bluebook/policy.bluebook +189 -0
- data/lib/hecks/language/bluebook/process_manager.bluebook +381 -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 +448 -0
- data/lib/hecks/language/bluebook/vocabulary.bluebook +379 -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 +333 -0
- data/lib/hecks/language/port.bluebook +120 -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 +174 -0
- data/lib/hecks/ports/access_control.port +9 -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 +8 -0
- data/lib/hecks/ports/agent.rb +167 -0
- data/lib/hecks/ports/authentication.port +6 -0
- data/lib/hecks/ports/authentication.rb +50 -0
- data/lib/hecks/ports/authorization.port +7 -0
- data/lib/hecks/ports/authorization.rb +62 -0
- data/lib/hecks/ports/clock.port +5 -0
- data/lib/hecks/ports/clock.rb +62 -0
- data/lib/hecks/ports/extraction.port +5 -0
- data/lib/hecks/ports/extraction.rb +37 -0
- data/lib/hecks/ports/identity_assignment.port +5 -0
- data/lib/hecks/ports/identity_assignment.rb +45 -0
- data/lib/hecks/ports/identity_generation.port +5 -0
- data/lib/hecks/ports/identity_generation.rb +49 -0
- data/lib/hecks/ports/identity_resolution.port +5 -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 +138 -0
- data/lib/hecks/ports/persistence/binding_policy.rb +56 -0
- data/lib/hecks/ports/persistence/execution.rb +23 -0
- data/lib/hecks/ports/persistence/null_saga_store.rb +25 -0
- data/lib/hecks/ports/persistence/plugin.rb +54 -0
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +169 -0
- data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +128 -0
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +161 -0
- data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +61 -0
- data/lib/hecks/ports/persistence/plugins/era/lineage.rb +304 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +171 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +190 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +478 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +166 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +314 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +168 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +170 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +134 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +137 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +89 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +85 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +43 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +132 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +74 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +758 -0
- data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +120 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +31 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +46 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +102 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +46 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +70 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +72 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +120 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +183 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +41 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +28 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +30 -0
- data/lib/hecks/ports/persistence/plugins/era/translation.rb +11 -0
- data/lib/hecks/ports/persistence/plugins/era.rb +48 -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 +96 -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 +642 -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 +44 -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 +446 -0
- data/lib/hecks/projector/docs_projector.rb +321 -0
- data/lib/hecks/projector/exporter.rb +158 -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 +411 -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 +92 -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 +107 -0
- data/lib/hecks/query_specification/hop_path.rb +132 -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/aggregate_lock.rb +45 -0
- data/lib/hecks/runtime/boot_gates.rb +41 -0
- data/lib/hecks/runtime/caller.rb +66 -0
- data/lib/hecks/runtime/capability_graph.rb +44 -0
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +135 -0
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +260 -0
- data/lib/hecks/runtime/command_interpreter.rb +497 -0
- data/lib/hecks/runtime/command_rules/admissibility.rb +357 -0
- data/lib/hecks/runtime/command_rules/arithmetic.rb +260 -0
- data/lib/hecks/runtime/command_rules/authorization.rb +65 -0
- data/lib/hecks/runtime/command_rules/emission.rb +34 -0
- data/lib/hecks/runtime/command_rules/references.rb +189 -0
- data/lib/hecks/runtime/command_rules.rb +28 -0
- data/lib/hecks/runtime/dependency_planning.rb +245 -0
- data/lib/hecks/runtime/dispatcher.rb +301 -0
- data/lib/hecks/runtime/entity_element.rb +253 -0
- data/lib/hecks/runtime/entity_interpreter.rb +299 -0
- data/lib/hecks/runtime/errors.rb +122 -0
- data/lib/hecks/runtime/event.rb +51 -0
- data/lib/hecks/runtime/identity.rb +156 -0
- data/lib/hecks/runtime/instance.rb +175 -0
- data/lib/hecks/runtime/interpreting.rb +90 -0
- data/lib/hecks/runtime/loader.rb +184 -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 +286 -0
- data/lib/hecks/runtime/reaction_invocation.rb +253 -0
- data/lib/hecks/runtime/read_model_interpreter.rb +341 -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 +126 -0
- data/lib/hecks/runtime/registry/saga_persistence.rb +142 -0
- data/lib/hecks/runtime/registry/verification.rb +246 -0
- data/lib/hecks/runtime/registry.rb +279 -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 +503 -0
- data/lib/hecks/runtime/saga_pending_dispatch.rb +45 -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 +130 -0
- data/lib/hecks/runtime/value/coercion.rb +565 -0
- data/lib/hecks/runtime/value/invariant_violation.rb +5 -0
- data/lib/hecks/runtime/value.rb +125 -0
- data/lib/hecks/runtime.rb +107 -0
- data/lib/hecks/storehouse.rb +632 -0
- data/lib/hecks/version.rb +16 -0
- data/lib/hecks/vocabulary.rb +218 -0
- data/lib/hecks.rb +123 -6
- data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +90 -0
- data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +128 -0
- data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +160 -0
- metadata +412 -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,166 @@
|
|
|
1
|
+
require_relative "synthesizer"
|
|
2
|
+
require "tmpdir"
|
|
3
|
+
require "fileutils"
|
|
4
|
+
|
|
5
|
+
module Hecks
|
|
6
|
+
module Bluebook
|
|
7
|
+
# BOOTS A REAL BLUEBOOK AND ACTUALLY DISPATCHES AGAINST IT — the
|
|
8
|
+
# sibling `bin/model_check` never had: that tool proves a bluebook
|
|
9
|
+
# is STRUCTURALLY sound (no dead states, no unreachable transitions)
|
|
10
|
+
# without ever running a single command; this proves it WORKS,
|
|
11
|
+
# catching exactly the class of bug static analysis structurally
|
|
12
|
+
# cannot see. Built and proved inside `bin/interview`'s own `smoke`
|
|
13
|
+
# command, where it first found two real bugs — a lifecycle field
|
|
14
|
+
# colliding with an explicit attribute, and a non-creating command
|
|
15
|
+
# missing `Command.ActsOn` — that reloaded clean, checked clean,
|
|
16
|
+
# and only broke once something actually dispatched against them.
|
|
17
|
+
#
|
|
18
|
+
# SYNTHESIZED ARGS, NEVER RANDOM (`Synthesizer`) — a String becomes
|
|
19
|
+
# a fixed marker, a closed set uses its own first admitted member, a
|
|
20
|
+
# reference reuses whatever this same run already minted for that
|
|
21
|
+
# target. ONE call per declared command, ONE call per declared
|
|
22
|
+
# report, per created root; every failure is collected and reported
|
|
23
|
+
# together rather than stopping at the first.
|
|
24
|
+
#
|
|
25
|
+
# WHAT THIS CANNOT CATCH: a call that dispatches cleanly but answers
|
|
26
|
+
# WRONG — the read-model join bug this exact tool's own first user
|
|
27
|
+
# hit is the textbook case, a query that silently returned an empty
|
|
28
|
+
# array rather than raising. Smoke-testing proves nothing crashes;
|
|
29
|
+
# it does not prove the answer is the right one.
|
|
30
|
+
#
|
|
31
|
+
# A FAILURE HERE IS NOT NECESSARILY A DOMAIN BUG, either — it may
|
|
32
|
+
# just be `Synthesizer`'s own naive values (0, an empty list,
|
|
33
|
+
# "smoke-test") not satisfying a real invariant this simple
|
|
34
|
+
# generator was never built to reason about (a positive amount, a
|
|
35
|
+
# non-empty topping list, an email pattern). Confirmed against
|
|
36
|
+
# Banking and Pizzas: both real domains, both showing exactly that
|
|
37
|
+
# class of failure, neither one an actual bug. Building a
|
|
38
|
+
# synthesizer that respects arbitrary declared invariants is real
|
|
39
|
+
# constraint-aware generation — a separate, larger tool than this.
|
|
40
|
+
module SmokeTest
|
|
41
|
+
Failure = Struct.new(:domain, :aggregate, :command, :error, keyword_init: true) do
|
|
42
|
+
def to_s = "#{domain}::#{aggregate}.#{command}: #{error}"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
module_function
|
|
46
|
+
|
|
47
|
+
# `dir` is any real, bootable hecks app directory — a saved
|
|
48
|
+
# domain, or a throwaway one a caller rendered into a temp dir
|
|
49
|
+
# for exactly this purpose. Plain `Hecks.boot`, not
|
|
50
|
+
# `Router.boot` — proven all night, and it works against a
|
|
51
|
+
# domain with framework-attached chapters (`uses_framework
|
|
52
|
+
# "Governance"`, say) that `Router.boot` refuses outright: those
|
|
53
|
+
# chapters carry no `.world` of their own, which `Router`'s
|
|
54
|
+
# per-domain realm resolution requires and a plain boot never
|
|
55
|
+
# did. Reports are reachable the identical way regardless of
|
|
56
|
+
# boot path — `dispatcher.query("Domain.report_name", **args)`
|
|
57
|
+
# is the SAME `Dispatcher#query` either boot hands back; Router
|
|
58
|
+
# was never actually required for this, only its OWN namespace
|
|
59
|
+
# SUGAR (`Domain.report_name(...)` as a bare method call) was.
|
|
60
|
+
#
|
|
61
|
+
# NEVER BOOTS `dir`'S OWN REAL BINDINGS — measured, not a
|
|
62
|
+
# precaution taken on spec: pointed at `examples/pizzas` (a real,
|
|
63
|
+
# persistent store carrying real accumulated records), a
|
|
64
|
+
# synthesized `CreatePizza` collided with an actual pre-existing
|
|
65
|
+
# record literally named "smoke-test" — a coincidence this time,
|
|
66
|
+
# data pollution the next. `isolate!` copies only the `.bluebook`
|
|
67
|
+
# (and `.world`, for its realm) into a throwaway directory and
|
|
68
|
+
# deliberately leaves the real `.hecksagon` behind — with none
|
|
69
|
+
# present, `Ports::Persistence::BindingPolicy.default_binding`
|
|
70
|
+
# binds every aggregate to Memory on its own, no settings needed.
|
|
71
|
+
# Whatever `dir` is really bound to in production is never
|
|
72
|
+
# touched.
|
|
73
|
+
# `install_facade: false` — this only ever dispatches by FQN string
|
|
74
|
+
# (below), so it never needs the `Widget::Item.Add(...)` Ruby
|
|
75
|
+
# sugar `Hecks.boot` installs by default. Skipping it matters
|
|
76
|
+
# here specifically: that sugar lands as a BARE global constant on
|
|
77
|
+
# `Object` per domain and per aggregate name, with no scoping and
|
|
78
|
+
# no cleanup — and this tool boots throwaway domains under
|
|
79
|
+
# whatever generic names the caller's `.bluebook` happens to use
|
|
80
|
+
# ("Widget", "Item", "Tag" in this tool's own specs). Installing
|
|
81
|
+
# the facade would leak those names into the rest of the process —
|
|
82
|
+
# measured, not hypothetical: it once left a stale `Widget` constant
|
|
83
|
+
# that corrupted an unrelated spec's own unrelated use of the same
|
|
84
|
+
# bare name.
|
|
85
|
+
def call(dir)
|
|
86
|
+
Dir.mktmpdir("hecks-smoke-") do |scratch|
|
|
87
|
+
isolate!(dir, scratch)
|
|
88
|
+
dispatcher = Hecks.boot(scratch, install_facade: false)
|
|
89
|
+
domain = dispatcher.registry.bluebooks.keys.first
|
|
90
|
+
next [] unless domain
|
|
91
|
+
|
|
92
|
+
smoke_domain(dispatcher, domain)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# ONLY THE `.bluebook`, NEVER `.world` EITHER — a real world's own
|
|
97
|
+
# settings (`persisted_by("Heki") { dir "..." }`) are keyed to the
|
|
98
|
+
# REAL adapter it names, not to Memory; copied verbatim, they
|
|
99
|
+
# apply to the wrong binding and refuse with a `WiringError`
|
|
100
|
+
# ("Memory does not declare :dir") — measured, not assumed, the
|
|
101
|
+
# first time this ran against Banking. A plain `Hecks.boot`
|
|
102
|
+
# needs no realm to address anything (unlike `Router.boot`), so
|
|
103
|
+
# leaving the world out entirely is the correct minimal isolation,
|
|
104
|
+
# not a workaround. `translations/*.bluebook` also deliberately
|
|
105
|
+
# excluded — those are earlier, superseded versions of the same
|
|
106
|
+
# domain; smoke-testing the current declaration is the point, not
|
|
107
|
+
# its whole history.
|
|
108
|
+
def isolate!(dir, scratch)
|
|
109
|
+
source = Adapters::Folder.new.bluebook_directory(dir)
|
|
110
|
+
target = File.join(scratch, "bluebook")
|
|
111
|
+
FileUtils.mkdir_p(target)
|
|
112
|
+
Dir.glob(File.join(source, "*.bluebook")).each { |file| FileUtils.cp(file, target) }
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# AGGREGATES WALKED IN DECLARATION ORDER, on purpose — so whatever
|
|
116
|
+
# a LATER aggregate's own shape needs from an EARLIER one (a
|
|
117
|
+
# `TripItem` needing a real `PackingItem`, say) already exists by
|
|
118
|
+
# the time that aggregate's own turn comes, the same reason
|
|
119
|
+
# `Synthesizer#args_for`'s `created` map is threaded through in
|
|
120
|
+
# this same order.
|
|
121
|
+
def smoke_domain(dispatcher, domain)
|
|
122
|
+
chapter = dispatcher.registry.bluebook(domain)
|
|
123
|
+
return [] unless chapter
|
|
124
|
+
|
|
125
|
+
created = {}
|
|
126
|
+
failures = []
|
|
127
|
+
|
|
128
|
+
chapter.aggregates.each do |aggregate|
|
|
129
|
+
creating, noncreating = aggregate.commands.partition(&:creates?)
|
|
130
|
+
|
|
131
|
+
creating.each do |command|
|
|
132
|
+
args = Synthesizer.args_for(chapter, aggregate, command, created)
|
|
133
|
+
begin
|
|
134
|
+
result = dispatcher.dispatch("#{domain}::#{aggregate.name}.#{command.hecks_name}", **args)
|
|
135
|
+
created[aggregate.name] = result.instance.id
|
|
136
|
+
rescue StandardError => e
|
|
137
|
+
failures << Failure.new(domain: domain, aggregate: aggregate.name, command: command.hecks_name,
|
|
138
|
+
error: "#{e.class}: #{e.message}")
|
|
139
|
+
next
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
noncreating.each do |nc_command|
|
|
143
|
+
nc_args = Synthesizer.args_for(chapter, aggregate, nc_command, created).merge(id: created[aggregate.name])
|
|
144
|
+
dispatcher.dispatch("#{domain}::#{aggregate.name}.#{nc_command.hecks_name}", **nc_args)
|
|
145
|
+
rescue StandardError => e
|
|
146
|
+
failures << Failure.new(domain: domain, aggregate: aggregate.name, command: nc_command.hecks_name,
|
|
147
|
+
error: "#{e.class}: #{e.message}")
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
chapter.read_models.each do |model|
|
|
153
|
+
root_id = created[model.reference_target]
|
|
154
|
+
next unless root_id # nothing was created for this root — nothing to smoke-test yet, not a failure
|
|
155
|
+
|
|
156
|
+
dispatcher.query("#{domain}.#{model.query_name}", model.reference_name => root_id)
|
|
157
|
+
rescue StandardError => e
|
|
158
|
+
failures << Failure.new(domain: domain, aggregate: model.name, command: "report(#{model.name})",
|
|
159
|
+
error: "#{e.class}: #{e.message}")
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
failures
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
module Hecks
|
|
2
|
+
module Bluebook
|
|
3
|
+
# ONE SYNTHESIZED ARGUMENT PER DECLARED ATTRIBUTE — never a random
|
|
4
|
+
# guess. Reads only real `IR` (`Aggregate`, `Command`,
|
|
5
|
+
# `Attribute`, `ValueObject`), so it works against ANY
|
|
6
|
+
# loaded bluebook, not one particular domain: a String becomes a
|
|
7
|
+
# fixed marker; an Integer becomes 0; a closed set uses ITS OWN
|
|
8
|
+
# first admitted member (never a value a real `one_of` would
|
|
9
|
+
# legitimately refuse); a reference uses whatever id the CALLER
|
|
10
|
+
# already knows for that target (`created`), so a command whose
|
|
11
|
+
# own shape depends on an earlier-created record — a `TripItem`
|
|
12
|
+
# needing a real `PackingItem`, say — gets something real to work
|
|
13
|
+
# with instead of a guess that would only ever fail.
|
|
14
|
+
#
|
|
15
|
+
# Extracted from `bin/interview`'s own smoke test, where this first
|
|
16
|
+
# got built and proved — the logic never actually knew anything
|
|
17
|
+
# about the Interview domain or any one app; it only ever read IR.
|
|
18
|
+
module Synthesizer
|
|
19
|
+
# THE ONLY TYPE NAMES THAT ARE EVER TRULY SCALAR — anything else
|
|
20
|
+
# a value object's own field names is ANOTHER value object,
|
|
21
|
+
# nested (`Pizza.price_cents: Price`, itself wrapping `cents:
|
|
22
|
+
# Integer` — a real, ordinary shape, not an edge case). Missing
|
|
23
|
+
# this the first time round meant a nested field silently
|
|
24
|
+
# synthesized as the bare string `"smoke-test"` instead of the
|
|
25
|
+
# real nested structure a command actually declares — caught
|
|
26
|
+
# only by testing against Pizzas instead of re-testing against
|
|
27
|
+
# the one simpler domain this was first built for, where every
|
|
28
|
+
# value object happened to be single-field and primitive-typed.
|
|
29
|
+
# THE SAME LIST `Attribute::PRIMITIVES` holds, referenced rather
|
|
30
|
+
# than repeated. It was a second, byte-identical copy — and only
|
|
31
|
+
# the Attribute one is held to `vocabulary.bluebook` by
|
|
32
|
+
# spec/vocabulary_conformance_spec, so this copy could drift from
|
|
33
|
+
# the language and nothing would say so.
|
|
34
|
+
PRIMITIVES = Attribute::PRIMITIVES
|
|
35
|
+
|
|
36
|
+
module_function
|
|
37
|
+
|
|
38
|
+
# `chapter`/`aggregate` are the real `Bluebook`/`Aggregate`
|
|
39
|
+
# the command belongs to — needed to resolve a value object type
|
|
40
|
+
# name back to its own declared shape. `created` maps an
|
|
41
|
+
# aggregate NAME to a real id already minted for it earlier in
|
|
42
|
+
# the same run; a reference whose target isn't in there yet gets
|
|
43
|
+
# a placeholder instead of failing outright, since the caller may
|
|
44
|
+
# not care about that particular argument's real value.
|
|
45
|
+
def args_for(chapter, aggregate, command, created = {})
|
|
46
|
+
command.attributes.to_h do |attribute|
|
|
47
|
+
if attribute.reference?
|
|
48
|
+
[attribute.name, created.fetch(attribute.type.target_name, "smoke-test-id")]
|
|
49
|
+
else
|
|
50
|
+
[attribute.name, value_for(chapter, aggregate, attribute.type)]
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# A value object's OWN synthesized value — its first admitted
|
|
56
|
+
# member if it's a closed set (the one value guaranteed not to be
|
|
57
|
+
# refused), otherwise one synthesized scalar per declared field.
|
|
58
|
+
# Falls back to searching every aggregate in the chapter, the
|
|
59
|
+
# same tolerance `bin/interview shape`'s own lookup already
|
|
60
|
+
# needed: a value object referenced by name doesn't have to be
|
|
61
|
+
# declared on the SAME aggregate using it.
|
|
62
|
+
def value_for(chapter, aggregate, type_name)
|
|
63
|
+
value_object = aggregate.value_object(type_name) ||
|
|
64
|
+
chapter.aggregates.filter_map { |a| a.value_object(type_name) }.first
|
|
65
|
+
return "smoke-test" unless value_object
|
|
66
|
+
|
|
67
|
+
return value_object.members.first.to_h if value_object.respond_to?(:closed_set?) && value_object.closed_set? && value_object.members.any?
|
|
68
|
+
|
|
69
|
+
value_object.attributes.to_h { |field| [field.name, field_value_for(chapter, aggregate, field.type)] }
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# A single field's own synthesized value — a plain scalar if its
|
|
73
|
+
# type is one of the true primitives, otherwise that type names
|
|
74
|
+
# ANOTHER value object, resolved the identical way `value_for`
|
|
75
|
+
# resolves any other one (its own closed set or its own nested
|
|
76
|
+
# fields, however deep that nesting actually goes).
|
|
77
|
+
def field_value_for(chapter, aggregate, type_name)
|
|
78
|
+
PRIMITIVES.include?(type_name.to_s) ? scalar_for(type_name) : value_for(chapter, aggregate, type_name)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# A bare primitive's own synthesized value. Never used for a
|
|
82
|
+
# closed set's OWN field (that's `value_for`'s job, reading the
|
|
83
|
+
# set's real first member) — only for a plain scalar field with
|
|
84
|
+
# no declared vocabulary to respect.
|
|
85
|
+
def scalar_for(primitive)
|
|
86
|
+
case primitive.to_s
|
|
87
|
+
when "Integer" then 0
|
|
88
|
+
when "Float" then 0.0
|
|
89
|
+
when "TrueClass", "FalseClass" then false
|
|
90
|
+
else "smoke-test"
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
module Hecks
|
|
2
|
+
module Bluebook
|
|
3
|
+
# One field crossing a value-object boundary: a scalar becoming a VO
|
|
4
|
+
# member, a VO member becoming a scalar, or a rename across the move.
|
|
5
|
+
# Paths are dotted ("price.cents") for a VO member, bare otherwise.
|
|
6
|
+
TranslationMove = Struct.new(:from, :to)
|
|
7
|
+
|
|
8
|
+
# One field whose VALUE, not just its name or position, changed —
|
|
9
|
+
# an old value has nothing in common with a new one, so the only
|
|
10
|
+
# honest way to bridge it is a declared, exhaustive lookup table.
|
|
11
|
+
# Paths follow `TranslationMove`'s convention (dotted reaches a VO
|
|
12
|
+
# member); `values` maps every old-era value that can appear to its
|
|
13
|
+
# new-era replacement.
|
|
14
|
+
TranslationConvert = Struct.new(:from, :to, :values)
|
|
15
|
+
|
|
16
|
+
# A value object's or entity's own TYPE NAME changed with its member
|
|
17
|
+
# structure unchanged — the one drift `rename`/`move` cannot express,
|
|
18
|
+
# because the attribute kept its name and only the type it points at
|
|
19
|
+
# was renamed. Mirrors `was:` one level deeper.
|
|
20
|
+
TranslationRetype = Struct.new(:from, :to)
|
|
21
|
+
|
|
22
|
+
# A computed transform — rescale, reformat, split, merge — whose only
|
|
23
|
+
# implementation is the SQL expression itself, evaluated exclusively
|
|
24
|
+
# inside the compiled Postgres head. No in-process reference exists
|
|
25
|
+
# to check it against; any aggregate carrying one refuses to boot on
|
|
26
|
+
# every other adapter.
|
|
27
|
+
TranslationCompute = Struct.new(:from, :to, :sql)
|
|
28
|
+
|
|
29
|
+
# The aggregate's own IDENTITY changed what it's computed from — not
|
|
30
|
+
# a field crossing a boundary (that's `move`), a value objects's type
|
|
31
|
+
# name (`retype`), or a value transform (`compute`): the record's own
|
|
32
|
+
# key. No `from:`/`to:` path, unlike every other rule here, because
|
|
33
|
+
# nothing is being consumed from or moved into `state` — the state
|
|
34
|
+
# a record already holds is untouched; only what identifies it is
|
|
35
|
+
# recomputed. Same SQL-only, Postgres-only, no-in-process-reference
|
|
36
|
+
# shape `compute` already has, and for the same reason: there is
|
|
37
|
+
# nothing to check this against outside the compiled head.
|
|
38
|
+
TranslationRekey = Struct.new(:sql)
|
|
39
|
+
|
|
40
|
+
# A newly added, required attribute with no source in old data at
|
|
41
|
+
# all — not a rename, move, or convert, all of which need a FROM
|
|
42
|
+
# path in the old shape. `default` is the value an existing record
|
|
43
|
+
# reads until the next command against it writes a real one; unlike
|
|
44
|
+
# `compute`, this is adapter-agnostic — applied in-process by
|
|
45
|
+
# `Lineage#translate`, the same as rename/move/drop, because there is
|
|
46
|
+
# nothing to compute, only a value to declare.
|
|
47
|
+
TranslationBackfill = Struct.new(:name, :default)
|
|
48
|
+
|
|
49
|
+
# One aggregate's part of a translation: which attributes were
|
|
50
|
+
# renamed, moved, converted, or deliberately dropped on the way from
|
|
51
|
+
# the old era to the new one. `drops` exists so data loss is a
|
|
52
|
+
# declared decision, not a field that quietly stopped being
|
|
53
|
+
# explained.
|
|
54
|
+
class TranslationAggregate
|
|
55
|
+
attr_reader :name, :was, :renames, :moves, :converts, :drops, :retypes, :computes, :rekeys, :backfills
|
|
56
|
+
|
|
57
|
+
def initialize(name:, was: nil, renames: {}, moves: [], converts: [], drops: [], retypes: [],
|
|
58
|
+
computes: [], rekeys: [], backfills: [])
|
|
59
|
+
@name = name.to_s
|
|
60
|
+
@was = was&.to_s
|
|
61
|
+
@renames = renames
|
|
62
|
+
@moves = moves
|
|
63
|
+
@converts = converts
|
|
64
|
+
@drops = drops
|
|
65
|
+
@retypes = retypes
|
|
66
|
+
@computes = computes
|
|
67
|
+
@rekeys = rekeys
|
|
68
|
+
@backfills = backfills
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# A declared map from one era of a domain's storage shape to the
|
|
73
|
+
# next. Renames and moves — the smallest slice that proves the
|
|
74
|
+
# concept: old records are translated when they are replayed, never
|
|
75
|
+
# rewritten. `retired` acknowledges aggregates that are gone
|
|
76
|
+
# outright — not renamed — so their disappearance is a decision,
|
|
77
|
+
# not an accident.
|
|
78
|
+
class Translation
|
|
79
|
+
attr_reader :domain, :from, :to, :aggregates, :retired
|
|
80
|
+
|
|
81
|
+
def initialize(domain:, from:, to:, aggregates: [], retired: [])
|
|
82
|
+
@domain = domain.to_s
|
|
83
|
+
@from = from
|
|
84
|
+
@to = to
|
|
85
|
+
@aggregates = aggregates
|
|
86
|
+
@retired = retired
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def for_aggregate(name) = @aggregates.find { |aggregate| aggregate.name == name.to_s }
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
require_relative "behaviour/value_object"
|
|
2
|
+
|
|
3
|
+
module Hecks
|
|
4
|
+
module Bluebook
|
|
5
|
+
Invariant = Struct.new(:description, :canonical, :predicate, keyword_init: true)
|
|
6
|
+
|
|
7
|
+
# A value object — a DECLARATION HOLDER, never instantiated.
|
|
8
|
+
#
|
|
9
|
+
# `ValueObjectBuilder` returns an anonymous subclass whose singleton
|
|
10
|
+
# carries the declaration : attributes, invariants, members. Nothing ever
|
|
11
|
+
# calls `.new` on one — coercion builds `Runtime::Value` wrappers, and
|
|
12
|
+
# invariants run as canonical text through the Evaluator. The runtime
|
|
13
|
+
# reaches a shape through `aggregate.value_object(name)`, the IR's own
|
|
14
|
+
# finder ; there is no constant nesting and no second index.
|
|
15
|
+
#
|
|
16
|
+
# `to_h` does not move. It is a byte-for-byte contract pinned by the
|
|
17
|
+
# golden fixtures, so it keeps spelling the short declared name, which
|
|
18
|
+
# is what `hecks_name` carries. DECLARATIONS IN THE GRAPH, STRINGS IN THE
|
|
19
|
+
# EXPORT.
|
|
20
|
+
class ValueObject
|
|
21
|
+
extend Construct
|
|
22
|
+
# EXTENDED, not included — this construct is a class, so its
|
|
23
|
+
# emission is a class method. See Hecks::IR's own note on
|
|
24
|
+
# the two shapes.
|
|
25
|
+
extend Hecks::IR
|
|
26
|
+
extend Behaviour::ValueObject
|
|
27
|
+
|
|
28
|
+
emits_ir(
|
|
29
|
+
name: :hecks_name,
|
|
30
|
+
attributes: many(:attributes),
|
|
31
|
+
invariants: -> { invariants.map { |rule| { description: rule.description, canonical: rule.canonical } } },
|
|
32
|
+
closed_set: :closed_set?,
|
|
33
|
+
# THE FIELD NAME IS STRINGIFIED, NEVER THE VALUE. A `member` row can
|
|
34
|
+
# hold any of the scalar types an attribute declares — `Integer 84`
|
|
35
|
+
# (`StatementFrequency#retention_months`, statements.bluebook), not
|
|
36
|
+
# only `String` — and `value.to_s` used to erase that on the way
|
|
37
|
+
# out, so `84` and `"84"` (a member some other row might
|
|
38
|
+
# legitimately spell as text) became indistinguishable once they
|
|
39
|
+
# reached `to_h`. The declared name still moves (`field.to_s`) —
|
|
40
|
+
# that half was never a Ruby object with a type to lose.
|
|
41
|
+
members: -> { members.map { |member| member.map { |field, value| [field.to_s, value] } } }
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
class << self
|
|
45
|
+
attr_reader :attributes, :invariants, :members
|
|
46
|
+
|
|
47
|
+
# One declared shape — a subclass rather than an instance, so the thing
|
|
48
|
+
# the bluebook declares and the thing Ruby holds are one object.
|
|
49
|
+
def declare(name:, attributes: [], invariants: [], members: [], closed_set: !members.empty?)
|
|
50
|
+
shape = Class.new(self)
|
|
51
|
+
shape.hecks_name = name.to_s
|
|
52
|
+
shape.absorb(attributes: attributes, invariants: invariants,
|
|
53
|
+
members: members, closed_set: closed_set)
|
|
54
|
+
shape
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def absorb(attributes:, invariants:, members:, closed_set:)
|
|
58
|
+
@attributes = attributes
|
|
59
|
+
@invariants = invariants
|
|
60
|
+
@members = members
|
|
61
|
+
@closed_set = closed_set
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Hecks::Bluebook
|
|
2
|
+
#
|
|
3
|
+
# Everything a .bluebook file becomes on its way to running: the expression
|
|
4
|
+
# language (expression/), the model itself (the chapter class plus
|
|
5
|
+
# everything it declares), the assembly that turns
|
|
6
|
+
# declarations back into that graph (assembly.rb + assembly/), the authoring
|
|
7
|
+
# DSL (dsl/), and the meta-validator that judges a chapter against the
|
|
8
|
+
# language's own grammar (meta_validator.rb + meta_validator/).
|
|
9
|
+
#
|
|
10
|
+
# The require order below preserves the boot order the flat list in
|
|
11
|
+
# lib/hecks.rb used to spell: expression and IR first (pure
|
|
12
|
+
# declarations), assembly's collaborators before its face, the DSL before
|
|
13
|
+
# the meta-validator that its builders call at build time.
|
|
14
|
+
|
|
15
|
+
module Hecks
|
|
16
|
+
# Declared as a CLASS, not a module — `Hecks::Bluebook` IS a
|
|
17
|
+
# chapter (bluebook/chapter.rb carries its body). Everything a chapter
|
|
18
|
+
# declares nests under it, as do the ways to build one (`DSL`) and to
|
|
19
|
+
# judge one (`MetaValidator`). Reopening this anywhere must say `class`.
|
|
20
|
+
module Bluebook
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# What the chapter's own files lean on at class-body level (`extend
|
|
25
|
+
# Construct`, the assembly's QuerySpecification marks) — required here
|
|
26
|
+
# because those files' contents are frozen and cannot say so themselves.
|
|
27
|
+
require_relative "construct"
|
|
28
|
+
require_relative "literal"
|
|
29
|
+
require_relative "query_specification"
|
|
30
|
+
|
|
31
|
+
require_relative "bluebook/expression"
|
|
32
|
+
# THE MODEL ITSELF — the chapter class's own body first, then everything
|
|
33
|
+
# a chapter declares. Order matters only for reading: each is a bag of
|
|
34
|
+
# declarations with no load-time cross-references.
|
|
35
|
+
require_relative "bluebook/chapter"
|
|
36
|
+
require_relative "bluebook/reference"
|
|
37
|
+
require_relative "bluebook/attribute"
|
|
38
|
+
require_relative "bluebook/value_object"
|
|
39
|
+
require_relative "bluebook/command"
|
|
40
|
+
require_relative "bluebook/lifecycle"
|
|
41
|
+
require_relative "bluebook/query"
|
|
42
|
+
require_relative "bluebook/read_model"
|
|
43
|
+
require_relative "bluebook/entity"
|
|
44
|
+
require_relative "bluebook/domain_port"
|
|
45
|
+
require_relative "bluebook/policy"
|
|
46
|
+
require_relative "bluebook/process_manager"
|
|
47
|
+
require_relative "bluebook/aggregate"
|
|
48
|
+
require_relative "bluebook/hexagon"
|
|
49
|
+
require_relative "bluebook/translation"
|
|
50
|
+
|
|
51
|
+
require_relative "bluebook/assembly/contract"
|
|
52
|
+
require_relative "bluebook/assembly/contracts"
|
|
53
|
+
require_relative "bluebook/assembly/specializer"
|
|
54
|
+
require_relative "bluebook/assembly/build"
|
|
55
|
+
require_relative "bluebook/assembly/marks"
|
|
56
|
+
require_relative "bluebook/assembly/aggregate_assembly"
|
|
57
|
+
require_relative "bluebook/assembly"
|
|
58
|
+
|
|
59
|
+
require_relative "bluebook/project_loader"
|
|
60
|
+
|
|
61
|
+
require_relative "bluebook/dsl"
|
|
62
|
+
require_relative "bluebook/pattern_subset"
|
|
63
|
+
|
|
64
|
+
require_relative "bluebook/meta_validator"
|
|
65
|
+
require_relative "bluebook/meta_validator/plan"
|
|
66
|
+
require_relative "bluebook/meta_validator/readings"
|
|
67
|
+
require_relative "bluebook/meta_validator/judge"
|
|
68
|
+
require_relative "bluebook/meta_validator/shapes"
|
|
69
|
+
require_relative "bluebook/meta_validator/reconstruction"
|
|
70
|
+
require_relative "bluebook/meta_validator/world_judge"
|
|
71
|
+
require_relative "bluebook/meta_validator/port_judge"
|
|
72
|
+
require_relative "bluebook/meta_validator/adapter_judge"
|
|
73
|
+
require_relative "bluebook/meta_validator/translation_judge"
|
|
74
|
+
require_relative "bluebook/meta_validator/syntax_boot"
|