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
|
@@ -3,22 +3,24 @@ require "json"
|
|
|
3
3
|
|
|
4
4
|
module Hecks
|
|
5
5
|
module Bluebook
|
|
6
|
-
# Judges a bluebook by
|
|
6
|
+
# Judges a bluebook by dispatching it into the language declared in itself.
|
|
7
7
|
#
|
|
8
|
-
# `lib/hecks/language/bluebook/` declares what a bluebook
|
|
8
|
+
# `lib/hecks/language/bluebook/` declares what a bluebook is —
|
|
9
9
|
# Chapter, Root, Verb, Shape, Ask, Piece, and the rest, split across files
|
|
10
10
|
# by domain concept and merged into one chapter at load time (see
|
|
11
11
|
# GRAMMAR_FILES below). This replays a built IR into that domain and turns
|
|
12
12
|
# any refusal into a Malformed, so the meta-domain is what actually judges
|
|
13
13
|
# rather than a description sitting beside the code — for whatever rules
|
|
14
14
|
# it carries. `spec/meta_rules_spec.rb`'s own header names the plan: port
|
|
15
|
-
# the language's rules
|
|
15
|
+
# the language's rules out of builder `raise Malformed` calls and into
|
|
16
16
|
# `given`/`invariant` here, where they are declarations any reader of the
|
|
17
17
|
# meta-domain can consume instead of behavior buried in a builder.
|
|
18
18
|
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
19
|
+
# ## This migration is partial, not done
|
|
20
|
+
#
|
|
21
|
+
# As of this writing the meta-domain declares 62 given/invariant/ensures
|
|
22
|
+
# rules (`Hecks::QueryIR.collect_rules` against
|
|
23
|
+
# `grammar_registry.bluebook("Bluebook")` enumerates them) —
|
|
22
24
|
# `spec/meta_rule_reachability_spec.rb` is what proves, per declaration,
|
|
23
25
|
# not per verb, that most of them still lack a spec exercising the
|
|
24
26
|
# refusal at all (see that file's own KNOWN_GAPS for the current count).
|
|
@@ -35,17 +37,18 @@ module Hecks
|
|
|
35
37
|
# So: "delete language/bluebook/ and validation stops" is true for the 62
|
|
36
38
|
# rules actually declared here, and false for whatever a builder's own
|
|
37
39
|
# `raise Malformed` still checks — the language does not yet own its own
|
|
38
|
-
# enforcement end to end
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
#
|
|
40
|
+
# enforcement end to end. The self-hosting mechanism itself is real and
|
|
41
|
+
# is the point worth keeping : a self-description that only describes is
|
|
42
|
+
# indistinguishable from enforcement, and the first version of this file
|
|
43
|
+
# was deleted for exactly that reason. What is not yet real is that
|
|
44
|
+
# self-hosting being the whole of validation.
|
|
45
|
+
#
|
|
46
|
+
# ## Isolation
|
|
44
47
|
#
|
|
45
|
-
# The meta-domain is loaded
|
|
48
|
+
# The meta-domain is loaded once and its registry reused ; each bluebook is
|
|
46
49
|
# judged in a fresh in-memory store so no domain can see another's records.
|
|
47
50
|
module MetaValidator
|
|
48
|
-
#
|
|
51
|
+
# **The folder is the chapter**. Files are grouped by the domain concept they
|
|
49
52
|
# describe and every one reopens the same `Hecks.bluebook "Bluebook"`.
|
|
50
53
|
# `BluebookBuilder.build` keeps one builder open per chapter name across
|
|
51
54
|
# calls, so the sorted folder accumulates one domain. Adding or renaming a
|
|
@@ -67,25 +70,25 @@ module Hecks
|
|
|
67
70
|
# TranslationJudge.
|
|
68
71
|
TRANSLATION_GRAMMAR = Dir.glob(File.expand_path("../language/translation/*.bluebook", __dir__)).freeze
|
|
69
72
|
|
|
70
|
-
# ADR 0026's
|
|
73
|
+
# ADR 0026's own seam: the core does not name its extension points.
|
|
71
74
|
#
|
|
72
|
-
# A sub-language chapter (Paging, so far the only one) is an
|
|
75
|
+
# A sub-language chapter (Paging, so far the only one) is an ordinary
|
|
73
76
|
# bluebook — declared with the same `aggregate`/`value_object`/
|
|
74
77
|
# `attaches_to` words every domain has, judged through the language
|
|
75
78
|
# the normal way, not bootstrapped raw the way GRAMMAR_FILES is. What
|
|
76
|
-
# makes it special is only where it
|
|
79
|
+
# makes it special is only where it lives: any file in this directory
|
|
77
80
|
# is discovered and loaded here, by the directory's own existence,
|
|
78
81
|
# never by a name this file would have to know. Add a chapter here
|
|
79
82
|
# and it is attached ; nothing in this file changes.
|
|
80
83
|
ATTACHED_GRAMMAR_DIR = File.expand_path("../language/bluebook/attaches", __dir__).freeze
|
|
81
84
|
|
|
82
|
-
# The chapters that
|
|
85
|
+
# The chapters that are the language — loaded raw during bootstrap, then
|
|
83
86
|
# judged through themselves and replaced by their own assembled graphs
|
|
84
87
|
# (see grammar_registry). Each is named after its file : Bluebook describes
|
|
85
88
|
# bluebooks (language/bluebook/) ; World describes worlds (world.bluebook),
|
|
86
89
|
# and backs the WorldJudge door ; Hecksagon describes hecksagons
|
|
87
90
|
# (hecksagon.bluebook) — declared for the same self-description reasons as
|
|
88
|
-
# World, but
|
|
91
|
+
# World, but without a judge door of its own : nothing dispatches a real
|
|
89
92
|
# .hecksagon file through it yet, so HecksagonBuilder's own behavior is
|
|
90
93
|
# unchanged. What this buys is what syntax.bluebook needed — a real shape
|
|
91
94
|
# `subscribe`'s `fills: "subscriptions"` can point at — not new validation
|
|
@@ -94,18 +97,21 @@ module Hecks
|
|
|
94
97
|
|
|
95
98
|
# The meta-domain is itself a bluebook. Judging it while loading it would
|
|
96
99
|
# recurse, so the load path marks the bootstrap and skips — but the skip
|
|
97
|
-
# is only the
|
|
100
|
+
# is only the first pass. Once every grammar file is loaded and merged,
|
|
98
101
|
# grammar_registry judges the language through itself and keeps the
|
|
99
102
|
# assembled result (the fixpoint, made load-bearing).
|
|
103
|
+
#
|
|
104
|
+
# @return [Boolean] whether the language's own grammar is still
|
|
105
|
+
# loading raw, unjudged
|
|
100
106
|
def self.bootstrapping? = @bootstrapping
|
|
101
107
|
|
|
102
|
-
# A
|
|
108
|
+
# A chapter may be split across files, so it cannot be judged until
|
|
103
109
|
# every file has been read.
|
|
104
110
|
#
|
|
105
|
-
# `BluebookBuilder.build` already
|
|
111
|
+
# `BluebookBuilder.build` already merges — `registry.bluebook_builder
|
|
106
112
|
# (name)` memoises one builder per chapter name, so nine files each
|
|
107
113
|
# saying `Hecks.bluebook "Bluebook"` accumulate into one. What it
|
|
108
|
-
# also does is call `MetaValidator.call` once
|
|
114
|
+
# also does is call `MetaValidator.call` once per file, judging a
|
|
109
115
|
# chapter that is still eight files short: `Aggregate`'s reference
|
|
110
116
|
# to `Bluebook` dangles because `Bluebook` has not been declared
|
|
111
117
|
# yet, and the load dies.
|
|
@@ -119,12 +125,21 @@ module Hecks
|
|
|
119
125
|
# once, before hecksagons and worlds load (DOMAIN_ORDER already
|
|
120
126
|
# puts every chapter ahead of those).
|
|
121
127
|
#
|
|
122
|
-
# Only chapters
|
|
128
|
+
# Only chapters declared inside the window are judged afterwards.
|
|
123
129
|
# Re-judging one already assembled — a framework member pulled in
|
|
124
130
|
# earlier by `uses_framework`, say — would re-run Assembly and hand
|
|
125
131
|
# out a second set of classes for a graph something already holds.
|
|
132
|
+
#
|
|
133
|
+
# @return [Boolean] whether `call` is currently queuing chapters
|
|
134
|
+
# instead of judging them
|
|
126
135
|
def self.deferring? = @deferring
|
|
127
136
|
|
|
137
|
+
# Opens the two-phase-load window: every chapter `call` sees while
|
|
138
|
+
# the block runs is queued (see `deferred_chapters`) rather than
|
|
139
|
+
# judged immediately.
|
|
140
|
+
#
|
|
141
|
+
# @yield the caller's own load of every file in one chapter window
|
|
142
|
+
# @return [Object] the block's own return value
|
|
128
143
|
def self.defer
|
|
129
144
|
previous = @deferring
|
|
130
145
|
@deferring = true
|
|
@@ -133,8 +148,22 @@ module Hecks
|
|
|
133
148
|
@deferring = previous
|
|
134
149
|
end
|
|
135
150
|
|
|
151
|
+
# The chapters queued while `defer`'s block ran, awaiting
|
|
152
|
+
# `judge_deferred!`.
|
|
153
|
+
#
|
|
154
|
+
# @return [Array<String>] each deferred chapter's own `hecks_name`,
|
|
155
|
+
# queued during the current or most recent `defer` window
|
|
136
156
|
def self.deferred_chapters = @deferred_chapters ||= []
|
|
137
157
|
|
|
158
|
+
# Judges every chapter queued by `defer`, once each, then clears the
|
|
159
|
+
# queue.
|
|
160
|
+
#
|
|
161
|
+
# @param registry [Runtime::Registry, nil] the registry to judge
|
|
162
|
+
# against; a no-op if `nil`
|
|
163
|
+
# @return [void]
|
|
164
|
+
# @raise [DSL::Malformed] if a chapter's own whole-chapter battery
|
|
165
|
+
# (`BluebookBuilder.validate_assembled!`) or the meta-domain itself
|
|
166
|
+
# (`call`) refuses it
|
|
138
167
|
def self.judge_deferred!(registry)
|
|
139
168
|
pending = deferred_chapters.uniq
|
|
140
169
|
@deferred_chapters = []
|
|
@@ -144,18 +173,18 @@ module Hecks
|
|
|
144
173
|
chapter = registry.bluebook(name)
|
|
145
174
|
next unless chapter
|
|
146
175
|
|
|
147
|
-
# A bare chapter-given left
|
|
176
|
+
# A bare chapter-given left pending by any file of this
|
|
148
177
|
# chapter (`AggregateBuilder#pending_chapter_given`) resolves
|
|
149
178
|
# first — before anything below reads a `Given`'s fields.
|
|
150
|
-
# `registry.bluebook_builder(name)` is the
|
|
179
|
+
# `registry.bluebook_builder(name)` is the same instance every
|
|
151
180
|
# one of this chapter's own files built onto (`#self.build`'s
|
|
152
181
|
# own comment); it is guaranteed already open here, since it
|
|
153
182
|
# is what produced `chapter` in the first place — the block is
|
|
154
183
|
# dead code, never actually invoked.
|
|
155
184
|
builder = registry.bluebook_builder(name) { raise "internal: no open builder for #{name}" }
|
|
156
185
|
builder.resolve_pending_chapter_givens!
|
|
157
|
-
#
|
|
158
|
-
# same timing: a bare entity-level given left
|
|
186
|
+
# The entity-scoped analogue, one level down — same reason,
|
|
187
|
+
# same timing: a bare entity-level given left pending by any
|
|
159
188
|
# file of this chapter (`EntityBuilder#pending_chapter_entity_
|
|
160
189
|
# given`) must resolve before anything below reads a piece's
|
|
161
190
|
# own `Given` fields too.
|
|
@@ -163,11 +192,11 @@ module Hecks
|
|
|
163
192
|
|
|
164
193
|
# `BluebookBuilder#build` skipped its own whole-chapter battery
|
|
165
194
|
# (hops, projected fields, correlation keys, event shapes,
|
|
166
|
-
# `with:` projections) for every file of
|
|
195
|
+
# `with:` projections) for every file of this chapter while
|
|
167
196
|
# `deferring?` was true, the same reason `call` below queued
|
|
168
197
|
# instead of judging — each of those checks needs every file
|
|
169
198
|
# loaded first (see `BluebookBuilder.validate_assembled!`'s own
|
|
170
|
-
# comment). `chapter` here is exactly that: whatever the
|
|
199
|
+
# comment). `chapter` here is exactly that: whatever the last
|
|
171
200
|
# file's own `add_bluebook` left in the registry, which by now
|
|
172
201
|
# holds every aggregate/policy/process_manager the whole
|
|
173
202
|
# chapter declares. Run once, here, instead of once per file.
|
|
@@ -178,39 +207,44 @@ module Hecks
|
|
|
178
207
|
|
|
179
208
|
# `&& !@forcing_fixpoint` — see `while_forcing_fixpoint` below, whose own
|
|
180
209
|
# window must win even while a growth spec's `while_disabled` is open,
|
|
181
|
-
# for the reason recorded there.
|
|
182
|
-
# `while_shadow_parsing`/`while_forcing_fixpoint` use, not
|
|
183
|
-
#
|
|
184
|
-
#
|
|
185
|
-
#
|
|
186
|
-
#
|
|
187
|
-
#
|
|
188
|
-
#
|
|
189
|
-
#
|
|
190
|
-
#
|
|
191
|
-
#
|
|
192
|
-
#
|
|
193
|
-
#
|
|
194
|
-
#
|
|
195
|
-
# disabled-validation window raced the
|
|
210
|
+
# for the reason recorded there. Uses the same stack-restore shape
|
|
211
|
+
# `while_shadow_parsing`/`while_forcing_fixpoint` use, deliberately not
|
|
212
|
+
# a bare env toggle (`ENV["HECKS_META_VALIDATION"] == "off"`, read
|
|
213
|
+
# directly, with no `previous`/`ensure` of its own): the gap between
|
|
214
|
+
# "bare toggle" and "stack-restore" is not cosmetic — a test's
|
|
215
|
+
# temporary window could reach code it was never meant to touch. If
|
|
216
|
+
# `grammar_registry`'s one-time lazy build (below) happens to land
|
|
217
|
+
# inside that window, every language chapter gets cached in its raw,
|
|
218
|
+
# never-judged form for the rest of the process — `unmark_scalar`'s
|
|
219
|
+
# String->Integer/Boolean fix (assembly/marks.rb) never runs, so a
|
|
220
|
+
# `Command`'s own `required: true` stays `required: "true"` forever
|
|
221
|
+
# after, permanently memoized. Found live: an intermittent,
|
|
222
|
+
# parallel_rspec-only ir_golden_spec.rb failure, order-dependent on
|
|
223
|
+
# whether identifier_numeric_coercion_growth_spec.rb's
|
|
224
|
+
# disabled-validation window raced the one lazy build in its own worker
|
|
196
225
|
# process — reproduced in isolation by disabling validation before the
|
|
197
226
|
# first `grammar_registry` call. `&& !@forcing_fixpoint` was the first
|
|
198
|
-
# fix and is kept ;
|
|
199
|
-
# the gap for every
|
|
200
|
-
# race that was actually observed — nothing outside
|
|
201
|
-
# `ENV["HECKS_META_VALIDATION"]`
|
|
202
|
-
#
|
|
203
|
-
#
|
|
204
|
-
#
|
|
227
|
+
# fix and is kept ; `@disabled` itself uses this same stack-restore
|
|
228
|
+
# shape to close the gap for every other caller of `while_disabled`,
|
|
229
|
+
# not just the one race that was actually observed — nothing outside
|
|
230
|
+
# this file reads `ENV["HECKS_META_VALIDATION"]` (every growth spec
|
|
231
|
+
# calls `while_disabled` instead), so there is no bare global left to
|
|
232
|
+
# race.
|
|
233
|
+
#
|
|
234
|
+
# @return [Boolean] whether meta-domain judging is currently switched
|
|
235
|
+
# off (and not overridden by a fixpoint build in progress)
|
|
205
236
|
def self.disabled? = @disabled && !@forcing_fixpoint
|
|
206
237
|
|
|
207
|
-
#
|
|
208
|
-
# fixpoint`
|
|
238
|
+
# The same stack-restore shape `while_shadow_parsing`/`while_forcing_
|
|
239
|
+
# fixpoint` use. This toggle's real, intended use is a growth spec
|
|
209
240
|
# that boots a scratch bluebook from a tempfile and wants the runtime
|
|
210
241
|
# behaviour without the validation overhead ; that is always a single
|
|
211
242
|
# bounded window around one boot, never a flag meant to survive past
|
|
212
243
|
# it, so the flag itself is scoped in the same `previous`/`ensure`
|
|
213
244
|
# shape rather than a plain assignment a caller could forget to undo.
|
|
245
|
+
#
|
|
246
|
+
# @yield the caller's own boot, with `disabled?` true throughout
|
|
247
|
+
# @return [Object] the block's own return value
|
|
214
248
|
def self.while_disabled
|
|
215
249
|
previous = @disabled
|
|
216
250
|
@disabled = true
|
|
@@ -220,23 +254,29 @@ module Hecks
|
|
|
220
254
|
end
|
|
221
255
|
|
|
222
256
|
# ADR 0025's own prerequisite (docs/dsl-work-slices.md, S0a): a word
|
|
223
|
-
# a later slice removes from the
|
|
224
|
-
#
|
|
257
|
+
# a later slice removes from the live grammar must still parse
|
|
258
|
+
# frozen era text — `EraGuard.shadow_parse` (runtime/era_guard.rb)
|
|
225
259
|
# is a plain `Kernel.eval` of stored source, run at boot, at mint,
|
|
226
260
|
# and during tamper detection, against whatever grammar is live
|
|
227
|
-
#
|
|
261
|
+
# today, not whatever grammar was live when that text was written.
|
|
228
262
|
# Judging it again here would refuse history the day a spelling it
|
|
229
|
-
# used is removed — proved with a rule that already lives
|
|
263
|
+
# used is removed — proved with a rule that already lives only in
|
|
230
264
|
# the meta-domain, never duplicated as a builder's own `raise
|
|
231
265
|
# Malformed` (`vision`'s own comment: "moved to the language").
|
|
232
266
|
#
|
|
233
|
-
# Mirrors `defer`'s own stack-restore shape
|
|
234
|
-
#
|
|
235
|
-
#
|
|
236
|
-
#
|
|
237
|
-
#
|
|
267
|
+
# Mirrors `defer`'s own stack-restore shape — this must never leak
|
|
268
|
+
# past the one shadow-parse call that set it, the same reason
|
|
269
|
+
# `ConstShim.with`/`.active?` (bluebook/dsl/const_shim.rb) restores in
|
|
270
|
+
# an `ensure` rather than being flipped and left.
|
|
271
|
+
#
|
|
272
|
+
# @return [Boolean] whether frozen era text is currently being
|
|
273
|
+
# shadow-parsed
|
|
238
274
|
def self.shadow_parsing? = @shadow_parsing
|
|
239
275
|
|
|
276
|
+
# Wraps `block` with `shadow_parsing?` true, restoring it afterward.
|
|
277
|
+
#
|
|
278
|
+
# @yield the caller's own shadow-parse of one piece of frozen era text
|
|
279
|
+
# @return [Object] the block's own return value
|
|
240
280
|
def self.while_shadow_parsing
|
|
241
281
|
previous = @shadow_parsing
|
|
242
282
|
@shadow_parsing = true
|
|
@@ -245,13 +285,17 @@ module Hecks
|
|
|
245
285
|
@shadow_parsing = previous
|
|
246
286
|
end
|
|
247
287
|
|
|
248
|
-
#
|
|
288
|
+
# The same stack-restore shape `while_shadow_parsing` uses, for the
|
|
249
289
|
# same reason: whatever this wraps must never see `disabled?` answer
|
|
250
|
-
# true, however a test elsewhere has
|
|
251
|
-
# exact moment. Only `grammar_registry`'s own one-time build
|
|
252
|
-
# wraps itself in this — nothing else needs it, and nothing
|
|
253
|
-
# should reach for it just to dodge `disabled?` for a domain
|
|
290
|
+
# true, however a test elsewhere has a `while_disabled` window open at
|
|
291
|
+
# that exact moment. Only `grammar_registry`'s own one-time build
|
|
292
|
+
# (below) wraps itself in this — nothing else needs it, and nothing
|
|
293
|
+
# else should reach for it just to dodge `disabled?` for a domain
|
|
254
294
|
# bluebook, which is precisely the toggle's real, intended use.
|
|
295
|
+
#
|
|
296
|
+
# @yield the one-time fixpoint build, with `disabled?` forced false
|
|
297
|
+
# throughout
|
|
298
|
+
# @return [Object] the block's own return value
|
|
255
299
|
def self.while_forcing_fixpoint
|
|
256
300
|
previous = @forcing_fixpoint
|
|
257
301
|
@forcing_fixpoint = true
|
|
@@ -262,11 +306,21 @@ module Hecks
|
|
|
262
306
|
|
|
263
307
|
# The same bluebook judged twice gets the same verdict, and a suite reloads
|
|
264
308
|
# its fixtures constantly — banking alone is ~200 dispatches per build.
|
|
265
|
-
# Keyed on the IR itself, so a
|
|
309
|
+
# Keyed on the IR itself, so a changed bluebook is always re-judged.
|
|
310
|
+
#
|
|
311
|
+
# @return [Hash{String => Array<String>}] the process-wide judging
|
|
312
|
+
# cache, keyed by a SHA-256 digest of the judged artifact; each
|
|
313
|
+
# value is that artifact's own list of refusal messages (`[]` when
|
|
314
|
+
# well formed)
|
|
266
315
|
def self.verdicts = @verdicts ||= {}
|
|
267
316
|
|
|
268
317
|
# A world is not a bluebook, so it gets its own door. Same judge, same
|
|
269
318
|
# meta-domain registry — a different artifact and a different language file.
|
|
319
|
+
#
|
|
320
|
+
# @param world [Bluebook::World] the world to judge
|
|
321
|
+
# @return [Bluebook::World] `world` unchanged, if well formed or
|
|
322
|
+
# while disabled/bootstrapping/shadow-parsing
|
|
323
|
+
# @raise [DSL::Malformed] if `WorldJudge` finds `world` malformed
|
|
270
324
|
def self.call_world(world)
|
|
271
325
|
return world if disabled? || bootstrapping? || shadow_parsing?
|
|
272
326
|
|
|
@@ -281,6 +335,11 @@ module Hecks
|
|
|
281
335
|
# A port is not a bluebook either — same door shape as call_world,
|
|
282
336
|
# one artifact over. Whole-project table-unification survey, item
|
|
283
337
|
# #13's remaining builders.
|
|
338
|
+
#
|
|
339
|
+
# @param port [Bluebook::Port] the port to judge
|
|
340
|
+
# @return [Bluebook::Port] `port` unchanged, if well formed or while
|
|
341
|
+
# disabled/bootstrapping/shadow-parsing
|
|
342
|
+
# @raise [DSL::Malformed] if `PortJudge` finds `port` malformed
|
|
284
343
|
def self.call_port(port)
|
|
285
344
|
return port if disabled? || bootstrapping? || shadow_parsing?
|
|
286
345
|
|
|
@@ -295,6 +354,11 @@ module Hecks
|
|
|
295
354
|
# An adapter is not a bluebook either — same door shape, one more
|
|
296
355
|
# artifact over. Whole-project table-unification survey, item
|
|
297
356
|
# #13's remaining builders.
|
|
357
|
+
#
|
|
358
|
+
# @param adapter [Bluebook::Adapter] the adapter to judge
|
|
359
|
+
# @return [Bluebook::Adapter] `adapter` unchanged, if well formed or
|
|
360
|
+
# while disabled/bootstrapping/shadow-parsing
|
|
361
|
+
# @raise [DSL::Malformed] if `AdapterJudge` finds `adapter` malformed
|
|
298
362
|
def self.call_adapter(adapter)
|
|
299
363
|
return adapter if disabled? || bootstrapping? || shadow_parsing?
|
|
300
364
|
|
|
@@ -309,14 +373,20 @@ module Hecks
|
|
|
309
373
|
# A translation is not a bluebook either — same door shape, one more
|
|
310
374
|
# artifact over (a `translations/*.bluebook` edge — `data_translation`'s
|
|
311
375
|
# own real, established convention; there is no separate extension).
|
|
312
|
-
# TranslationJudge walks the
|
|
376
|
+
# TranslationJudge walks the whole built translation (every nested
|
|
313
377
|
# aggregate's own rule table) in one pass — only
|
|
314
378
|
# TranslationBuilder's own top-level `build` calls this;
|
|
315
379
|
# TranslationAggregateBuilder#build stays a plain struct constructor,
|
|
316
380
|
# the same way `WorldJudge` judges every `Wiring` a `.world` declares
|
|
317
|
-
# in
|
|
381
|
+
# in one pass over `World::World.Declare`'s own caller, not from a
|
|
318
382
|
# separate door per binding. Whole-project table-unification survey,
|
|
319
383
|
# item #13's remaining builders.
|
|
384
|
+
#
|
|
385
|
+
# @param translation [Bluebook::Translation] the translation to judge
|
|
386
|
+
# @return [Bluebook::Translation] `translation` unchanged, if well
|
|
387
|
+
# formed or while disabled/bootstrapping/shadow-parsing
|
|
388
|
+
# @raise [DSL::Malformed] if `TranslationJudge` finds `translation`
|
|
389
|
+
# malformed
|
|
320
390
|
def self.call_translation(translation)
|
|
321
391
|
return translation if disabled? || bootstrapping? || shadow_parsing?
|
|
322
392
|
|
|
@@ -337,55 +407,54 @@ module Hecks
|
|
|
337
407
|
"#{translation.domain}'s translation is not well formed; #{refusals.join('; ')}"
|
|
338
408
|
end
|
|
339
409
|
|
|
340
|
-
#
|
|
341
|
-
#
|
|
342
|
-
#
|
|
343
|
-
# in, collect refusals, throw the records away — which is all
|
|
344
|
-
#
|
|
345
|
-
# meta-domain
|
|
346
|
-
# builder's own object graph
|
|
347
|
-
# it.
|
|
348
|
-
#
|
|
349
|
-
#
|
|
350
|
-
#
|
|
351
|
-
#
|
|
352
|
-
#
|
|
353
|
-
# What is
|
|
354
|
-
# classes, so a second load of the same chapter re-assembles
|
|
355
|
-
#
|
|
356
|
-
# expect. Caching the graph would hand two
|
|
357
|
-
#
|
|
358
|
-
#
|
|
359
|
-
#
|
|
360
|
-
#
|
|
361
|
-
#
|
|
362
|
-
#
|
|
363
|
-
#
|
|
364
|
-
#
|
|
365
|
-
#
|
|
366
|
-
#
|
|
367
|
-
#
|
|
368
|
-
#
|
|
369
|
-
#
|
|
370
|
-
#
|
|
371
|
-
#
|
|
372
|
-
#
|
|
373
|
-
#
|
|
374
|
-
#
|
|
375
|
-
#
|
|
376
|
-
# `
|
|
377
|
-
#
|
|
378
|
-
# THIS mechanism (`option_rows`/`filter_options` in meta_validator/
|
|
379
|
-
# readings.rb read `node.wheres`/`node.order_by`/`node.limit` off the
|
|
380
|
-
# live object directly, never off `to_h`), so extending `to_h` changed
|
|
381
|
-
# nothing here. `ReadModel#to_h` now spells all three explicitly, the
|
|
382
|
-
# same mechanism `Query#to_h` already used — purely additive, still
|
|
410
|
+
# The language hands the graph back.
|
|
411
|
+
#
|
|
412
|
+
# A bluebook judged elsewhere only checks: dispatch every declaration
|
|
413
|
+
# in, collect refusals, throw the records away — which is all a
|
|
414
|
+
# boundary check needs. This is the one call that returns what the
|
|
415
|
+
# meta-domain holds instead, assembled into the graph the runtime
|
|
416
|
+
# runs, so the builder's own object graph exists only to be
|
|
417
|
+
# dispatched — nothing keeps it. `Hecks.bluebook` registers whatever
|
|
418
|
+
# comes back from here, so this one line is the difference between a
|
|
419
|
+
# language that checks a domain and a language that is the source of
|
|
420
|
+
# one: the runtime runs what the meta-domain holds, not the builder's
|
|
421
|
+
# own graph.
|
|
422
|
+
#
|
|
423
|
+
# What is cached is the declarations, not the graph. A hash carries no
|
|
424
|
+
# Ruby classes, so a second load of the same chapter re-assembles
|
|
425
|
+
# fresh ones — the behaviour `Namespace.install` and
|
|
426
|
+
# `spec/construct_spec` both expect. Caching the graph would hand two
|
|
427
|
+
# boots the same classes.
|
|
428
|
+
#
|
|
429
|
+
# One belief stayed unlanded for a while, worth naming because it
|
|
430
|
+
# looked so much like a wall: that the language may only hold what
|
|
431
|
+
# `to_h` carries. `ReadModel#to_h` omitted a read model's filters
|
|
432
|
+
# until 2026-08-11, so read-model filtering seemed impossible to read
|
|
433
|
+
# back — and hoisted policies lost which head declared them for the
|
|
434
|
+
# same reason. But `to_h` is a projection and the language is the
|
|
435
|
+
# source. They must agree about everything `to_h` spells ; they need
|
|
436
|
+
# not be the same size. Both were held even before the wire format
|
|
437
|
+
# carried them, as declarations the wire format didn't yet see.
|
|
438
|
+
#
|
|
439
|
+
# The wire format did later move, for a reason unrelated to this
|
|
440
|
+
# file — a Rust-codegen task needed `wheres`/`order_by`/`limit` on
|
|
441
|
+
# the wire to compile a read model's real declared filtering, and the
|
|
442
|
+
# boundary described above was never load-bearing for this mechanism
|
|
443
|
+
# (`option_rows`/`filter_options` in meta_validator/readings.rb read
|
|
444
|
+
# `node.wheres`/`node.order_by`/`node.limit` off the live object
|
|
445
|
+
# directly, never off `to_h`), so extending `to_h` changed nothing
|
|
446
|
+
# here. `ReadModel#to_h` now spells all three explicitly, the same
|
|
447
|
+
# mechanism `Query#to_h` already used — purely additive, still
|
|
383
448
|
# agreeing with the language about everything it spells.
|
|
384
449
|
#
|
|
385
|
-
#
|
|
386
|
-
#
|
|
387
|
-
#
|
|
388
|
-
#
|
|
450
|
+
# @param bluebook [Object] a built bluebook chapter graph (an
|
|
451
|
+
# `Aggregate`/`Entity`/`ValueObject`/... instance from
|
|
452
|
+
# `lib/hecks/bluebook/`), answering `to_h` and `hecks_name`
|
|
453
|
+
# @return [Object] `bluebook` unchanged while disabled, bootstrapping,
|
|
454
|
+
# shadow-parsing, or deferring; otherwise the graph the meta-domain
|
|
455
|
+
# assembles from its own judged declarations
|
|
456
|
+
# @raise [DSL::Malformed] if the meta-domain refuses any of
|
|
457
|
+
# `bluebook`'s declarations
|
|
389
458
|
def self.call(bluebook)
|
|
390
459
|
return bluebook if disabled? || bootstrapping? || shadow_parsing?
|
|
391
460
|
|
|
@@ -405,9 +474,16 @@ module Hecks
|
|
|
405
474
|
Assembly.call(held[:declaration])
|
|
406
475
|
end
|
|
407
476
|
|
|
408
|
-
# Dispatch it in and
|
|
477
|
+
# Dispatch it in and read it back. A refused chapter has no declarations to
|
|
409
478
|
# read — the records are half-written by definition — so it carries refusals
|
|
410
479
|
# and nothing else.
|
|
480
|
+
#
|
|
481
|
+
# @param bluebook [Object] a built bluebook chapter graph, as `call`
|
|
482
|
+
# receives it
|
|
483
|
+
# @return [Hash{Symbol => Object}] `{refusals: [...]}` when `Judge`
|
|
484
|
+
# refuses any declaration; otherwise `{refusals: [],
|
|
485
|
+
# declaration: Hash}`, the assembled graph `Reconstruction.of` reads
|
|
486
|
+
# back from the judged records
|
|
411
487
|
def self.hold(bluebook)
|
|
412
488
|
judge = Judge.new(bluebook)
|
|
413
489
|
return { refusals: judge.refusals } unless judge.refusals.empty?
|
|
@@ -415,52 +491,57 @@ module Hecks
|
|
|
415
491
|
{ refusals: [], declaration: Reconstruction.of(judge.runtime, bluebook.hecks_name) }
|
|
416
492
|
end
|
|
417
493
|
|
|
494
|
+
# The booted, self-judged language registry every ordinary bluebook is
|
|
495
|
+
# judged against — built once per process and memoized.
|
|
496
|
+
#
|
|
497
|
+
# @return [Runtime::Registry] the booted, fixpoint-judged language
|
|
498
|
+
# registry
|
|
418
499
|
def self.grammar_registry
|
|
419
500
|
@grammar_registry ||= begin
|
|
420
501
|
registry = load_grammar_into(Runtime::Registry.new)
|
|
421
|
-
# Assigned
|
|
502
|
+
# Assigned before the fixpoint judge below: judging re-enters
|
|
422
503
|
# grammar_registry through fresh_runtime (judge.rb) and Plan.for
|
|
423
504
|
# (judge.rb, reconstruction.rb) — a bare ||= would still be nil
|
|
424
505
|
# while its right-hand side evaluates, and recurse forever. That
|
|
425
|
-
# reentrancy window is real: a caller landing here
|
|
426
|
-
# fixpoint/attach below have run sees the
|
|
506
|
+
# reentrancy window is real: a caller landing here before the
|
|
507
|
+
# fixpoint/attach below have run sees the same registry object,
|
|
427
508
|
# correctly, but one still missing the attached chapters (Paging's
|
|
428
509
|
# `attaches_to` among them) — see grammar_registry_ready? below.
|
|
429
510
|
@grammar_registry = registry
|
|
430
|
-
#
|
|
511
|
+
# **The fixpoint made load-bearing**. The bootstrap loaded the language
|
|
431
512
|
# raw ; now the language judges itself, its records are read back,
|
|
432
|
-
# and the
|
|
513
|
+
# and the assembled graph replaces the raw one — so every bluebook
|
|
433
514
|
# judged from here on is judged by the language the language itself
|
|
434
515
|
# produced. Outside load_grammar_into on purpose : its ensure clears
|
|
435
516
|
# @bootstrapping, and call() must see bootstrapping? == false to do
|
|
436
517
|
# anything at all. `while_forcing_fixpoint`-wrapped so a growth
|
|
437
518
|
# spec's own `while_disabled` window can never leave this
|
|
438
|
-
#
|
|
519
|
+
# one-time build cached in its raw, never-judged form — see
|
|
439
520
|
# `disabled?`'s own comment.
|
|
440
521
|
while_forcing_fixpoint do
|
|
441
522
|
LANGUAGE_CHAPTERS.each { |name| registry.add_bluebook(call(registry.bluebook(name))) }
|
|
442
523
|
load_attached_grammar_into(registry)
|
|
443
524
|
end
|
|
444
|
-
# Stamped
|
|
525
|
+
# Stamped last, keyed by this registry's own identity rather than
|
|
445
526
|
# a bare boolean — a manual reset (fixpoint_spec.rb's own
|
|
446
527
|
# `@grammar_registry = nil`) makes @grammar_registry not equal
|
|
447
528
|
# this object_id again until a fresh build finishes, so a stale
|
|
448
|
-
# "ready" from the
|
|
529
|
+
# "ready" from the previous cycle can never leak into the next.
|
|
449
530
|
@grammar_ready_for = registry.object_id
|
|
450
531
|
registry
|
|
451
532
|
end
|
|
452
533
|
end
|
|
453
534
|
|
|
454
|
-
# A
|
|
535
|
+
# A reentrant call during the fixpoint/attach window above gets a
|
|
455
536
|
# real, correctly-mutating registry object back — no infinite loop,
|
|
456
|
-
# no wrong data for
|
|
457
|
-
#
|
|
537
|
+
# no wrong data for that caller's own purposes. But anything that
|
|
538
|
+
# memoizes a snapshot derived from it must not lock that snapshot
|
|
458
539
|
# in forever : this is one signal such a cache can check. Found
|
|
459
540
|
# live — SyntaxBoot.call had cached a Query keyword list missing
|
|
460
541
|
# every Paging-attached word (limit/offset/cursor/nulls) because
|
|
461
542
|
# something called it inside this exact window.
|
|
462
543
|
#
|
|
463
|
-
# SyntaxBoot.call
|
|
544
|
+
# SyntaxBoot.call no longer uses this. Gating its cache on "the
|
|
464
545
|
# whole registry is finished" meant nothing was cached for the
|
|
465
546
|
# entire window, and the window is not narrow — every word routed
|
|
466
547
|
# through `word_gate_dispatch` while the language judged itself
|
|
@@ -470,40 +551,52 @@ module Hecks
|
|
|
470
551
|
# the snapshot is a function of. Kept here for any other derived
|
|
471
552
|
# cache that genuinely needs "is the build finished" rather than
|
|
472
553
|
# "have my inputs changed".
|
|
554
|
+
#
|
|
555
|
+
# @return [Boolean] whether `grammar_registry`'s memoized singleton
|
|
556
|
+
# has finished its fixpoint judge and attached-chapter load
|
|
473
557
|
def self.grammar_registry_ready?
|
|
474
558
|
@grammar_registry && @grammar_ready_for == @grammar_registry.object_id
|
|
475
559
|
end
|
|
476
560
|
|
|
477
|
-
#
|
|
478
|
-
# they are declared
|
|
561
|
+
# Attached chapters load after the fixpoint, not during bootstrap —
|
|
562
|
+
# they are declared in the language the language just finished
|
|
479
563
|
# judging itself through, so they are ordinary bluebooks, judged the
|
|
480
564
|
# ordinary way (`Hecks.bluebook` → `BluebookBuilder#build` →
|
|
481
565
|
# `MetaValidator.call`, `bootstrapping?` already false). A directory
|
|
482
566
|
# with nothing in it loads nothing ; this is a no-op until a chapter
|
|
483
567
|
# is added there.
|
|
568
|
+
#
|
|
569
|
+
# @param registry [Runtime::Registry] the registry to load every
|
|
570
|
+
# `ATTACHED_GRAMMAR_DIR` chapter file into
|
|
571
|
+
# @return [void]
|
|
484
572
|
def self.load_attached_grammar_into(registry)
|
|
485
573
|
Hecks.with_registry(registry) do
|
|
486
574
|
Dir.glob(File.join(ATTACHED_GRAMMAR_DIR, "*.bluebook")).each { |file| Kernel.load(file) }
|
|
487
575
|
end
|
|
488
576
|
end
|
|
489
577
|
|
|
490
|
-
#
|
|
578
|
+
# The one place the grammar's own boot sequence is spelled — ports, the
|
|
491
579
|
# memory/prism adapters, the (now nine-file) chapter itself, then the
|
|
492
580
|
# sibling world grammar. `grammar_registry` uses this for its memoised
|
|
493
|
-
# singleton ; anything that needs an
|
|
581
|
+
# singleton ; anything that needs an isolated registry (a spec wanting a
|
|
494
582
|
# fresh store per example, say) calls this directly instead of hand-
|
|
495
583
|
# copying the sequence.
|
|
496
584
|
#
|
|
497
|
-
#
|
|
585
|
+
# The bootstrap guard lives here, not just around the singleton. Splitting
|
|
498
586
|
# the chapter into several files means each file's own `Hecks.bluebook
|
|
499
587
|
# "Bluebook"` call now runs `BluebookBuilder#build` once per file — and
|
|
500
588
|
# `MetaValidator.call` judges whatever it is handed unless `bootstrapping?`
|
|
501
589
|
# is true. A caller that loaded the grammar files by hand into its own
|
|
502
|
-
# registry, without this guard, would get each file
|
|
503
|
-
#
|
|
590
|
+
# registry, without this guard, would get each file dispatched and judged
|
|
591
|
+
# alone the moment it loaded — and a lone file like `aggregate.bluebook`
|
|
504
592
|
# refuses immediately, since `Aggregate.Attribute` references `ValueObject`
|
|
505
593
|
# and `Aggregate.Holds` references `Entity`, both declared in later files.
|
|
506
594
|
# Every caller of the grammar must go through here for exactly that reason.
|
|
595
|
+
#
|
|
596
|
+
# @param registry [Runtime::Registry] the registry to load the whole
|
|
597
|
+
# grammar (ports, adapters, and every language chapter) into, raw
|
|
598
|
+
# and unjudged
|
|
599
|
+
# @return [Runtime::Registry] `registry`, unchanged in identity
|
|
507
600
|
def self.load_grammar_into(registry)
|
|
508
601
|
@bootstrapping = true
|
|
509
602
|
Hecks.with_registry(registry) do
|
|
@@ -523,7 +616,7 @@ module Hecks
|
|
|
523
616
|
@bootstrapping = false
|
|
524
617
|
end
|
|
525
618
|
|
|
526
|
-
# A
|
|
619
|
+
# A fresh store per bluebook. The registry memoises repositories, so
|
|
527
620
|
# reusing it let every bluebook see the records of every bluebook judged
|
|
528
621
|
# before it. The parsed grammar is reused ; only the records are cleared.
|
|
529
622
|
# (During grammar_registry's own fixpoint judge this clear runs on the
|
|
@@ -532,6 +625,9 @@ module Hecks
|
|
|
532
625
|
# No `bind_runtime` here : judging dispatches by FQN and never opens the
|
|
533
626
|
# door, and binding would re-install the language's own facade constants
|
|
534
627
|
# once per judged chapter.
|
|
628
|
+
#
|
|
629
|
+
# @return [Runtime::Dispatcher] a dispatcher over the shared grammar
|
|
630
|
+
# registry, with its records cleared
|
|
535
631
|
def self.fresh_runtime
|
|
536
632
|
registry = grammar_registry
|
|
537
633
|
registry.instance_variable_set(:@repositories, {})
|