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,218 @@
|
|
|
1
|
+
# GENERATED — projected from the language's own Vocabulary aggregate
|
|
2
|
+
# (lib/hecks/language/bluebook/vocabulary.bluebook).
|
|
3
|
+
#
|
|
4
|
+
# DO NOT EDIT. spec/vocabulary_table_spec.rb re-projects this in memory
|
|
5
|
+
# and refuses a diff, so an edit here fails the ordinary suite.
|
|
6
|
+
#
|
|
7
|
+
# Plain data on purpose — no requires, no dependency on the model —
|
|
8
|
+
# because several of these sets are read while a bluebook is still
|
|
9
|
+
# being parsed. A table that needed the framework to load could not
|
|
10
|
+
# be the table the framework loads with.
|
|
11
|
+
|
|
12
|
+
module Hecks
|
|
13
|
+
module Vocabulary
|
|
14
|
+
TABLES = {
|
|
15
|
+
"AggregateDispatchOrder" => [
|
|
16
|
+
{"step"=>"refuse_unknown_arguments"}.freeze,
|
|
17
|
+
{"step"=>"refuse_absent_arguments"}.freeze,
|
|
18
|
+
{"step"=>"normalize_args"}.freeze,
|
|
19
|
+
{"step"=>"refuse_role_mismatch"}.freeze,
|
|
20
|
+
{"step"=>"resolve_references"}.freeze,
|
|
21
|
+
{"step"=>"hydrate"}.freeze,
|
|
22
|
+
{"step"=>"enforce_givens"}.freeze,
|
|
23
|
+
{"step"=>"admissible_transition"}.freeze,
|
|
24
|
+
{"step"=>"assign_creation_attributes"}.freeze,
|
|
25
|
+
{"step"=>"apply_mutations"}.freeze,
|
|
26
|
+
{"step"=>"advance_lifecycle"}.freeze,
|
|
27
|
+
{"step"=>"delegate_to_entity"}.freeze,
|
|
28
|
+
{"step"=>"enforce_ensures"}.freeze,
|
|
29
|
+
{"step"=>"enforce_invariants"}.freeze,
|
|
30
|
+
{"step"=>"save"}.freeze,
|
|
31
|
+
{"step"=>"emit"}.freeze
|
|
32
|
+
].freeze,
|
|
33
|
+
"Comparison" => [
|
|
34
|
+
{"symbol"=>">=", "compares_less_than"=>"true", "compares_equal"=>"false", "negated"=>"true"}.freeze,
|
|
35
|
+
{"symbol"=>"<=", "compares_less_than"=>"true", "compares_equal"=>"true", "negated"=>"false"}.freeze,
|
|
36
|
+
{"symbol"=>"<", "compares_less_than"=>"true", "compares_equal"=>"false", "negated"=>"false"}.freeze,
|
|
37
|
+
{"symbol"=>">", "compares_less_than"=>"true", "compares_equal"=>"true", "negated"=>"true"}.freeze,
|
|
38
|
+
{"symbol"=>"==", "compares_less_than"=>"false", "compares_equal"=>"true", "negated"=>"false"}.freeze,
|
|
39
|
+
{"symbol"=>"!=", "compares_less_than"=>"false", "compares_equal"=>"true", "negated"=>"true"}.freeze
|
|
40
|
+
].freeze,
|
|
41
|
+
"DomainRefusal" => [
|
|
42
|
+
{"name"=>"AbsentArgument"}.freeze,
|
|
43
|
+
{"name"=>"AlreadyExists"}.freeze,
|
|
44
|
+
{"name"=>"AttributeAbsent"}.freeze,
|
|
45
|
+
{"name"=>"EnsuresNotMet"}.freeze,
|
|
46
|
+
{"name"=>"GivenNotMet"}.freeze,
|
|
47
|
+
{"name"=>"InvariantViolation"}.freeze,
|
|
48
|
+
{"name"=>"LifecycleRefused"}.freeze,
|
|
49
|
+
{"name"=>"NothingToCorrect"}.freeze,
|
|
50
|
+
{"name"=>"NotFound"}.freeze,
|
|
51
|
+
{"name"=>"ProjectionAbsent"}.freeze,
|
|
52
|
+
{"name"=>"RemoteRefusal"}.freeze,
|
|
53
|
+
{"name"=>"TypeMismatch"}.freeze,
|
|
54
|
+
{"name"=>"Unauthorized"}.freeze,
|
|
55
|
+
{"name"=>"UnknownArgument"}.freeze,
|
|
56
|
+
{"name"=>"UnknownVerb"}.freeze
|
|
57
|
+
].freeze,
|
|
58
|
+
"EntityDispatchOrder" => [
|
|
59
|
+
{"step"=>"refuse_unknown_arguments"}.freeze,
|
|
60
|
+
{"step"=>"refuse_absent_arguments"}.freeze,
|
|
61
|
+
{"step"=>"normalize_args"}.freeze,
|
|
62
|
+
{"step"=>"refuse_role_mismatch"}.freeze,
|
|
63
|
+
{"step"=>"resolve_references"}.freeze,
|
|
64
|
+
{"step"=>"hydrate_parent"}.freeze,
|
|
65
|
+
{"step"=>"locate_element"}.freeze,
|
|
66
|
+
{"step"=>"enforce_givens"}.freeze,
|
|
67
|
+
{"step"=>"admissible_transition"}.freeze,
|
|
68
|
+
{"step"=>"apply_mutations"}.freeze,
|
|
69
|
+
{"step"=>"advance_lifecycle"}.freeze,
|
|
70
|
+
{"step"=>"enforce_ensures"}.freeze,
|
|
71
|
+
{"step"=>"enforce_invariants"}.freeze,
|
|
72
|
+
{"step"=>"save"}.freeze,
|
|
73
|
+
{"step"=>"emit"}.freeze
|
|
74
|
+
].freeze,
|
|
75
|
+
"FieldHint" => [
|
|
76
|
+
{"name"=>"email", "pattern"=>"email", "resolves_to"=>"html_type"}.freeze,
|
|
77
|
+
{"name"=>"url", "pattern"=>"\\b(url|uri|website|link)\\b", "resolves_to"=>"html_type"}.freeze,
|
|
78
|
+
{"name"=>"tel", "pattern"=>"phone|\\btel(ephone)?\\b", "resolves_to"=>"html_type"}.freeze,
|
|
79
|
+
{"name"=>"textarea", "pattern"=>"\\b(text|body|note|notes|description|message|comment)\\b", "resolves_to"=>"kind"}.freeze
|
|
80
|
+
].freeze,
|
|
81
|
+
"IncludeHaystack" => [
|
|
82
|
+
{"type"=>"Array", "strategy"=>"membership"}.freeze,
|
|
83
|
+
{"type"=>"String", "strategy"=>"substring"}.freeze
|
|
84
|
+
].freeze,
|
|
85
|
+
"LoadOrder" => [
|
|
86
|
+
{"glob"=>"*.port"}.freeze,
|
|
87
|
+
{"glob"=>"*.adapter"}.freeze,
|
|
88
|
+
{"glob"=>"*.bluebook"}.freeze,
|
|
89
|
+
{"glob"=>"translations/*.bluebook"}.freeze,
|
|
90
|
+
{"glob"=>"*.hecksagon"}.freeze,
|
|
91
|
+
{"glob"=>"*.world"}.freeze
|
|
92
|
+
].freeze,
|
|
93
|
+
"MutationOp" => [
|
|
94
|
+
{"name"=>"set", "sign"=>""}.freeze,
|
|
95
|
+
{"name"=>"append", "sign"=>""}.freeze,
|
|
96
|
+
{"name"=>"increment", "sign"=>"1"}.freeze,
|
|
97
|
+
{"name"=>"decrement", "sign"=>"-1"}.freeze,
|
|
98
|
+
{"name"=>"multiply", "sign"=>""}.freeze,
|
|
99
|
+
{"name"=>"clamp", "sign"=>""}.freeze,
|
|
100
|
+
{"name"=>"remove", "sign"=>""}.freeze,
|
|
101
|
+
{"name"=>"delegate", "sign"=>""}.freeze,
|
|
102
|
+
{"name"=>"corrects", "sign"=>""}.freeze
|
|
103
|
+
].freeze,
|
|
104
|
+
"NormalisationStrategy" => [
|
|
105
|
+
{"name"=>"collapse_whitespace"}.freeze,
|
|
106
|
+
{"name"=>"replace"}.freeze
|
|
107
|
+
].freeze,
|
|
108
|
+
"Primitive" => [
|
|
109
|
+
{"name"=>"String"}.freeze,
|
|
110
|
+
{"name"=>"Integer"}.freeze,
|
|
111
|
+
{"name"=>"Float"}.freeze,
|
|
112
|
+
{"name"=>"TrueClass"}.freeze,
|
|
113
|
+
{"name"=>"FalseClass"}.freeze
|
|
114
|
+
].freeze,
|
|
115
|
+
"QueryComparator" => [
|
|
116
|
+
{"name"=>"eq"}.freeze,
|
|
117
|
+
{"name"=>"ne"}.freeze,
|
|
118
|
+
{"name"=>"gt"}.freeze,
|
|
119
|
+
{"name"=>"gte"}.freeze,
|
|
120
|
+
{"name"=>"lt"}.freeze,
|
|
121
|
+
{"name"=>"lte"}.freeze,
|
|
122
|
+
{"name"=>"in"}.freeze,
|
|
123
|
+
{"name"=>"contains"}.freeze,
|
|
124
|
+
{"name"=>"none_in_state"}.freeze
|
|
125
|
+
].freeze,
|
|
126
|
+
"RefusalTemplate" => [
|
|
127
|
+
{"refusal"=>"NotFound", "site"=>"creating_no_identity", "template"=>"{command} creates a {aggregate} — pass {identity}:"}.freeze,
|
|
128
|
+
{"refusal"=>"AlreadyExists", "site"=>"creating_duplicate", "template"=>"{command} creates a {aggregate} that already exists — {identity} {offered}"}.freeze,
|
|
129
|
+
{"refusal"=>"AlreadyExists", "site"=>"entity_duplicate", "template"=>"a {entity} already exists on {aggregate} — {identity} {offered}"}.freeze,
|
|
130
|
+
{"refusal"=>"NotFound", "site"=>"acting_no_identity", "template"=>"{command} acts on an existing {aggregate} — pass {identity}:"}.freeze,
|
|
131
|
+
{"refusal"=>"NotFound", "site"=>"record_missing", "template"=>"no {aggregate} with {identity} {offered}"}.freeze,
|
|
132
|
+
{"refusal"=>"NotFound", "site"=>"entity_parent_no_identity", "template"=>"{command} acts on a {aggregate}'s {entity} — pass {identity}:"}.freeze,
|
|
133
|
+
{"refusal"=>"UnknownVerb", "site"=>"entity_unknown", "template"=>"{aggregate} has no entity {entity}"}.freeze,
|
|
134
|
+
{"refusal"=>"NotFound", "site"=>"entity_element_no_identity", "template"=>"{command} acts on one {entity} — pass {identity}:"}.freeze,
|
|
135
|
+
{"refusal"=>"NotFound", "site"=>"entity_element_missing", "template"=>"no {entity} with {identity} {wants} on {aggregate} {parent_id}"}.freeze,
|
|
136
|
+
{"refusal"=>"NotFound", "site"=>"reference_target_missing", "template"=>"no {target} with {heads} {key}"}.freeze,
|
|
137
|
+
{"refusal"=>"NotFound", "site"=>"read_model_reference_missing", "template"=>"no {aggregate} with reference {offered}"}.freeze,
|
|
138
|
+
{"refusal"=>"TypeMismatch", "site"=>"read_model_object_reference", "template"=>"{query} refused — a reference is an id, and {field} arrived as an object"}.freeze,
|
|
139
|
+
{"refusal"=>"UnknownVerb", "site"=>"no_query", "template"=>"{aggregate} has no query {query}"}.freeze,
|
|
140
|
+
{"refusal"=>"UnknownVerb", "site"=>"entity_query_missing", "template"=>"{entity} has no query {query}"}.freeze,
|
|
141
|
+
{"refusal"=>"UnknownVerb", "site"=>"entity_holds_no_list", "template"=>"{aggregate} holds no list of {entity}"}.freeze,
|
|
142
|
+
{"refusal"=>"UnknownVerb", "site"=>"entity_no_command", "template"=>"{entity} has no command {command}"}.freeze,
|
|
143
|
+
{"refusal"=>"UnknownVerb", "site"=>"aggregate_no_command", "template"=>"{aggregate} has no command {command}"}.freeze,
|
|
144
|
+
{"refusal"=>"UnknownVerb", "site"=>"port_no_operation", "template"=>"{port} has no operation {operation}"}.freeze,
|
|
145
|
+
{"refusal"=>"UnknownVerb", "site"=>"no_domain", "template"=>"no domain {domain} loaded (verb {verb})"}.freeze,
|
|
146
|
+
{"refusal"=>"UnknownVerb", "site"=>"no_read_model", "template"=>"{domain} has no read model {query}"}.freeze,
|
|
147
|
+
{"refusal"=>"UnknownVerb", "site"=>"not_fully_qualified", "template"=>"{verb} is not a fully-qualified verb (Domain::Aggregate.Command)"}.freeze,
|
|
148
|
+
{"refusal"=>"UnknownVerb", "site"=>"no_aggregate", "template"=>"{domain} has no aggregate {aggregate}"}.freeze,
|
|
149
|
+
{"refusal"=>"LifecycleRefused", "site"=>"transition_blocked", "template"=>"{command} refused — {field} is {current}, and {command} moves it only from {allowed}"}.freeze,
|
|
150
|
+
{"refusal"=>"TypeMismatch", "site"=>"value_object_shape", "template"=>"{name} is a {type} — pass its fields as an object, not {offered}"}.freeze,
|
|
151
|
+
{"refusal"=>"TypeMismatch", "site"=>"reference_as_object", "template"=>"{command} refused — a reference is an id, and {attribute} arrived as an object{known_by}"}.freeze,
|
|
152
|
+
{"refusal"=>"TypeMismatch", "site"=>"multi_field_scalar", "template"=>"{type} has multiple fields and cannot stand in for a scalar"}.freeze,
|
|
153
|
+
{"refusal"=>"TypeMismatch", "site"=>"composite_identity", "template"=>"{type} is a composite identity — an identity must have exactly one field"}.freeze,
|
|
154
|
+
{"refusal"=>"TypeMismatch", "site"=>"numeric_field", "template"=>"{type}.{field} expects {expected}, got {offered}"}.freeze,
|
|
155
|
+
{"refusal"=>"TypeMismatch", "site"=>"non_finite_field", "template"=>"{type}.{field} must be a finite number, got {offered}"}.freeze,
|
|
156
|
+
{"refusal"=>"TypeMismatch", "site"=>"pattern_mismatch", "template"=>"{type}.{field} must match {pattern}, got {offered}"}.freeze,
|
|
157
|
+
{"refusal"=>"TypeMismatch", "site"=>"arithmetic_amount", "template"=>"{op} of {target} needs an Integer, got {offered}"}.freeze,
|
|
158
|
+
{"refusal"=>"TypeMismatch", "site"=>"arithmetic_current", "template"=>"{op} of {target} needs an Integer {target}, got {offered}"}.freeze,
|
|
159
|
+
{"refusal"=>"TypeMismatch", "site"=>"arithmetic_shared_field", "template"=>"{op} of {target} needs a value object with one shared Integer field"}.freeze,
|
|
160
|
+
{"refusal"=>"UnknownArgument", "site"=>"unknown_args", "template"=>"{command} does not declare {unknown} — it takes {declared}"}.freeze,
|
|
161
|
+
{"refusal"=>"AbsentArgument", "site"=>"absent_args", "template"=>"{command} was not given {absent} — it takes {declared}"}.freeze,
|
|
162
|
+
{"refusal"=>"InvariantViolation", "site"=>"closed_set_member", "template"=>"{type} admits {admitted} — got {offered}"}.freeze,
|
|
163
|
+
{"refusal"=>"InvariantViolation", "site"=>"value_object_invariant", "template"=>"{name} invariant violated — {description} (given {offered})"}.freeze,
|
|
164
|
+
{"refusal"=>"InvariantViolation", "site"=>"admits_declared_set", "template"=>"{name} admits {admits} — {admitted} — got {offered}"}.freeze,
|
|
165
|
+
{"refusal"=>"InvariantViolation", "site"=>"undeclared_set", "template"=>"{name} admits {admits}, which this chapter does not declare — a closed set is named Aggregate::SetName, and it must be one the bluebook actually holds"}.freeze,
|
|
166
|
+
{"refusal"=>"Unauthorized", "site"=>"tenant_required", "template"=>"{query} declares authorize with tenant: {field} — pass {field}: to name which {field} this ask is scoped to"}.freeze,
|
|
167
|
+
{"refusal"=>"Unauthorized", "site"=>"role_mismatch", "template"=>"{command} refused — role: {role}, and the caller stated {caller_role}"}.freeze,
|
|
168
|
+
{"refusal"=>"AttributeAbsent", "site"=>"absent_read", "template"=>"{aggregate} {field} is absent on this record — declared, not optional, and added since it was written. Backfill it in a translation (backfill :{field}, default: ...), or declare it optional: true"}.freeze,
|
|
169
|
+
{"refusal"=>"ProjectionAbsent", "site"=>"absent_read", "template"=>"{aggregate} {field} is not yet projected on this record — declared via projects :{field}, but no rebuild sweep has populated it. Run the sweep, or read {reference}.{remote_field} directly if this rule cannot wait"}.freeze
|
|
170
|
+
].freeze,
|
|
171
|
+
"SignTest" => [
|
|
172
|
+
{"name"=>"positive?", "compares_via"=>">"}.freeze,
|
|
173
|
+
{"name"=>"negative?", "compares_via"=>"<"}.freeze,
|
|
174
|
+
{"name"=>"zero?", "compares_via"=>"=="}.freeze
|
|
175
|
+
].freeze,
|
|
176
|
+
"SizedType" => [
|
|
177
|
+
{"type"=>"Array"}.freeze,
|
|
178
|
+
{"type"=>"String"}.freeze,
|
|
179
|
+
{"type"=>"Hash"}.freeze
|
|
180
|
+
].freeze,
|
|
181
|
+
"ToStringType" => [
|
|
182
|
+
{"type"=>"String"}.freeze,
|
|
183
|
+
{"type"=>"Integer"}.freeze,
|
|
184
|
+
{"type"=>"Float"}.freeze,
|
|
185
|
+
{"type"=>"TrueClass"}.freeze,
|
|
186
|
+
{"type"=>"FalseClass"}.freeze,
|
|
187
|
+
{"type"=>"NilClass"}.freeze
|
|
188
|
+
].freeze,
|
|
189
|
+
"Trigger" => [
|
|
190
|
+
{"name"=>"refused"}.freeze
|
|
191
|
+
].freeze,
|
|
192
|
+
"VocabularyName" => [
|
|
193
|
+
|
|
194
|
+
].freeze
|
|
195
|
+
}.freeze
|
|
196
|
+
|
|
197
|
+
# THE TERMS — the first field of each row, which for a
|
|
198
|
+
# one-field vocabulary is the whole of it. Derived ONCE and
|
|
199
|
+
# frozen rather than mapped per call: these are constant
|
|
200
|
+
# tables, and a constant that allocates a new array every
|
|
201
|
+
# time it is read is not one.
|
|
202
|
+
TERMS = TABLES.transform_values { |rows| rows.map { |row| row.values.first }.freeze }.freeze
|
|
203
|
+
|
|
204
|
+
module_function
|
|
205
|
+
|
|
206
|
+
# Refuses an unknown name rather than answering nil: a set
|
|
207
|
+
# the language does not declare is a typo, not an empty set.
|
|
208
|
+
def fetch(name) = TERMS.fetch(name)
|
|
209
|
+
|
|
210
|
+
# The rows whole, for the vocabularies that carry more than
|
|
211
|
+
# a term — Comparison's own algebra, RefusalTemplate's text.
|
|
212
|
+
def rows(name) = TABLES.fetch(name)
|
|
213
|
+
|
|
214
|
+
def symbols(name) = fetch(name).map(&:to_sym)
|
|
215
|
+
|
|
216
|
+
def names = TABLES.keys
|
|
217
|
+
end
|
|
218
|
+
end
|
data/lib/hecks.rb
CHANGED
|
@@ -1,6 +1,123 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
require_relative
|
|
6
|
-
require_relative
|
|
1
|
+
require_relative "hecks/version"
|
|
2
|
+
# The closed sets the runtime computes with, generated from
|
|
3
|
+
# vocabulary.bluebook. Plain data, required first, because some of
|
|
4
|
+
# them are read while a bluebook is still being parsed.
|
|
5
|
+
require_relative "hecks/vocabulary"
|
|
6
|
+
require_relative "hecks/rendering"
|
|
7
|
+
require_relative "hecks/naming"
|
|
8
|
+
require_relative "hecks/fqn"
|
|
9
|
+
require_relative "hecks/freezer"
|
|
10
|
+
require_relative "hecks/construct"
|
|
11
|
+
# Before `bluebook` — every construct under `Bluebook` includes or
|
|
12
|
+
# extends this to declare what it emits.
|
|
13
|
+
require_relative "hecks/ir"
|
|
14
|
+
require_relative "hecks/literal"
|
|
15
|
+
require_relative "hecks/facade"
|
|
16
|
+
require_relative "hecks/query_specification"
|
|
17
|
+
|
|
18
|
+
require_relative "hecks/ports"
|
|
19
|
+
require_relative "hecks/bluebook"
|
|
20
|
+
require_relative "hecks/router"
|
|
21
|
+
|
|
22
|
+
require_relative "hecks/runtime"
|
|
23
|
+
require_relative "hecks/adapters"
|
|
24
|
+
require_relative "hecks/projector"
|
|
25
|
+
# AFTER the projector registry and its `Target` mixin are both real —
|
|
26
|
+
# every target registers itself as it loads, so this require IS the
|
|
27
|
+
# installation of them.
|
|
28
|
+
require_relative "hecks/projections"
|
|
29
|
+
# AFTER `Projector` (dispatches against the `:cli` projection) and
|
|
30
|
+
# `Ports::Clock` (fills a staleness rule's `now` at the door) both exist.
|
|
31
|
+
require_relative "hecks/facade/cli_door"
|
|
32
|
+
require_relative "hecks/facade/cli_runner"
|
|
33
|
+
require_relative "hecks/storehouse"
|
|
34
|
+
require_relative "hecks/framework"
|
|
35
|
+
require_relative "hecks/embryonaut_bluebook"
|
|
36
|
+
|
|
37
|
+
module Hecks
|
|
38
|
+
class LoadOutsideBoot < StandardError; end
|
|
39
|
+
|
|
40
|
+
class << self
|
|
41
|
+
attr_reader :current_registry
|
|
42
|
+
|
|
43
|
+
# The loading words below collect into the registry the RUNTIME is
|
|
44
|
+
# holding open ; booting and that ambient state belong to the runtime
|
|
45
|
+
# layer, so this module is their facade and Hecks::Runtime is where
|
|
46
|
+
# they live.
|
|
47
|
+
# `install_facade:` — see Runtime::Loader.boot. Defaults on; a caller
|
|
48
|
+
# that only dispatches by FQN string can skip the global sugar.
|
|
49
|
+
#
|
|
50
|
+
# `environment:` — RECOVERED, not new: this parameter (and the
|
|
51
|
+
# `environments/<name>.hecksagon` / `.world` overlay it loads —
|
|
52
|
+
# see Adapters::Folder#load_domain) existed on a prior commit of
|
|
53
|
+
# this repo (933d1dd), was vendored out to a real consumer
|
|
54
|
+
# (lifeadelics/domain), and was then lost from this repo's own
|
|
55
|
+
# history (no branch here reaches that commit). Ported forward
|
|
56
|
+
# from the consumer's vendor snapshot — the only surviving copy —
|
|
57
|
+
# and generalized: the original only loaded a `.hecksagon`
|
|
58
|
+
# overlay; this also loads a same-named `.world` overlay, both
|
|
59
|
+
# merged into the base rather than replacing it (Registry#add_hecksagon
|
|
60
|
+
# / #add_world). hecks never reads ENV itself — a caller
|
|
61
|
+
# resolves its own env var name and passes the resulting string
|
|
62
|
+
# straight through, e.g. `Hecks.boot(path, environment:
|
|
63
|
+
# ENV.fetch("MYAPP_ENV", "development"))`.
|
|
64
|
+
def boot(path, shared: nil, install_facade: true, environment: nil)
|
|
65
|
+
Runtime.boot(path, shared: shared, install_facade: install_facade, environment: environment)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# `paths` — an explicit list of files to boot (a `.bluebook`, its
|
|
69
|
+
# `.hecksagon`, optionally a `.world`), loaded in place from wherever
|
|
70
|
+
# they actually live — see Runtime::Loader.boot_files's own header for
|
|
71
|
+
# why this exists beside `boot` rather than as a special case of it.
|
|
72
|
+
def boot_files(paths, shared: nil, install_facade: true, environment: nil)
|
|
73
|
+
Runtime.boot_files(paths, shared: shared, install_facade: install_facade, environment: environment)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def with_registry(registry, &block) = Runtime.with_registry(registry, &block)
|
|
77
|
+
|
|
78
|
+
def current_registry = Runtime.current_registry
|
|
79
|
+
|
|
80
|
+
# Bind who is dispatching for the duration of the block — checked
|
|
81
|
+
# against a command's declared `role`, if it has one. Unbound (the
|
|
82
|
+
# default), a command's role stays exactly what it is without this:
|
|
83
|
+
# decoration.
|
|
84
|
+
#
|
|
85
|
+
# `actor_id` is OPTIONAL — a caller naming only a role is checked by
|
|
86
|
+
# string equality against the command's own `role`, exactly as
|
|
87
|
+
# before. A caller that also names WHO it is lets the check run
|
|
88
|
+
# against a real Governance `RoleAssignment` instead, once the
|
|
89
|
+
# command's domain has Governance attached — see
|
|
90
|
+
# `CommandRules::Authorization`'s own header.
|
|
91
|
+
#
|
|
92
|
+
# `as_of` and `scope` are OPTIONAL too, same shape — see
|
|
93
|
+
# `Runtime.as_caller`'s own header for what each does.
|
|
94
|
+
def as_caller(role:, actor_id: nil, as_of: nil, scope: nil, &block)
|
|
95
|
+
Runtime.as_caller(role: role, actor_id: actor_id, as_of: as_of, scope: scope, &block)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def bluebook(name, version: nil, &block)
|
|
99
|
+
collect(:add_bluebook, Bluebook::DSL::BluebookBuilder.build(name, version: version, &block))
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def hecksagon(name, &block) = collect(:add_hecksagon, Bluebook::DSL::HecksagonBuilder.build(name, &block))
|
|
103
|
+
def port(name, &block) = collect(:add_port, Bluebook::DSL::PortBuilder.build(name, &block))
|
|
104
|
+
def adapter(name, &block) = collect(:add_adapter, Bluebook::DSL::AdapterBuilder.build(name, &block))
|
|
105
|
+
def world(name, &block) = collect(:add_world, Bluebook::DSL::WorldBuilder.build(name, &block))
|
|
106
|
+
|
|
107
|
+
def data_translation(name, from:, to:, &block)
|
|
108
|
+
collect(:add_translation, Bluebook::DSL::TranslationBuilder.build(name, from: from, to: to, &block))
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
private
|
|
112
|
+
|
|
113
|
+
def collect(method, item)
|
|
114
|
+
unless Runtime.current_registry
|
|
115
|
+
raise LoadOutsideBoot,
|
|
116
|
+
"declaration loaded outside a boot — use Hecks.boot(path) rather than requiring the file directly"
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
Runtime.current_registry.public_send(method, item)
|
|
120
|
+
item
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
module RuboCop
|
|
2
|
+
module Cop
|
|
3
|
+
module Hecks
|
|
4
|
+
# FLAGS THE EXACT SHAPE behind 8+ real bugs already fixed one at a
|
|
5
|
+
# time across this codebase (Tiers 1-5): `holder[a] || holder[b]` —
|
|
6
|
+
# the SAME receiver looked up by two different keys, falling back to
|
|
7
|
+
# the second lookup whenever the first is falsy. `||` cannot tell a
|
|
8
|
+
# genuinely STORED `false` from a MISSING key — both are falsy in
|
|
9
|
+
# Ruby — so a real `false` sitting at `holder[a]` is silently
|
|
10
|
+
# discarded and `holder[b]` (usually absent, so `nil`) is returned
|
|
11
|
+
# instead. Every one of those 8+ instances was the identical
|
|
12
|
+
# AST shape with a different pair of keys (most commonly
|
|
13
|
+
# `h[k.to_sym] || h[k]`, reading a value that could arrive keyed
|
|
14
|
+
# either by symbol or by string off the wire).
|
|
15
|
+
#
|
|
16
|
+
# THE FIX THIS CODEBASE ALREADY CONVERGED ON — see
|
|
17
|
+
# `lib/hecks/query_specification/field_path.rb#read`, the shared
|
|
18
|
+
# digger this whole bug class got consolidated behind: check
|
|
19
|
+
# `key?` FIRST, never fall back through `||`.
|
|
20
|
+
#
|
|
21
|
+
# sym = segment.to_sym
|
|
22
|
+
# return current.key?(sym) ? current[sym] : current[segment]
|
|
23
|
+
#
|
|
24
|
+
# That method's own comment says it plainly: "`key?` first, never
|
|
25
|
+
# `||`, because `||` falls through a genuinely-stored `false` to
|
|
26
|
+
# the OTHER spelling (usually absent) and returns `nil` instead."
|
|
27
|
+
# This cop exists so the NEXT `holder[a] || holder[b]` gets caught
|
|
28
|
+
# mechanically, before it becomes bug #9, rather than found by
|
|
29
|
+
# hand again in a future audit.
|
|
30
|
+
#
|
|
31
|
+
# SCOPED TO THE `[]`/`[]` SHAPE ONLY, deliberately — a receiver
|
|
32
|
+
# method-call is compared by AST structure (`==`, which ignores
|
|
33
|
+
# source location), so `hash[a] || hash[b]` is flagged whether
|
|
34
|
+
# `hash` is a local variable, a method call, or a constant, but
|
|
35
|
+
# `a[k] || b[k]` (DIFFERENT receivers) and `value || default`
|
|
36
|
+
# (an ordinary default, not a second lookup at all) are both left
|
|
37
|
+
# alone — neither one can silently drop a stored `false` the way
|
|
38
|
+
# a same-receiver double-lookup can.
|
|
39
|
+
#
|
|
40
|
+
# @example
|
|
41
|
+
# # bad — a stored `false` at hash[:active] is discarded
|
|
42
|
+
# hash[:active] || hash["active"]
|
|
43
|
+
#
|
|
44
|
+
# # good
|
|
45
|
+
# hash.key?(:active) ? hash[:active] : hash["active"]
|
|
46
|
+
#
|
|
47
|
+
# # good — or the shared digger this codebase already has
|
|
48
|
+
# Hecks::QuerySpecification::FieldPath.dig(hash, "active")
|
|
49
|
+
class FallbackHashLookup < Base
|
|
50
|
+
MSG = "`%<receiver>s[...] || %<receiver>s[...]` falls back to the second lookup " \
|
|
51
|
+
"whenever the first is falsy — but `||` cannot tell a genuinely stored `false` " \
|
|
52
|
+
"apart from a missing key, so a real `false` at `%<receiver>s[%<lhs_key>s]` is " \
|
|
53
|
+
"silently discarded in favor of `%<receiver>s[%<rhs_key>s]` instead of being " \
|
|
54
|
+
"returned. Use `%<receiver>s.key?(%<lhs_key>s) ? %<receiver>s[%<lhs_key>s] : " \
|
|
55
|
+
"%<receiver>s[%<rhs_key>s]`, or a shared digger (see `key?` in " \
|
|
56
|
+
"`Hecks::QuerySpecification::FieldPath#read`), instead."
|
|
57
|
+
|
|
58
|
+
# @!method bracket_lookup(node)
|
|
59
|
+
def_node_matcher :bracket_lookup, "(send $_receiver :[] $_key)"
|
|
60
|
+
|
|
61
|
+
def on_or(node)
|
|
62
|
+
lhs_receiver, lhs_key = bracket_lookup(node.lhs)
|
|
63
|
+
return unless lhs_receiver
|
|
64
|
+
|
|
65
|
+
rhs_receiver, rhs_key = bracket_lookup(node.rhs)
|
|
66
|
+
return unless rhs_receiver
|
|
67
|
+
|
|
68
|
+
# THE STRUCTURAL EQUALITY CHECK — `==` on an AST node (from the
|
|
69
|
+
# `ast` gem `Node` this compiles down to) compares `type` and
|
|
70
|
+
# `children` recursively and ignores source location, so
|
|
71
|
+
# `hash[a] || hash[b]` matches even though the two `hash`
|
|
72
|
+
# sub-nodes are two distinct node OBJECTS parsed from two
|
|
73
|
+
# different source ranges. A different receiver on each side
|
|
74
|
+
# (`a[k] || b[k]`) fails this check and is correctly left alone.
|
|
75
|
+
return unless lhs_receiver == rhs_receiver
|
|
76
|
+
|
|
77
|
+
add_offense(
|
|
78
|
+
node,
|
|
79
|
+
message: format(
|
|
80
|
+
MSG,
|
|
81
|
+
receiver: lhs_receiver.source,
|
|
82
|
+
lhs_key: lhs_key.source,
|
|
83
|
+
rhs_key: rhs_key.source
|
|
84
|
+
)
|
|
85
|
+
)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
module RuboCop
|
|
2
|
+
module Cop
|
|
3
|
+
module Hecks
|
|
4
|
+
# FLAGS `hash[new] = hash.delete(old)` INSIDE A LOOP — a method that
|
|
5
|
+
# both READS and WRITES the same hash across a loop's iterations,
|
|
6
|
+
# in the specific rename/permutation shape this codebase has
|
|
7
|
+
# already lost real data to once.
|
|
8
|
+
#
|
|
9
|
+
# THE BUG THIS IS THE MECHANICAL FOLLOW-UP TO (M27,
|
|
10
|
+
# docs/audits/2026-08-10-main-bug-audit.md,
|
|
11
|
+
# docs/audits/2026-08-11-bug-triage.md; fixed in
|
|
12
|
+
# `Hecks::Ports::Persistence::Lineage#apply_renames`,
|
|
13
|
+
# lib/hecks/ports/persistence/plugins/era/lineage.rb): a rename
|
|
14
|
+
# rule set applied one rule at a time, `state[new_name] =
|
|
15
|
+
# state.delete(old_name)` per rule, against the SAME hash it was
|
|
16
|
+
# reading from — so a swap (`rename :a, to: :b` alongside `rename
|
|
17
|
+
# :b, to: :a`) on `{a: 1, b: 2}` collapsed to `{a: 1}`. The first
|
|
18
|
+
# rule wrote `b: 1` (clobbering the real `b: 2`) before the second
|
|
19
|
+
# rule ever got a chance to read the value that was supposed to
|
|
20
|
+
# move to `:a` — sequential edits stepping on each other, not the
|
|
21
|
+
# simultaneous permutation a rename set actually means. The same
|
|
22
|
+
# shape loses data identically for ANY chain longer than one link
|
|
23
|
+
# (`a->b->c->a`), not just a two-element swap.
|
|
24
|
+
#
|
|
25
|
+
# THE FIX THIS COP POINTS AT — snapshot every old key's value
|
|
26
|
+
# FIRST, delete all old keys, THEN write all new keys, so no
|
|
27
|
+
# rename in the pass ever reads a key this same pass has already
|
|
28
|
+
# written:
|
|
29
|
+
#
|
|
30
|
+
# snapshot = renames.filter_map { |old_name, new_name| [old_name, new_name, state[old_name]] if state.key?(old_name) }
|
|
31
|
+
# snapshot.each { |old_name, _new_name, _value| state.delete(old_name) }
|
|
32
|
+
# snapshot.each { |_old_name, new_name, value| state[new_name] = value }
|
|
33
|
+
#
|
|
34
|
+
# WHAT THIS COP DOES NOT ATTEMPT — the general checklist item is
|
|
35
|
+
# broader than any AST pattern can safely automate ("any method
|
|
36
|
+
# that both reads and writes the same collection across a loop"
|
|
37
|
+
# covers plenty of correct code too — accumulating into a result
|
|
38
|
+
# hash, memoizing into a cache). This cop stays narrow and
|
|
39
|
+
# precise: only the EXACT `recv[x] = recv.delete(y)` shape, same
|
|
40
|
+
# receiver both sides, inside something that iterates. A single
|
|
41
|
+
# rename outside any loop is not this bug (nothing else can have
|
|
42
|
+
# run first); `hash.store(...)` instead of `hash[...] =`, or
|
|
43
|
+
# `hash.delete(...)` whose result is not immediately written back
|
|
44
|
+
# into the SAME hash, are not this shape either and are left to
|
|
45
|
+
# the broader code-review checklist item, not this cop.
|
|
46
|
+
#
|
|
47
|
+
# @example
|
|
48
|
+
# # bad — one rule at a time against the hash it reads from
|
|
49
|
+
# renames.each do |old_name, new_name|
|
|
50
|
+
# state[new_name] = state.delete(old_name)
|
|
51
|
+
# end
|
|
52
|
+
#
|
|
53
|
+
# # good — snapshot first, then delete, then write: one permutation
|
|
54
|
+
# snapshot = renames.filter_map { |old_name, new_name| [old_name, new_name, state[old_name]] if state.key?(old_name) }
|
|
55
|
+
# snapshot.each { |old_name, _new_name, _value| state.delete(old_name) }
|
|
56
|
+
# snapshot.each { |_old_name, new_name, value| state[new_name] = value }
|
|
57
|
+
class SequentialHashRenameInLoop < Base
|
|
58
|
+
MSG = "`%<recv>s[new] = %<recv>s.delete(old)` inside a loop applies one rename at a time against the " \
|
|
59
|
+
"SAME hash it reads from — a swap (`{a: :b, b: :a}`) on `{a: 1, b: 2}` collapses to `{a: 1}` " \
|
|
60
|
+
"because the first rule's write clobbers the second rule's read target before it runs (the exact " \
|
|
61
|
+
"bug fixed for Lineage#apply_renames). Snapshot every old key's value FIRST, delete all old keys, " \
|
|
62
|
+
"then write all new keys, so the pass applies as one simultaneous permutation instead of a " \
|
|
63
|
+
"sequence of edits each stepping on the last."
|
|
64
|
+
|
|
65
|
+
RESTRICT_ON_SEND = [:[]=].freeze
|
|
66
|
+
|
|
67
|
+
LOOP_METHODS = %i[
|
|
68
|
+
each each_pair each_with_index each_with_object with_index
|
|
69
|
+
map collect flat_map each_entry each_key each_value
|
|
70
|
+
inject reduce each_slice each_cons
|
|
71
|
+
].freeze
|
|
72
|
+
|
|
73
|
+
# `hash[new_name] = hash.delete(old_name)` parses as a `send`
|
|
74
|
+
# node (indexed assignment has no dedicated node type in Ruby's
|
|
75
|
+
# own grammar): `(send recv :[]= new_key (send recv2 :delete
|
|
76
|
+
# old_key))`. `$_recv`/`$_recv2` are captured (not merely
|
|
77
|
+
# matched) so `same_receiver?` below can compare them
|
|
78
|
+
# structurally — node-pattern has no built-in "same subtree
|
|
79
|
+
# twice" backreference, so the equality check is real Ruby, not
|
|
80
|
+
# the pattern itself.
|
|
81
|
+
def_node_matcher :rename_write?, <<~PATTERN
|
|
82
|
+
(send $_recv :[]= _new_key (send $_recv2 :delete _old_key))
|
|
83
|
+
PATTERN
|
|
84
|
+
|
|
85
|
+
def on_send(node)
|
|
86
|
+
rename_write?(node) do |recv, recv2|
|
|
87
|
+
next unless same_receiver?(recv, recv2)
|
|
88
|
+
next unless in_loop?(node)
|
|
89
|
+
|
|
90
|
+
add_offense(node, message: format(MSG, recv: recv.source))
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
private
|
|
95
|
+
|
|
96
|
+
# Structural equality (type + children, recursively) — exactly
|
|
97
|
+
# what `Parser::AST::Node#==` already gives, ignoring source
|
|
98
|
+
# location, so `state` vs `state` (two separate `send(nil,
|
|
99
|
+
# :state)` reader calls) and `@state` vs `@state` both count as
|
|
100
|
+
# "the same collection", not just an identical local variable.
|
|
101
|
+
def same_receiver?(recv, recv2)
|
|
102
|
+
recv == recv2
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Walks every ancestor looking for something that iterates —
|
|
106
|
+
# not just the immediate parent, since the offending assignment
|
|
107
|
+
# may sit one or more non-loop nodes deep inside a loop's block
|
|
108
|
+
# (an `if` guarding it, say) and still carries the exact same
|
|
109
|
+
# hazard.
|
|
110
|
+
def in_loop?(node)
|
|
111
|
+
node.each_ancestor(:block, :numblock, :for, :while, :until, :while_post, :until_post).any? do |ancestor|
|
|
112
|
+
loop_ancestor?(ancestor)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def loop_ancestor?(ancestor)
|
|
117
|
+
case ancestor.type
|
|
118
|
+
when :for, :while, :until, :while_post, :until_post
|
|
119
|
+
true
|
|
120
|
+
when :block, :numblock
|
|
121
|
+
send_node = ancestor.send_node
|
|
122
|
+
send_node.send_type? && LOOP_METHODS.include?(send_node.method_name)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|