hecks 1.3.0 → 1.5.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 +4 -4
- data/lib/hecks/adapters/driven/claude_code.rb +72 -7
- data/lib/hecks/adapters/driven/d1.rb +187 -23
- data/lib/hecks/adapters/driven/folder.rb +83 -10
- data/lib/hecks/adapters/driven/google_authentication.rb +33 -12
- data/lib/hecks/adapters/driven/governance_authorization.rb +87 -18
- data/lib/hecks/adapters/driven/heki/journal.rb +13 -4
- data/lib/hecks/adapters/driven/heki/saga_store.rb +56 -10
- data/lib/hecks/adapters/driven/heki/snapshot.rb +1 -1
- data/lib/hecks/adapters/driven/heki.rb +106 -9
- data/lib/hecks/adapters/driven/identity_registry.rb +12 -2
- data/lib/hecks/adapters/driven/in_memory_ordering.rb +25 -3
- data/lib/hecks/adapters/driven/in_process_key_vault.adapter +3 -0
- data/lib/hecks/adapters/driven/in_process_key_vault.rb +53 -0
- data/lib/hecks/adapters/driven/lambda/client.rb +67 -14
- data/lib/hecks/adapters/driven/lambda.rb +82 -35
- data/lib/hecks/adapters/driven/local_storage.rb +83 -10
- data/lib/hecks/adapters/driven/memory.rb +205 -9
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +21 -1
- data/lib/hecks/adapters/driven/postgres/codec.rb +27 -11
- data/lib/hecks/adapters/driven/postgres/outbox.rb +40 -2
- data/lib/hecks/adapters/driven/postgres/reconnect.rb +23 -7
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +14 -14
- data/lib/hecks/adapters/driven/postgres.rb +175 -28
- data/lib/hecks/adapters/driven/prism.rb +50 -11
- data/lib/hecks/adapters/driven/secure_random_identity.rb +3 -0
- data/lib/hecks/adapters/driven/sql_query_builder.rb +34 -22
- data/lib/hecks/adapters/driven/sqlite/codec.rb +38 -10
- data/lib/hecks/adapters/driven/sqlite/projection.rb +60 -32
- data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +12 -12
- data/lib/hecks/adapters/driven/sqlite.rb +181 -21
- data/lib/hecks/adapters/driven/system_clock.rb +3 -0
- data/lib/hecks/adapters/driven/tenant_provisioner.adapter +3 -0
- data/lib/hecks/adapters/driven/tenant_provisioner.rb +66 -0
- data/lib/hecks/adapters/driven.rb +6 -4
- data/lib/hecks/adapters/driving/github_webhook.rb +31 -18
- data/lib/hecks/behaviors/dsl.rb +60 -2
- data/lib/hecks/behaviors/expectations.rb +190 -29
- data/lib/hecks/behaviors/ir.rb +12 -1
- data/lib/hecks/behaviors/rspec.rb +9 -1
- data/lib/hecks/behaviors/runner.rb +21 -2
- data/lib/hecks/behaviors.rb +9 -1
- data/lib/hecks/bluebook/aggregate.rb +43 -13
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +17 -10
- data/lib/hecks/bluebook/assembly/build.rb +26 -5
- data/lib/hecks/bluebook/assembly/contract.rb +98 -23
- data/lib/hecks/bluebook/assembly/contracts.rb +59 -52
- data/lib/hecks/bluebook/assembly/marks.rb +159 -30
- data/lib/hecks/bluebook/assembly/specializer.rb +38 -21
- data/lib/hecks/bluebook/assembly.rb +32 -14
- data/lib/hecks/bluebook/attribute.rb +26 -12
- data/lib/hecks/bluebook/behaviour/aggregate.rb +43 -11
- data/lib/hecks/bluebook/behaviour/attribute.rb +18 -5
- data/lib/hecks/bluebook/behaviour/chapter.rb +76 -5
- data/lib/hecks/bluebook/behaviour/command.rb +55 -25
- data/lib/hecks/bluebook/behaviour/domain_port.rb +27 -7
- data/lib/hecks/bluebook/behaviour/entity.rb +20 -8
- data/lib/hecks/bluebook/behaviour/hexagon.rb +30 -4
- data/lib/hecks/bluebook/behaviour/lifecycle.rb +27 -6
- data/lib/hecks/bluebook/behaviour/policy.rb +42 -17
- data/lib/hecks/bluebook/behaviour/process_manager.rb +39 -8
- data/lib/hecks/bluebook/behaviour/query.rb +6 -1
- data/lib/hecks/bluebook/behaviour/read_model.rb +29 -8
- data/lib/hecks/bluebook/behaviour/traits.rb +48 -12
- data/lib/hecks/bluebook/behaviour/value_object.rb +21 -9
- data/lib/hecks/bluebook/capabilities.rb +27 -0
- data/lib/hecks/bluebook/chapter.rb +51 -9
- data/lib/hecks/bluebook/command.rb +62 -17
- data/lib/hecks/bluebook/domain_port.rb +34 -9
- data/lib/hecks/bluebook/dsl/adapter_builder.rb +24 -0
- data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +49 -49
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +282 -123
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +112 -75
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +81 -2
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +486 -117
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +179 -47
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +116 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +284 -122
- data/lib/hecks/bluebook/dsl/const_shim.rb +46 -15
- data/lib/hecks/bluebook/dsl/domain_port_builder.rb +90 -25
- data/lib/hecks/bluebook/dsl/entity_builder.rb +191 -61
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +148 -132
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +130 -30
- data/lib/hecks/bluebook/dsl/identity_declaration.rb +38 -21
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +27 -4
- data/lib/hecks/bluebook/dsl/policy_builder.rb +86 -36
- data/lib/hecks/bluebook/dsl/port_builder.rb +38 -7
- data/lib/hecks/bluebook/dsl/port_operation_builder.rb +56 -22
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +111 -47
- data/lib/hecks/bluebook/dsl/query_builder.rb +37 -8
- data/lib/hecks/bluebook/dsl/read_model_builder.rb +127 -52
- data/lib/hecks/bluebook/dsl/rule_reference.rb +97 -43
- data/lib/hecks/bluebook/dsl/translation_builder.rb +150 -44
- data/lib/hecks/bluebook/dsl/value_object_builder.rb +68 -20
- data/lib/hecks/bluebook/dsl/word_gate.rb +59 -53
- data/lib/hecks/bluebook/dsl/world_builder.rb +51 -8
- data/lib/hecks/bluebook/entity.rb +40 -11
- data/lib/hecks/bluebook/expression/ast_json.rb +128 -36
- data/lib/hecks/bluebook/expression/ast_reader.rb +32 -3
- data/lib/hecks/bluebook/expression/canonical_form.rb +55 -16
- data/lib/hecks/bluebook/expression/evaluator.rb +221 -43
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +54 -18
- data/lib/hecks/bluebook/expression/resolver.rb +369 -128
- data/lib/hecks/bluebook/hexagon.rb +35 -1
- data/lib/hecks/bluebook/lifecycle.rb +12 -1
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +2 -1
- data/lib/hecks/bluebook/meta_validator/judge.rb +126 -108
- data/lib/hecks/bluebook/meta_validator/plan.rb +81 -46
- data/lib/hecks/bluebook/meta_validator/port_judge.rb +3 -2
- data/lib/hecks/bluebook/meta_validator/readings.rb +200 -50
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +68 -41
- data/lib/hecks/bluebook/meta_validator/shapes.rb +166 -21
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +286 -46
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +11 -10
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -5
- data/lib/hecks/bluebook/meta_validator.rb +235 -139
- data/lib/hecks/bluebook/model_check.rb +434 -104
- data/lib/hecks/bluebook/pattern_subset.rb +32 -10
- data/lib/hecks/bluebook/policy.rb +15 -13
- data/lib/hecks/bluebook/process_manager.rb +27 -14
- data/lib/hecks/bluebook/project_discovery.rb +5 -0
- data/lib/hecks/bluebook/project_loader.rb +40 -0
- data/lib/hecks/bluebook/project_register.rb +50 -6
- data/lib/hecks/bluebook/query.rb +31 -4
- data/lib/hecks/bluebook/read_model.rb +35 -15
- data/lib/hecks/bluebook/reference.rb +26 -13
- data/lib/hecks/bluebook/smoke_test.rb +46 -23
- data/lib/hecks/bluebook/synthesizer.rb +46 -12
- data/lib/hecks/bluebook/translation.rb +34 -5
- data/lib/hecks/bluebook/value_object.rb +29 -11
- data/lib/hecks/bluebook.rb +5 -6
- data/lib/hecks/codemod.rb +138 -50
- data/lib/hecks/construct.rb +21 -7
- data/lib/hecks/corpus.rb +438 -0
- data/lib/hecks/deploy/bluebook/deploy.hecksagon +19 -0
- data/lib/hecks/doc/reference.rb +200 -31
- data/lib/hecks/embryonaut_bluebook.rb +38 -15
- data/lib/hecks/facade/cli_door.rb +69 -10
- data/lib/hecks/facade/cli_runner.rb +105 -24
- data/lib/hecks/facade/command_request.rb +23 -0
- data/lib/hecks/facade/handle.rb +155 -35
- data/lib/hecks/facade/json_door.rb +106 -25
- data/lib/hecks/facade/surface/aggregate_door.rb +50 -27
- data/lib/hecks/facade/surface/chapter.rb +26 -17
- data/lib/hecks/facade/surface.rb +16 -3
- data/lib/hecks/facade.rb +15 -4
- data/lib/hecks/forms/app.rb +46 -30
- data/lib/hecks/forms/command_form_renderer.rb +70 -9
- data/lib/hecks/forms/field_renderer.rb +142 -6
- data/lib/hecks/forms/field_shape.rb +183 -19
- data/lib/hecks/forms/html.rb +51 -7
- data/lib/hecks/forms/index_renderer.rb +14 -2
- data/lib/hecks/forms/page.rb +14 -0
- data/lib/hecks/forms/params.rb +120 -23
- data/lib/hecks/forms/port_argument.rb +14 -2
- data/lib/hecks/forms/query_form_renderer.rb +65 -2
- data/lib/hecks/forms/record_renderer.rb +60 -2
- data/lib/hecks/forms/record_table.rb +28 -1
- data/lib/hecks/forms/reference_options.rb +24 -0
- data/lib/hecks/forms/value_object_shape.rb +13 -3
- data/lib/hecks/forms.rb +24 -4
- data/lib/hecks/fqn.rb +59 -1
- data/lib/hecks/framework/bluebook/governance.bluebook +9 -0
- data/lib/hecks/framework/bluebook/privacy.bluebook +155 -0
- data/lib/hecks/framework/oidc.json +15 -0
- data/lib/hecks/framework.rb +79 -25
- data/lib/hecks/freezer.rb +27 -11
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +241 -106
- data/lib/hecks/fuzzing/combination_miner.rb +178 -0
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +241 -45
- data/lib/hecks/fuzzing/coverage_campaign.rb +161 -0
- data/lib/hecks/fuzzing/differential.rb +192 -0
- data/lib/hecks/fuzzing/domain_generator.rb +871 -0
- data/lib/hecks/fuzzing/era_boundary.rb +68 -19
- data/lib/hecks/fuzzing/form_census.rb +121 -20
- data/lib/hecks/fuzzing/generated_domain_check.rb +171 -0
- data/lib/hecks/fuzzing/invalid_value_generator.rb +45 -6
- data/lib/hecks/fuzzing/isolated_boot.rb +137 -80
- data/lib/hecks/fuzzing/nondeterministic.rb +79 -0
- data/lib/hecks/fuzzing/persistence_parity.rb +111 -21
- data/lib/hecks/fuzzing/properties/corrections.rb +34 -9
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +300 -51
- data/lib/hecks/fuzzing/properties/guards.rb +86 -42
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +80 -32
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +40 -35
- data/lib/hecks/fuzzing/properties/outbox.rb +70 -32
- data/lib/hecks/fuzzing/properties/querying.rb +82 -28
- data/lib/hecks/fuzzing/properties.rb +84 -51
- data/lib/hecks/fuzzing/qa_settings.rb +164 -0
- data/lib/hecks/fuzzing/replay.rb +241 -133
- data/lib/hecks/fuzzing/rotation_priority.rb +48 -28
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +139 -0
- data/lib/hecks/fuzzing/self_consistency.rb +315 -137
- data/lib/hecks/fuzzing/sequence_generator/adversary.rb +46 -40
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +18 -11
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +13 -12
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +21 -12
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +59 -32
- data/lib/hecks/fuzzing/sequence_generator.rb +158 -23
- data/lib/hecks/fuzzing/shrinker.rb +309 -0
- data/lib/hecks/fuzzing/structural_skips.rb +37 -130
- data/lib/hecks/fuzzing/sweep_depth.rb +12 -4
- data/lib/hecks/fuzzing/target_capabilities.rb +107 -29
- data/lib/hecks/fuzzing/value_generator.rb +110 -22
- data/lib/hecks/fuzzing.rb +5 -0
- data/lib/hecks/grammar/evolve.rb +188 -12
- data/lib/hecks/grammar.rb +53 -7
- data/lib/hecks/ir.rb +51 -20
- data/lib/hecks/language/bluebook/bluebook.bluebook +41 -0
- data/lib/hecks/language/bluebook/policy.bluebook +11 -1
- data/lib/hecks/language/bluebook/vocabulary.bluebook +348 -13
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +11 -0
- data/lib/hecks/language/oidc.json +5 -0
- data/lib/hecks/literal.rb +41 -9
- data/lib/hecks/naming.rb +112 -31
- data/lib/hecks/ports/access_control.rb +53 -2
- data/lib/hecks/ports/agent/answers.rb +83 -6
- data/lib/hecks/ports/agent.rb +119 -35
- data/lib/hecks/ports/authentication.rb +44 -4
- data/lib/hecks/ports/authorization.rb +50 -11
- data/lib/hecks/ports/clock.rb +42 -23
- data/lib/hecks/ports/extraction.rb +16 -0
- data/lib/hecks/ports/identity_assignment.rb +23 -2
- data/lib/hecks/ports/identity_generation.rb +17 -3
- data/lib/hecks/ports/identity_resolution.rb +17 -1
- data/lib/hecks/ports/key_vault.port +6 -0
- data/lib/hecks/ports/key_vault.rb +58 -0
- data/lib/hecks/ports/loading.rb +4 -0
- data/lib/hecks/ports/persistence/append_only.rb +172 -8
- data/lib/hecks/ports/persistence/binding_policy.rb +34 -0
- data/lib/hecks/ports/persistence/codec_boundary.rb +178 -0
- data/lib/hecks/ports/persistence/execution.rb +4 -0
- data/lib/hecks/ports/persistence/null_saga_store.rb +12 -1
- data/lib/hecks/ports/persistence/plugin.rb +42 -4
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +218 -25
- data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +77 -9
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +81 -24
- data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +29 -18
- data/lib/hecks/ports/persistence/plugins/era/lineage.rb +144 -60
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +103 -8
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +98 -23
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +282 -109
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +63 -25
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +118 -66
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +51 -28
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +34 -5
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +25 -12
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +129 -34
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +51 -6
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +33 -9
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +16 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +95 -6
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +25 -2
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +314 -90
- data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +68 -10
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +9 -3
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +9 -2
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +48 -8
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +16 -1
- data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +36 -5
- data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +23 -3
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +58 -19
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +96 -5
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +15 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +9 -1
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -2
- data/lib/hecks/ports/persistence/plugins/era.rb +12 -2
- data/lib/hecks/ports/persistence/remote_runtime.rb +9 -2
- data/lib/hecks/ports/persistence/repository_factory.rb +23 -3
- data/lib/hecks/ports/persistence/state_codec.rb +319 -0
- data/lib/hecks/ports/persistence.rb +36 -1
- data/lib/hecks/ports/projection.rb +61 -7
- data/lib/hecks/ports/query/in_memory.rb +41 -8
- data/lib/hecks/ports/query/ordering.rb +21 -6
- data/lib/hecks/ports/query.rb +35 -0
- data/lib/hecks/ports.rb +1 -0
- data/lib/hecks/projections/bootstrap_table.rb +147 -0
- data/lib/hecks/projections/diagrams.rb +315 -79
- data/lib/hecks/projections/glossary/html.rb +91 -3
- data/lib/hecks/projections/glossary/markdown.rb +50 -3
- data/lib/hecks/projections/glossary/mermaid.rb +49 -1
- data/lib/hecks/projections/glossary/sections.rb +1 -1
- data/lib/hecks/projections/glossary/sentences.rb +110 -5
- data/lib/hecks/projections/glossary.rb +173 -31
- data/lib/hecks/projections/ir.rb +1 -1
- data/lib/hecks/projections/model/deviations.rb +62 -17
- data/lib/hecks/projections/model.rb +75 -21
- data/lib/hecks/projections/oidc.rb +45 -8
- data/lib/hecks/projections/parser_table.rb +53 -12
- data/lib/hecks/projections/reference.rb +15 -3
- data/lib/hecks/projections/rust_vocabulary.rb +646 -0
- data/lib/hecks/projections/shape.rb +10 -2
- data/lib/hecks/projections/statements.rb +69 -22
- data/lib/hecks/projections/vocabulary.rb +26 -9
- data/lib/hecks/projections.rb +5 -3
- data/lib/hecks/projector/cli_projector.rb +245 -37
- data/lib/hecks/projector/docs_projector.rb +154 -28
- data/lib/hecks/projector/exporter.rb +104 -29
- data/lib/hecks/projector/ir_projector.rb +7 -1
- data/lib/hecks/projector/narrate_projector.rb +144 -23
- data/lib/hecks/projector/target.rb +42 -18
- data/lib/hecks/projector.rb +86 -18
- data/lib/hecks/query_ir.rb +94 -47
- data/lib/hecks/query_specification/common/comparators.rb +19 -3
- data/lib/hecks/query_specification/common/comparison.rb +109 -27
- data/lib/hecks/query_specification/common/dsl.rb +65 -9
- data/lib/hecks/query_specification/common/null_policy.rb +61 -15
- data/lib/hecks/query_specification/common/null_semantics.rb +4 -0
- data/lib/hecks/query_specification/common/options.rb +25 -0
- data/lib/hecks/query_specification/field_path.rb +69 -15
- data/lib/hecks/query_specification/hop_path.rb +57 -20
- data/lib/hecks/query_specification/read_model/specification.rb +4 -0
- data/lib/hecks/rendering.rb +9 -3
- data/lib/hecks/router/namespace_installer.rb +16 -3
- data/lib/hecks/router.rb +56 -1
- data/lib/hecks/runtime/aggregate_lock.rb +20 -11
- data/lib/hecks/runtime/boot_gates.rb +21 -3
- data/lib/hecks/runtime/caller.rb +40 -8
- data/lib/hecks/runtime/capability_graph.rb +13 -2
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +40 -41
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +45 -67
- data/lib/hecks/runtime/command_interpreter.rb +195 -113
- data/lib/hecks/runtime/command_rules/admissibility.rb +231 -80
- data/lib/hecks/runtime/command_rules/arithmetic.rb +154 -96
- data/lib/hecks/runtime/command_rules/authorization.rb +38 -17
- data/lib/hecks/runtime/command_rules/emission.rb +18 -1
- data/lib/hecks/runtime/command_rules/references.rb +145 -55
- data/lib/hecks/runtime/command_rules.rb +3 -0
- data/lib/hecks/runtime/dependency_planning.rb +56 -11
- data/lib/hecks/runtime/dispatcher.rb +263 -92
- data/lib/hecks/runtime/entity_element.rb +304 -67
- data/lib/hecks/runtime/entity_interpreter.rb +149 -88
- data/lib/hecks/runtime/errors.rb +37 -23
- data/lib/hecks/runtime/event.rb +15 -10
- data/lib/hecks/runtime/identity.rb +91 -23
- data/lib/hecks/runtime/instance.rb +103 -18
- data/lib/hecks/runtime/interpreting.rb +24 -16
- data/lib/hecks/runtime/invocation.rb +358 -0
- data/lib/hecks/runtime/loader.rb +105 -19
- data/lib/hecks/runtime/outbox.rb +164 -26
- data/lib/hecks/runtime/policy_interpreter.rb +73 -60
- data/lib/hecks/runtime/port_operation_interpreter.rb +42 -19
- data/lib/hecks/runtime/query_interpreter.rb +93 -74
- data/lib/hecks/runtime/reaction_invocation.rb +73 -28
- data/lib/hecks/runtime/read_model_interpreter.rb +60 -44
- data/lib/hecks/runtime/rebuild_sweep.rb +32 -4
- data/lib/hecks/runtime/reference_hop.rb +48 -6
- data/lib/hecks/runtime/refusal_wording.rb +142 -115
- data/lib/hecks/runtime/registry/saga_persistence.rb +32 -21
- data/lib/hecks/runtime/registry/verification.rb +153 -28
- data/lib/hecks/runtime/registry.rb +202 -32
- data/lib/hecks/runtime/remote_dispatcher.rb +125 -24
- data/lib/hecks/runtime/routing.rb +36 -154
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +25 -27
- data/lib/hecks/runtime/saga_interpreter.rb +90 -76
- data/lib/hecks/runtime/saga_pending_dispatch.rb +12 -12
- data/lib/hecks/runtime/tenant_check.rb +33 -13
- data/lib/hecks/runtime/tenant_scope.rb +23 -5
- data/lib/hecks/runtime/value/admission.rb +75 -30
- data/lib/hecks/runtime/value/coercion.rb +555 -142
- data/lib/hecks/runtime/value/entity_list_coercion.rb +132 -60
- data/lib/hecks/runtime/value.rb +71 -21
- data/lib/hecks/runtime.rb +39 -7
- data/lib/hecks/storehouse.rb +368 -72
- data/lib/hecks/tenancy/bluebook/tenancy.bluebook +130 -0
- data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +32 -0
- data/lib/hecks/version.rb +3 -3
- data/lib/hecks/vocabulary.rb +205 -4
- data/lib/hecks.rb +91 -11
- data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +19 -11
- data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +24 -12
- data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +38 -14
- metadata +28 -2
data/lib/hecks/codemod.rb
CHANGED
|
@@ -1,49 +1,58 @@
|
|
|
1
1
|
require_relative "bluebook/meta_validator"
|
|
2
|
+
require_relative "corpus"
|
|
2
3
|
|
|
3
4
|
module Hecks
|
|
4
|
-
#
|
|
5
|
-
# once a DSL builder change makes some previously-required declaration
|
|
6
|
-
# optional/redundant — pulled out of `bin/codemod_implicit_append_fields`
|
|
7
|
-
# (the first one built), which needed three real, hard-won fixes before
|
|
8
|
-
# it could be trusted: a process-lifetime AST cache with no
|
|
9
|
-
# invalidation, a batch-revert granularity that let one unsafe
|
|
10
|
-
# candidate sink every other safe one sharing its boot, and (in the
|
|
11
|
-
# SPINE the codemod migrates FOR, not here) an append-at-end insertion
|
|
12
|
-
# that only round-tripped correctly for whichever field happened to be
|
|
13
|
-
# last. None of those are guessable in advance; they only surface by
|
|
14
|
-
# actually running a real edit against real self-hosted code. This
|
|
15
|
-
# module is that lesson, kept — the NEXT codemod plugs in two rule-
|
|
16
|
-
# specific procs (`find_candidates`, `apply_candidate`) and inherits
|
|
17
|
-
# the boot/safety-net machinery rather than rediscovering it.
|
|
5
|
+
# Shared machinery for a codemod that migrates real `.bluebook` source.
|
|
18
6
|
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
7
|
+
# ## Why this module exists
|
|
8
|
+
#
|
|
9
|
+
# For migrating source once a DSL builder change turns a required
|
|
10
|
+
# declaration into an optional, redundant one — pulled out of
|
|
11
|
+
# `bin/codemod_implicit_append_fields` (the first one built), which
|
|
12
|
+
# needed three real, hard-won fixes before it could be trusted: a
|
|
13
|
+
# process-lifetime AST cache with no invalidation, a batch-revert
|
|
14
|
+
# granularity that let one unsafe candidate sink every other safe one
|
|
15
|
+
# sharing its boot, and (in the spine the codemod migrates for, not
|
|
16
|
+
# here) an append-at-end insertion that only round-tripped correctly
|
|
17
|
+
# for whichever field happened to be last. None of those are guessable
|
|
18
|
+
# in advance; they only surface by actually running a real edit
|
|
19
|
+
# against real self-hosted code. This module is that lesson, kept —
|
|
20
|
+
# the next codemod plugs in two rule-specific procs (`find_candidates`,
|
|
21
|
+
# `apply_candidate`) and inherits the boot/safety-net machinery rather
|
|
22
|
+
# than rediscovering it.
|
|
23
|
+
#
|
|
24
|
+
# ## The three-step contract
|
|
25
|
+
#
|
|
26
|
+
# **A codemod is not pattern-matching alone**. Deciding "is this line safe
|
|
27
|
+
# to delete" means knowing what the runtime would resolve it to — so
|
|
21
28
|
# every codemod built on this module follows the same three steps:
|
|
22
29
|
# 1. Boot the real domain (or the self-hosted meta-domain) and read
|
|
23
|
-
# its IR to find
|
|
30
|
+
# its IR to find candidates — provided by the caller's own
|
|
24
31
|
# `find_candidates`, since the actual redundancy rule is specific
|
|
25
32
|
# to whichever spine change this migration serves.
|
|
26
33
|
# 2. Locate and remove each candidate's own source text — the
|
|
27
34
|
# caller's own `apply_candidate`.
|
|
28
35
|
# 3. Re-boot from the edited text and diff the full IR export
|
|
29
36
|
# against the pre-edit export. Byte-identical -> keep. Anything
|
|
30
|
-
# else (including a
|
|
31
|
-
# meta-domain
|
|
37
|
+
# else (including a raised exception — the self-hosted
|
|
38
|
+
# meta-domain dispatches itself into being, S14, so a bad edit
|
|
32
39
|
# can surface as a runtime refusal, not just a differing export)
|
|
33
|
-
# -> revert and report
|
|
40
|
+
# -> revert and report skipped, never silently guessed past.
|
|
41
|
+
#
|
|
42
|
+
# ## Design-time checklist for a future codemod
|
|
34
43
|
#
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
# - Does the resolved value get inserted into an
|
|
44
|
+
# For the spine change a future codemod migrates corpus text for —
|
|
45
|
+
# both items below are real bugs this module's own first use found,
|
|
46
|
+
# not hypothetical:
|
|
47
|
+
# - Does the resolved value get inserted into an order-sensitive
|
|
39
48
|
# list (the exported IR is array-order-sensitive throughout)? If
|
|
40
|
-
# so, the spine's own insertion must preserve the
|
|
49
|
+
# so, the spine's own insertion must preserve the original
|
|
41
50
|
# position, not just append — an append-at-end insertion only
|
|
42
51
|
# round-trips correctly for a value that already happened to be
|
|
43
52
|
# last.
|
|
44
|
-
# - Does resolution depend on
|
|
53
|
+
# - Does resolution depend on another construct already being
|
|
45
54
|
# declared (the aggregate/entity a `sets`/`append:` field resolves
|
|
46
|
-
# against)? If a creator command can be declared
|
|
55
|
+
# against)? If a creator command can be declared before the
|
|
47
56
|
# construct it creates (real, live: `command "Handler"` before
|
|
48
57
|
# `entity "Handler"`, one file down), one-pass resolution
|
|
49
58
|
# genuinely cannot see it yet — not a codemod bug, a structural
|
|
@@ -51,16 +60,16 @@ module Hecks
|
|
|
51
60
|
module Codemod
|
|
52
61
|
ROOT = File.expand_path("../..", __dir__)
|
|
53
62
|
|
|
54
|
-
EXAMPLE_ROOTS =
|
|
63
|
+
EXAMPLE_ROOTS = Corpus.members(:example, root: ROOT).map(&:path)
|
|
55
64
|
META_FILES = (Dir.glob(File.join(ROOT, "lib/hecks/grammar/*.bluebook")) +
|
|
56
65
|
Dir.glob(File.join(ROOT, "lib/hecks/framework/bluebook/*.bluebook")) +
|
|
57
66
|
Dir.glob(File.join(ROOT, "lib/hecks/language/bluebook/**/*.bluebook"))).sort
|
|
58
67
|
|
|
59
|
-
#
|
|
68
|
+
# The same lightweight path `spec/spec_helper.rb`'s own
|
|
60
69
|
# `boot_in_memory` uses — `Hecks.with_registry` satisfies
|
|
61
70
|
# `Hecks.bluebook`'s own `collect`'s "loaded outside a boot" check
|
|
62
71
|
# without `Hecks.boot`'s full era-check/adapter-wiring path, which
|
|
63
|
-
# needs a
|
|
72
|
+
# needs a live Postgres connection for `compliance` and would make
|
|
64
73
|
# every codemod depend on a database it has no reason to touch — a
|
|
65
74
|
# codemod only ever reads a chapter's own declared IR, never a
|
|
66
75
|
# stored record.
|
|
@@ -69,19 +78,27 @@ module Hecks
|
|
|
69
78
|
MEMORY_ADAPTER = File.join(ROOT, "lib/hecks/adapters/driven/memory.adapter")
|
|
70
79
|
PRISM_ADAPTER = File.join(ROOT, "lib/hecks/adapters/driven/prism.adapter")
|
|
71
80
|
|
|
81
|
+
# Exports a booted registry's canonical IR as JSON, for a before/after diff.
|
|
82
|
+
#
|
|
83
|
+
# @param registry [Runtime::Registry] the booted registry to export
|
|
84
|
+
# @return [String] the pretty-printed JSON IR export
|
|
72
85
|
def self.export_json(registry) = Hecks::Projector::Exporter.json(registry)
|
|
73
86
|
|
|
74
87
|
# `Hecks::Adapters::Prism` caches a file's parsed AST for the
|
|
75
|
-
# life of the
|
|
88
|
+
# life of the process, keyed by path — fine for every existing
|
|
76
89
|
# caller (a file loads once per process: one `bin/ir` run, one
|
|
77
|
-
# rspec worker), but a codemod legitimately reloads the
|
|
90
|
+
# rspec worker), but a codemod legitimately reloads the same path
|
|
78
91
|
# after editing it, and a stale cached tree reports a
|
|
79
|
-
# `given`/`ensures` block at its
|
|
92
|
+
# `given`/`ensures` block at its old line number, which no longer
|
|
80
93
|
# matches the freshly re-executed file's own `block.source_location`
|
|
81
94
|
# — surfacing as "did not survive extraction" on a perfectly valid
|
|
82
95
|
# file. `Prism.forget` is the real invalidation API this module's
|
|
83
96
|
# own first use motivated (found here, fixed at the source rather
|
|
84
97
|
# than left as a private `TREES.clear` poke from outside).
|
|
98
|
+
#
|
|
99
|
+
# @param path [String, Array<String>] a single `.bluebook` file, a directory
|
|
100
|
+
# to glob every `.bluebook` file from, or an explicit list of file paths
|
|
101
|
+
# @return [Runtime::Registry] a fresh registry with every file loaded and judged
|
|
85
102
|
def self.load_bluebook(path)
|
|
86
103
|
paths = if path.is_a?(Array)
|
|
87
104
|
path
|
|
@@ -104,16 +121,21 @@ module Hecks
|
|
|
104
121
|
registry
|
|
105
122
|
end
|
|
106
123
|
|
|
107
|
-
# `forget_all`, not a single `forget` — the meta-domain is
|
|
124
|
+
# `forget_all`, not a single `forget` — the meta-domain is nine
|
|
108
125
|
# files (`MetaValidator::GRAMMAR_FILES`) merged into one registry,
|
|
109
126
|
# and a caller here (the codemod runner) doesn't generally know in
|
|
110
|
-
# advance which
|
|
127
|
+
# advance which one it just edited.
|
|
128
|
+
# @return [String] the freshly re-derived meta-domain's canonical IR, as JSON
|
|
111
129
|
def self.boot_meta
|
|
112
130
|
Hecks::Adapters::Prism.forget_all
|
|
113
131
|
Hecks::Bluebook::MetaValidator.instance_variable_set(:@grammar_registry, nil)
|
|
114
132
|
export_json(Hecks::Bluebook::MetaValidator.grammar_registry)
|
|
115
133
|
end
|
|
116
134
|
|
|
135
|
+
# Forces the self-hosted meta-domain to re-derive from its current source,
|
|
136
|
+
# discarding any cached parse trees or memoized registry.
|
|
137
|
+
#
|
|
138
|
+
# @return [Runtime::Registry] the freshly re-derived meta-domain's registry
|
|
117
139
|
def self.meta_registry
|
|
118
140
|
Hecks::Adapters::Prism.forget_all
|
|
119
141
|
Hecks::Bluebook::MetaValidator.instance_variable_set(:@grammar_registry, nil)
|
|
@@ -123,10 +145,18 @@ module Hecks
|
|
|
123
145
|
# Walks every aggregate (and every nested entity, recursively)
|
|
124
146
|
# across every chapter in a booted registry, yielding [owning
|
|
125
147
|
# construct, command] pairs — `construct` is whichever
|
|
126
|
-
# Aggregate/Entity actually
|
|
148
|
+
# Aggregate/Entity actually owns the command, the same distinction
|
|
127
149
|
# `AggregateBuilder#command` vs `EntityBuilder#command` already
|
|
128
150
|
# draws. Generic enough for any rule that needs to walk real
|
|
129
151
|
# commands, not specific to the attribute-redundancy rule.
|
|
152
|
+
#
|
|
153
|
+
# @param registry [Runtime::Registry] a booted registry
|
|
154
|
+
# @yield [construct, command] every command in the registry, once per aggregate
|
|
155
|
+
# and once per nested entity
|
|
156
|
+
# @yieldparam construct [Bluebook::Aggregate, Bluebook::Entity] whichever
|
|
157
|
+
# aggregate or entity actually owns `command`
|
|
158
|
+
# @yieldparam command [Bluebook::Command] the command
|
|
159
|
+
# @return [Hash{String => Bluebook::Chapter}] `registry.bluebooks`, unchanged
|
|
130
160
|
def self.each_command(registry)
|
|
131
161
|
registry.bluebooks.each_value do |chapter|
|
|
132
162
|
chapter.aggregates.each do |aggregate|
|
|
@@ -139,38 +169,74 @@ module Hecks
|
|
|
139
169
|
end
|
|
140
170
|
end
|
|
141
171
|
|
|
172
|
+
# Finds one construct's own attribute by name.
|
|
173
|
+
#
|
|
174
|
+
# @param construct [Bluebook::Aggregate, Bluebook::Entity] the construct to search
|
|
175
|
+
# @param name [String, Symbol, #to_s] the attribute's declared name
|
|
176
|
+
# @return [Bluebook::Attribute, nil] the matching attribute, or nil if `construct`
|
|
177
|
+
# declares no attribute named `name`
|
|
142
178
|
def self.owner_attribute(construct, name)
|
|
143
179
|
construct.attributes.find { |attr| attr.name.to_s == name.to_s }
|
|
144
180
|
end
|
|
145
181
|
|
|
146
|
-
# A
|
|
182
|
+
# A list attribute's own element construct — the value object or
|
|
147
183
|
# entity `list_of(...)` names, resolved by `hecks_name` the same way
|
|
148
184
|
# `AttributeCollector#resolve_identity_field!` already does. Shared
|
|
149
185
|
# because "what does this list actually hold" is a question any
|
|
150
186
|
# append-shaped rule needs answered, not just this one.
|
|
187
|
+
#
|
|
188
|
+
# Nothing in the DSL stops a value object and an entity nested under
|
|
189
|
+
# the same aggregate from sharing a `hecks_name` — they are declared
|
|
190
|
+
# through two separate collections with no cross-kind uniqueness
|
|
191
|
+
# check between them. A silent value-objects-before-entities pick
|
|
192
|
+
# would resolve such a pair the same way every time regardless of
|
|
193
|
+
# which one `list_field` actually names, so a genuine collision is
|
|
194
|
+
# refused instead, the same "never first-wins silently" call
|
|
195
|
+
# `EntityBuilder#install_closed_sets!` already makes for a same-named
|
|
196
|
+
# closed set.
|
|
197
|
+
#
|
|
198
|
+
# @param construct [Bluebook::Aggregate, Bluebook::Entity] the construct
|
|
199
|
+
# declaring `list_field`
|
|
200
|
+
# @param list_field [String, Symbol, #to_s] the name of the `list_of(...)` attribute
|
|
201
|
+
# @return [Bluebook::Entity, Bluebook::ValueObject, nil] the construct
|
|
202
|
+
# `list_field` holds a list of, or nil if `list_field` names no attribute,
|
|
203
|
+
# isn't a list, or names no known value object or entity
|
|
204
|
+
# @raise [RuntimeError] if a value object and an entity both match `list_field`'s type
|
|
151
205
|
def self.element_construct_for(construct, list_field)
|
|
152
206
|
list_attr = owner_attribute(construct, list_field)
|
|
153
207
|
return nil unless list_attr&.list?
|
|
154
208
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
209
|
+
value_objects = construct.respond_to?(:value_objects) ? construct.value_objects : []
|
|
210
|
+
entities = construct.respond_to?(:entities) ? construct.entities : []
|
|
211
|
+
matches = (value_objects + entities).select { |c| c.hecks_name.to_s == list_attr.type.to_s }
|
|
212
|
+
|
|
213
|
+
if matches.size > 1
|
|
214
|
+
raise "#{construct.hecks_name}##{list_field} names #{list_attr.type}, held by both a value " \
|
|
215
|
+
"object and an entity — ambiguous, cannot resolve which one the list holds"
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
matches.first
|
|
158
219
|
end
|
|
159
220
|
|
|
160
|
-
# Either a raised exception
|
|
221
|
+
# Either a raised exception or a differing export counts as unsafe
|
|
161
222
|
# — see the module header on why the meta-domain specifically can
|
|
162
223
|
# raise. Returns [value_or_nil, error_message_or_nil].
|
|
224
|
+
#
|
|
225
|
+
# @yield the risky boot/export step to run
|
|
226
|
+
# @return [Array(Object, nil), Array(nil, String)] `[the block's result, nil]`
|
|
227
|
+
# on success, or `[nil, "ExceptionClass: message"]` if the block raises
|
|
228
|
+
# any StandardError
|
|
163
229
|
def self.safely
|
|
164
230
|
[yield, nil]
|
|
165
231
|
rescue StandardError => e
|
|
166
232
|
[nil, "#{e.class}: #{e.message}"]
|
|
167
233
|
end
|
|
168
234
|
|
|
169
|
-
#
|
|
235
|
+
# **The reusable runner** — every real bug fix this module carries lives
|
|
170
236
|
# here, not in a caller's own script. A caller supplies:
|
|
171
237
|
#
|
|
172
238
|
# find_candidates: ->(registry) { [...] }
|
|
173
|
-
# Given a booted registry, return every
|
|
239
|
+
# Given a booted registry, return every candidate this rule
|
|
174
240
|
# could migrate. A candidate is whatever shape the caller wants
|
|
175
241
|
# — `apply_candidate` is the only other thing that reads it.
|
|
176
242
|
#
|
|
@@ -178,19 +244,36 @@ module Hecks
|
|
|
178
244
|
# Given one file's current text and one candidate, return the
|
|
179
245
|
# edited text and whether a match was actually found/removed —
|
|
180
246
|
# `false` (text unchanged) when the candidate doesn't apply to
|
|
181
|
-
#
|
|
247
|
+
# this file, which is how the meta-domain's multi-file search
|
|
182
248
|
# below finds the right one without the caller needing to know
|
|
183
249
|
# which file a candidate lives in ahead of time.
|
|
184
250
|
#
|
|
185
251
|
# label: ->(candidate) { "..." }
|
|
186
252
|
# One-line description for the results report.
|
|
187
253
|
class Runner
|
|
254
|
+
# @param find_candidates [Proc] `->(registry) { [...] }` — given a booted
|
|
255
|
+
# registry, returns every candidate this rule could migrate; a candidate's
|
|
256
|
+
# shape is the caller's own, read back only by `apply_candidate`
|
|
257
|
+
# @param apply_candidate [Proc] `->(text, candidate) { [new_text, changed_bool] }`
|
|
258
|
+
# — given one file's current text and one candidate, returns the edited text
|
|
259
|
+
# and whether a match was found; `false` means the candidate doesn't apply to
|
|
260
|
+
# this file
|
|
261
|
+
# @param label [Proc] `->(candidate) { "..." }` — a one-line description of a
|
|
262
|
+
# candidate, for the results report
|
|
188
263
|
def initialize(find_candidates:, apply_candidate:, label:)
|
|
189
264
|
@find_candidates = find_candidates
|
|
190
265
|
@apply_candidate = apply_candidate
|
|
191
266
|
@label = label
|
|
192
267
|
end
|
|
193
268
|
|
|
269
|
+
# Runs this rule's codemod across every example domain and the meta-domain.
|
|
270
|
+
#
|
|
271
|
+
# @param dry_run [Boolean] when true, every safe edit is still written and
|
|
272
|
+
# reverified, then reverted rather than kept
|
|
273
|
+
# @return [Hash{Symbol => Array}] `:applied` (`Array<Hash{file: String,
|
|
274
|
+
# candidates: Array<String>}>`), `:skipped` (`Array<Hash{file: String,
|
|
275
|
+
# reason: String, candidates: Array<String>}>`), and `:clean`
|
|
276
|
+
# (`Array<String>` of domain directories or `"meta-domain"` with no candidates)
|
|
194
277
|
def run(dry_run: false)
|
|
195
278
|
results = { applied: [], skipped: [], clean: [] }
|
|
196
279
|
run_example_domains(results, dry_run)
|
|
@@ -198,6 +281,11 @@ module Hecks
|
|
|
198
281
|
results
|
|
199
282
|
end
|
|
200
283
|
|
|
284
|
+
# Prints `run`'s results to stdout.
|
|
285
|
+
#
|
|
286
|
+
# @param results [Hash{Symbol => Array}] a `run` result
|
|
287
|
+
# @param dry_run [Boolean] whether this was a dry run, for the report's own heading
|
|
288
|
+
# @return [void]
|
|
201
289
|
def report(results, dry_run:)
|
|
202
290
|
puts "== results (#{dry_run ? 'DRY RUN — nothing written' : 'applied'}) =="
|
|
203
291
|
puts "clean (no candidates): #{results[:clean].join(', ')}" unless results[:clean].empty?
|
|
@@ -279,10 +367,10 @@ module Hecks
|
|
|
279
367
|
end
|
|
280
368
|
end
|
|
281
369
|
|
|
282
|
-
#
|
|
283
|
-
# meta-domain is
|
|
370
|
+
# Per-candidate, not one batched write-then-verify — the
|
|
371
|
+
# meta-domain is one shared registry (SyntaxBoot dispatches it
|
|
284
372
|
# into itself, S14), so a single unsafe candidate among many would
|
|
285
|
-
# otherwise sink every
|
|
373
|
+
# otherwise sink every other, genuinely safe candidate in the same
|
|
286
374
|
# run: this module's first real run found exactly that (25
|
|
287
375
|
# candidates, one dispatch-time break, all 25 reverted as a batch
|
|
288
376
|
# before this per-candidate loop existed). `before_meta` stays the
|
|
@@ -291,8 +379,8 @@ module Hecks
|
|
|
291
379
|
# still equal the pristine original after each kept edit, by
|
|
292
380
|
# definition, no moving target needed.
|
|
293
381
|
# Same shape and same reason as run_example_domains just above (see
|
|
294
|
-
# its own comment) — the write/verify/revert sequence,
|
|
295
|
-
#
|
|
382
|
+
# its own comment) — the write/verify/revert sequence, per
|
|
383
|
+
# candidate (this method's own comment explains why it cannot
|
|
296
384
|
# batch), is one coherent unit; splitting it would scatter
|
|
297
385
|
# before_meta/live_meta/applied_by_file state across methods for
|
|
298
386
|
# no gain.
|
|
@@ -323,7 +411,7 @@ module Hecks
|
|
|
323
411
|
live_meta[target_file] = text
|
|
324
412
|
Codemod::META_FILES.each { |f| File.write(f, live_meta[f]) }
|
|
325
413
|
|
|
326
|
-
#
|
|
414
|
+
# **Dry run still verifies** — see run_example_domains' own
|
|
327
415
|
# comment; the edit is always written and rebooted for real,
|
|
328
416
|
# then always reverted afterward when dry-run (whether or not
|
|
329
417
|
# it was safe) so the next candidate is judged against the
|
data/lib/hecks/construct.rb
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
module Hecks
|
|
2
2
|
# The invisible field a built construct carries.
|
|
3
3
|
#
|
|
4
|
-
#
|
|
4
|
+
# ## Identity
|
|
5
|
+
#
|
|
6
|
+
# A construct is a record with an owner chain — the chapter (Bluebook)
|
|
5
7
|
# owns its aggregates, an aggregate owns everything declared on it — and the
|
|
6
8
|
# bluebook identity is carried in its own field, under a `hecks_` prefix that
|
|
7
9
|
# no domain attribute can collide with. Invisible means exactly that: not an
|
|
8
10
|
# attribute, not a key in `to_h`, not a reader on instances. Framework
|
|
9
11
|
# metadata about the construct, not part of the domain it describes.
|
|
10
12
|
#
|
|
11
|
-
# The identity is
|
|
13
|
+
# The identity is computed by walking owners rather than stamped, so nothing
|
|
12
14
|
# has to be re-stamped when a chapter is assembled after its aggregates:
|
|
13
15
|
#
|
|
14
16
|
# Pizzas the chapter — no owner
|
|
@@ -17,10 +19,10 @@ module Hecks
|
|
|
17
19
|
#
|
|
18
20
|
# That spelling is not invented here. It is the id `MetaValidator::Judge`
|
|
19
21
|
# already mints in `#identify`, so a construct and the meta-domain's
|
|
20
|
-
# record
|
|
22
|
+
# record of that construct carry the same identity, and there is no
|
|
21
23
|
# translation table between them to be quietly wrong in.
|
|
22
24
|
#
|
|
23
|
-
# Usage
|
|
25
|
+
# ## Usage
|
|
24
26
|
#
|
|
25
27
|
# price = Class.new(ValueObject) # a declaration holder
|
|
26
28
|
# price.hecks_name = "Price"
|
|
@@ -37,25 +39,37 @@ module Hecks
|
|
|
37
39
|
attr_writer :hecks_name
|
|
38
40
|
|
|
39
41
|
# A chapter is the only construct that legitimately has no owner. Everything
|
|
40
|
-
# else is
|
|
42
|
+
# else is declared in something, so a missing owner is an unstamped construct
|
|
41
43
|
# rather than a top — see hecks_fqn.
|
|
42
44
|
attr_writer :hecks_root
|
|
43
45
|
|
|
46
|
+
# Whether this construct is the top of its own owner chain.
|
|
47
|
+
#
|
|
48
|
+
# @return [Boolean] true for a chapter, which sets `hecks_root`; false otherwise
|
|
44
49
|
def hecks_root? = @hecks_root ? true : false
|
|
45
50
|
|
|
46
51
|
# The name as the bluebook declares it, never the constant path.
|
|
52
|
+
#
|
|
53
|
+
# @return [String] the construct's own name, without any owner prefix
|
|
47
54
|
def hecks_name = @hecks_name
|
|
48
55
|
|
|
49
56
|
# How this construct joins its owner. An aggregate is a member of its
|
|
50
|
-
# chapter's namespace (`::`) ; everything else is declared
|
|
57
|
+
# chapter's namespace (`::`) ; everything else is declared on its owner
|
|
51
58
|
# (`.`). Overridden by Aggregate, defaulted here for every other construct.
|
|
59
|
+
#
|
|
60
|
+
# @return [String] `"."`, the separator this construct uses in `hecks_fqn`
|
|
52
61
|
def hecks_separator = "."
|
|
53
62
|
|
|
54
|
-
#
|
|
63
|
+
# Refuses rather than guesses. A construct with no owner and no claim to be a
|
|
55
64
|
# chapter has simply not been stamped yet — entity commands are in that state
|
|
56
65
|
# while entities are still IR objects — and answering the bare name would be a
|
|
57
66
|
# plausible half-truth that no test would notice. That shape of falsehood is
|
|
58
67
|
# what this repo keeps finding, so it goes red instead.
|
|
68
|
+
#
|
|
69
|
+
# @return [String] the fully-qualified name, joining every owner from the
|
|
70
|
+
# chapter down to this construct
|
|
71
|
+
# @raise [Construct::Unowned] if this construct has no owner and is not itself
|
|
72
|
+
# a chapter (root)
|
|
59
73
|
def hecks_fqn
|
|
60
74
|
return hecks_name.to_s if hecks_root?
|
|
61
75
|
|