hecks 2.8.0 → 2.9.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/exe/hecks +4 -6
- data/lib/hecks/adapters/driven/claude_code.rb +4 -104
- data/lib/hecks/adapters/driven/d1.rb +44 -237
- data/lib/hecks/adapters/driven/folder.rb +17 -76
- data/lib/hecks/adapters/driven/google_authentication.rb +15 -49
- data/lib/hecks/adapters/driven/governance_authorization.rb +23 -70
- data/lib/hecks/adapters/driven/heki/journal.rb +8 -41
- data/lib/hecks/adapters/driven/heki/saga_store.rb +12 -54
- data/lib/hecks/adapters/driven/heki/snapshot.rb +4 -12
- data/lib/hecks/adapters/driven/heki.rb +13 -42
- data/lib/hecks/adapters/driven/identity_registry.rb +3 -14
- data/lib/hecks/adapters/driven/in_memory_ordering.rb +9 -26
- data/lib/hecks/adapters/driven/in_process_key_vault.rb +2 -14
- data/lib/hecks/adapters/driven/lambda/client.rb +10 -51
- data/lib/hecks/adapters/driven/lambda.rb +10 -84
- data/lib/hecks/adapters/driven/local_storage.rb +5 -40
- data/lib/hecks/adapters/driven/memory.rb +17 -98
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +5 -21
- data/lib/hecks/adapters/driven/postgres/codec.rb +6 -28
- data/lib/hecks/adapters/driven/postgres/outbox.rb +3 -12
- data/lib/hecks/adapters/driven/postgres/reconnect.rb +4 -30
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +34 -108
- data/lib/hecks/adapters/driven/postgres.rb +145 -134
- data/lib/hecks/adapters/driven/postgres_era.adapter +4 -15
- data/lib/hecks/adapters/driven/prism.rb +7 -30
- data/lib/hecks/adapters/driven/sql_query_builder.rb +21 -121
- data/lib/hecks/adapters/driven/sqlite/codec.rb +8 -40
- data/lib/hecks/adapters/driven/sqlite/projection.rb +26 -82
- data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +40 -84
- data/lib/hecks/adapters/driven/sqlite.rb +128 -65
- data/lib/hecks/adapters/driven/tenant_provisioner.rb +5 -48
- data/lib/hecks/adapters/driven.rb +5 -36
- data/lib/hecks/adapters/driving/github_webhook.rb +8 -76
- data/lib/hecks/behaviors/dsl.rb +7 -25
- data/lib/hecks/behaviors/expectations.rb +31 -141
- data/lib/hecks/behaviors/ir.rb +7 -20
- data/lib/hecks/behaviors/rspec.rb +6 -17
- data/lib/hecks/behaviors/runner.rb +10 -34
- data/lib/hecks/behaviors.rb +4 -8
- data/lib/hecks/bluebook/aggregate.rb +9 -75
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +9 -38
- data/lib/hecks/bluebook/assembly/build.rb +4 -15
- data/lib/hecks/bluebook/assembly/contract.rb +15 -136
- data/lib/hecks/bluebook/assembly/contracts.rb +54 -174
- data/lib/hecks/bluebook/assembly/marks.rb +31 -223
- data/lib/hecks/bluebook/assembly/specializer.rb +6 -52
- data/lib/hecks/bluebook/assembly.rb +6 -45
- data/lib/hecks/bluebook/attribute.rb +12 -61
- data/lib/hecks/bluebook/behaviour/aggregate.rb +10 -39
- data/lib/hecks/bluebook/behaviour/attribute.rb +3 -14
- data/lib/hecks/bluebook/behaviour/chapter.rb +14 -42
- data/lib/hecks/bluebook/behaviour/command.rb +14 -66
- data/lib/hecks/bluebook/behaviour/domain_port.rb +4 -20
- data/lib/hecks/bluebook/behaviour/entity.rb +7 -27
- data/lib/hecks/bluebook/behaviour/hexagon.rb +23 -41
- data/lib/hecks/bluebook/behaviour/lifecycle.rb +15 -40
- data/lib/hecks/bluebook/behaviour/policy.rb +23 -52
- data/lib/hecks/bluebook/behaviour/process_manager.rb +30 -57
- data/lib/hecks/bluebook/behaviour/read_model.rb +25 -31
- data/lib/hecks/bluebook/behaviour/traits.rb +27 -64
- data/lib/hecks/bluebook/behaviour/value_object.rb +5 -24
- data/lib/hecks/bluebook/capabilities.rb +17 -49
- data/lib/hecks/bluebook/chapter.rb +10 -48
- data/lib/hecks/bluebook/command.rb +23 -81
- data/lib/hecks/bluebook/domain_port.rb +14 -63
- data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +50 -229
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +50 -377
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +33 -204
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +16 -69
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +86 -708
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +56 -170
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +1 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +74 -546
- data/lib/hecks/bluebook/dsl/const_shim.rb +8 -41
- data/lib/hecks/bluebook/dsl/domain_port_builder.rb +12 -87
- data/lib/hecks/bluebook/dsl/entity_builder.rb +44 -330
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +20 -269
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +26 -194
- data/lib/hecks/bluebook/dsl/identity_declaration.rb +13 -88
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +6 -20
- data/lib/hecks/bluebook/dsl/policy_builder.rb +16 -88
- data/lib/hecks/bluebook/dsl/port_builder.rb +2 -6
- data/lib/hecks/bluebook/dsl/port_operation_builder.rb +22 -96
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +31 -184
- data/lib/hecks/bluebook/dsl/query_builder.rb +11 -42
- data/lib/hecks/bluebook/dsl/read_model_builder.rb +75 -201
- data/lib/hecks/bluebook/dsl/rule_reference.rb +22 -163
- data/lib/hecks/bluebook/dsl/translation_builder.rb +28 -114
- data/lib/hecks/bluebook/dsl/value_object_builder.rb +10 -124
- data/lib/hecks/bluebook/dsl/word_gate.rb +16 -162
- data/lib/hecks/bluebook/dsl/world_builder.rb +19 -111
- data/lib/hecks/bluebook/entity.rb +13 -71
- data/lib/hecks/bluebook/expression/ast_json.rb +24 -190
- data/lib/hecks/bluebook/expression/ast_reader.rb +12 -54
- data/lib/hecks/bluebook/expression/canonical_form.rb +11 -88
- data/lib/hecks/bluebook/expression/evaluator.rb +47 -295
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +30 -147
- data/lib/hecks/bluebook/expression/resolver.rb +37 -660
- data/lib/hecks/bluebook/hexagon.rb +5 -28
- data/lib/hecks/bluebook/lifecycle.rb +5 -16
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -7
- data/lib/hecks/bluebook/meta_validator/judge.rb +111 -361
- data/lib/hecks/bluebook/meta_validator/plan.rb +33 -162
- data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -7
- data/lib/hecks/bluebook/meta_validator/readings.rb +56 -342
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +24 -176
- data/lib/hecks/bluebook/meta_validator/shapes.rb +53 -267
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +43 -305
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +7 -43
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -18
- data/lib/hecks/bluebook/meta_validator.rb +79 -349
- data/lib/hecks/bluebook/model_check/client_profile.rb +6 -21
- data/lib/hecks/bluebook/model_check.rb +100 -597
- data/lib/hecks/bluebook/pattern_subset.rb +11 -69
- data/lib/hecks/bluebook/process_manager.rb +13 -83
- data/lib/hecks/bluebook/project_loader.rb +3 -39
- data/lib/hecks/bluebook/project_register.rb +12 -60
- data/lib/hecks/bluebook/query.rb +9 -48
- data/lib/hecks/bluebook/read_model.rb +57 -81
- data/lib/hecks/bluebook/reference.rb +7 -41
- data/lib/hecks/bluebook/smoke_test.rb +8 -98
- data/lib/hecks/bluebook/synthesizer.rb +13 -62
- data/lib/hecks/bluebook/translation.rb +26 -62
- data/lib/hecks/bluebook/value_object.rb +11 -36
- data/lib/hecks/bluebook.rb +5 -22
- data/lib/hecks/cache_dir.rb +4 -23
- data/lib/hecks/cli/document.rb +3 -21
- data/lib/hecks/cli/ir.rb +3 -5
- data/lib/hecks/cli/mcp.rb +2 -3
- data/lib/hecks/cli/mcp_door.rb +19 -114
- data/lib/hecks/cli/model_check.rb +18 -85
- data/lib/hecks/cli/project_cli.rb +7 -40
- data/lib/hecks/cli/project_diagrams.rb +0 -7
- data/lib/hecks/cli/run.rb +12 -58
- data/lib/hecks/cli/smoke_test.rb +2 -16
- data/lib/hecks/cli/stores.rb +1 -2
- data/lib/hecks/cli.rb +18 -24
- data/lib/hecks/construct.rb +8 -34
- data/lib/hecks/deploy/bluebook/deploy.bluebook +33 -142
- data/lib/hecks/deploy/bluebook/deploy.hecksagon +2 -9
- data/lib/hecks/embryonaut_bluebook/lock.rb +3 -35
- data/lib/hecks/embryonaut_bluebook/shape.rb +1 -17
- data/lib/hecks/embryonaut_bluebook/vendor.rb +8 -53
- data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +4 -19
- data/lib/hecks/embryonaut_bluebook.rb +4 -71
- data/lib/hecks/facade/cli_door.rb +24 -106
- data/lib/hecks/facade/cli_runner.rb +28 -172
- data/lib/hecks/facade/command_request.rb +13 -33
- data/lib/hecks/facade/handle.rb +34 -121
- data/lib/hecks/facade/json_door.rb +31 -146
- data/lib/hecks/facade/surface/aggregate_door.rb +39 -104
- data/lib/hecks/facade/surface/chapter.rb +10 -54
- data/lib/hecks/facade/surface.rb +8 -23
- data/lib/hecks/facade.rb +10 -25
- data/lib/hecks/forms/app.rb +15 -70
- data/lib/hecks/forms/command_form_renderer.rb +10 -29
- data/lib/hecks/forms/field_renderer.rb +17 -156
- data/lib/hecks/forms/field_shape.rb +30 -222
- data/lib/hecks/forms/html.rb +12 -47
- data/lib/hecks/forms/index_renderer.rb +1 -4
- data/lib/hecks/forms/page.rb +3 -9
- data/lib/hecks/forms/params.rb +14 -60
- data/lib/hecks/forms/port_argument.rb +2 -19
- data/lib/hecks/forms/query_form_renderer.rb +4 -79
- data/lib/hecks/forms/record_renderer.rb +8 -75
- data/lib/hecks/forms/record_table.rb +7 -50
- data/lib/hecks/forms/reference_options.rb +3 -30
- data/lib/hecks/forms/value_object_shape.rb +8 -35
- data/lib/hecks/forms.rb +5 -33
- data/lib/hecks/fqn.rb +5 -12
- data/lib/hecks/framework/bluebook/compliance.bluebook +16 -65
- data/lib/hecks/framework/bluebook/console_settings.bluebook +47 -134
- data/lib/hecks/framework/bluebook/framework.hecksagon +5 -14
- data/lib/hecks/framework/bluebook/governance.bluebook +13 -34
- data/lib/hecks/framework/bluebook/identity.bluebook +11 -26
- data/lib/hecks/framework/bluebook/privacy.bluebook +8 -33
- data/lib/hecks/framework.rb +11 -80
- data/lib/hecks/freezer.rb +5 -39
- data/lib/hecks/grammar/expression.bluebook +15 -40
- data/lib/hecks/grammar/translation.bluebook +3 -6
- data/lib/hecks/grammar.rb +16 -41
- data/lib/hecks/ir.rb +14 -83
- data/lib/hecks/language/adapter.bluebook +2 -7
- data/lib/hecks/language/bluebook/aggregate.bluebook +56 -221
- data/lib/hecks/language/bluebook/attaches/paging.bluebook +6 -15
- data/lib/hecks/language/bluebook/bluebook.bluebook +15 -83
- data/lib/hecks/language/bluebook/bluebook.hecksagon +3 -15
- data/lib/hecks/language/bluebook/command.bluebook +27 -144
- data/lib/hecks/language/bluebook/entity.bluebook +24 -97
- data/lib/hecks/language/bluebook/policy.bluebook +16 -67
- data/lib/hecks/language/bluebook/process_manager.bluebook +28 -151
- data/lib/hecks/language/bluebook/projection.bluebook +126 -60
- data/lib/hecks/language/bluebook/query.bluebook +12 -43
- data/lib/hecks/language/bluebook/shape.bluebook +23 -73
- data/lib/hecks/language/bluebook/syntax.bluebook +51 -262
- data/lib/hecks/language/bluebook/vocabulary.bluebook +82 -197
- data/lib/hecks/language/hecksagon/adapter_binding.bluebook +3 -10
- data/lib/hecks/language/hecksagon/domain_port.bluebook +4 -19
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +6 -25
- data/lib/hecks/language/hecksagon/port_operation.bluebook +3 -14
- data/lib/hecks/language/oidc.json +35 -0
- data/lib/hecks/language/port.bluebook +4 -17
- data/lib/hecks/language/translation/translation.bluebook +3 -9
- data/lib/hecks/language/translation/translation_aggregate.bluebook +5 -24
- data/lib/hecks/language/world/wiring.bluebook +1 -3
- data/lib/hecks/language/world/world.bluebook +5 -7
- data/lib/hecks/literal.rb +8 -50
- data/lib/hecks/mcp_door_scope.rb +9 -90
- data/lib/hecks/mcp_stdio_guard.rb +4 -41
- data/lib/hecks/naming.rb +29 -137
- data/lib/hecks/ports/access_control.rb +7 -23
- data/lib/hecks/ports/agent/answers.rb +5 -23
- data/lib/hecks/ports/agent.rb +47 -172
- data/lib/hecks/ports/authentication.rb +12 -39
- data/lib/hecks/ports/authorization.rb +16 -43
- data/lib/hecks/ports/clock.rb +5 -45
- data/lib/hecks/ports/extraction.rb +7 -12
- data/lib/hecks/ports/identity_assignment.rb +8 -29
- data/lib/hecks/ports/identity_generation.rb +6 -29
- data/lib/hecks/ports/identity_resolution.rb +2 -10
- data/lib/hecks/ports/key_vault.rb +9 -45
- data/lib/hecks/ports/persistence/append_only.rb +61 -64
- data/lib/hecks/ports/persistence/binding_policy.rb +4 -14
- data/lib/hecks/ports/persistence/codec_boundary.rb +20 -80
- data/lib/hecks/ports/persistence/null_saga_store.rb +4 -20
- data/lib/hecks/ports/persistence/plugin.rb +13 -42
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +38 -141
- data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +15 -115
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +16 -84
- data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +6 -25
- data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +3 -22
- data/lib/hecks/ports/persistence/plugins/era/lineage.rb +55 -181
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/events.rb +77 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +12 -122
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +28 -128
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +73 -474
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +31 -124
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +45 -219
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +13 -108
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +18 -75
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +9 -49
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +6 -123
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +23 -55
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +14 -72
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +7 -16
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +14 -115
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +13 -45
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +127 -554
- data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +13 -63
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +2 -17
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +3 -14
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +13 -58
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -17
- data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +9 -26
- data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +9 -25
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +18 -124
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +34 -123
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +5 -12
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +3 -9
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -14
- data/lib/hecks/ports/persistence/plugins/era.rb +4 -23
- data/lib/hecks/ports/persistence/postgres_dump/connection.rb +7 -23
- data/lib/hecks/ports/persistence/postgres_dump.rb +4 -35
- data/lib/hecks/ports/persistence/remote_runtime.rb +2 -24
- data/lib/hecks/ports/persistence/repository_factory.rb +8 -27
- data/lib/hecks/ports/persistence/state_codec.rb +23 -103
- data/lib/hecks/ports/persistence.rb +7 -14
- data/lib/hecks/ports/projection.rb +42 -84
- data/lib/hecks/ports/query/in_memory.rb +10 -58
- data/lib/hecks/ports/query/ordering.rb +11 -32
- data/lib/hecks/ports/query.rb +14 -37
- data/lib/hecks/ports.rb +2 -8
- data/lib/hecks/projections/bootstrap_table.rb +11 -43
- data/lib/hecks/projections/deploy/fargate/assembly.rb +2 -15
- data/lib/hecks/projections/deploy/fargate/cdn.rb +1 -48
- data/lib/hecks/projections/deploy/fargate/cdn_default.rb +2 -11
- data/lib/hecks/projections/deploy/fargate/check.rb +5 -14
- data/lib/hecks/projections/deploy/fargate/containers.rb +3 -78
- data/lib/hecks/projections/deploy/fargate/extras.rb +3 -44
- data/lib/hecks/projections/deploy/fargate/monitoring.rb +0 -44
- data/lib/hecks/projections/deploy/fargate/settings.rb +2 -54
- data/lib/hecks/projections/deploy/fargate/yaml.rb +13 -58
- data/lib/hecks/projections/deploy/fargate.rb +35 -202
- data/lib/hecks/projections/deploy/lambda.rb +150 -678
- data/lib/hecks/projections/deploy/preview/access_yaml.rb +1 -33
- data/lib/hecks/projections/deploy/preview/containers.rb +6 -111
- data/lib/hecks/projections/deploy/preview/routing_yaml.rb +4 -56
- data/lib/hecks/projections/deploy/preview/script.rb +2 -14
- data/lib/hecks/projections/deploy/preview/settings.rb +3 -33
- data/lib/hecks/projections/deploy/preview/task_yaml.rb +2 -38
- data/lib/hecks/projections/deploy/preview/template.rb +2 -58
- data/lib/hecks/projections/deploy/preview.rb +2 -67
- data/lib/hecks/projections/deploy/scripts/settings.rb +3 -25
- data/lib/hecks/projections/deploy/scripts.rb +4 -57
- data/lib/hecks/projections/deploy/shared.rb +47 -146
- data/lib/hecks/projections/deploy/smoke.rb +4 -61
- data/lib/hecks/projections/deploy/template_diff/comparer.rb +3 -25
- data/lib/hecks/projections/deploy/template_diff/loader.rb +2 -11
- data/lib/hecks/projections/deploy/template_diff.rb +5 -57
- data/lib/hecks/projections/diagrams.rb +20 -582
- data/lib/hecks/projections/glossary/html.rb +14 -130
- data/lib/hecks/projections/glossary/markdown.rb +8 -69
- data/lib/hecks/projections/glossary/mermaid.rb +9 -66
- data/lib/hecks/projections/glossary/sensitivity.rb +5 -34
- data/lib/hecks/projections/glossary/sentences.rb +14 -159
- data/lib/hecks/projections/glossary.rb +30 -222
- data/lib/hecks/projections/ir.rb +3 -10
- data/lib/hecks/projections/model/deviations.rb +15 -42
- data/lib/hecks/projections/model.rb +12 -51
- data/lib/hecks/projections/oidc.rb +12 -56
- data/lib/hecks/projections/parser_table.rb +9 -28
- data/lib/hecks/projections/reference.rb +2 -15
- data/lib/hecks/projections/rust_vocabulary.rb +12 -250
- data/lib/hecks/projections/shape.rb +3 -29
- data/lib/hecks/projections/statements.rb +7 -86
- data/lib/hecks/projections/vocabulary.rb +6 -22
- data/lib/hecks/projections.rb +2 -16
- data/lib/hecks/projector/cli_projector.rb +60 -375
- data/lib/hecks/projector/docs_projector.rb +10 -201
- data/lib/hecks/projector/exporter.rb +42 -134
- data/lib/hecks/projector/ir_projector.rb +2 -9
- data/lib/hecks/projector/narrate_projector.rb +15 -189
- data/lib/hecks/projector/target.rb +13 -76
- data/lib/hecks/projector.rb +30 -121
- data/lib/hecks/query_specification/common/comparators.rb +5 -26
- data/lib/hecks/query_specification/common/comparison.rb +35 -143
- data/lib/hecks/query_specification/common/dsl.rb +8 -24
- data/lib/hecks/query_specification/common/null_policy.rb +20 -70
- data/lib/hecks/query_specification/common/options.rb +2 -6
- data/lib/hecks/query_specification/common/where_clause.rb +2 -10
- data/lib/hecks/query_specification/field_path.rb +37 -77
- data/lib/hecks/query_specification/hop_path.rb +12 -76
- data/lib/hecks/release/gem_pin.rb +2 -26
- data/lib/hecks/release/runner/ci_publisher.rb +3 -6
- data/lib/hecks/release/runner/commands.rb +2 -4
- data/lib/hecks/release/runner/gem_publisher.rb +2 -3
- data/lib/hecks/release/runner/npm_publisher.rb +6 -20
- data/lib/hecks/release/runner/preflight.rb +4 -19
- data/lib/hecks/release/runner/tagger.rb +2 -9
- data/lib/hecks/release/runner.rb +3 -32
- data/lib/hecks/rendering.rb +4 -26
- data/lib/hecks/router/namespace_installer.rb +12 -36
- data/lib/hecks/router.rb +4 -8
- data/lib/hecks/runtime/aggregate_lock.rb +8 -33
- data/lib/hecks/runtime/boot_gates.rb +3 -18
- data/lib/hecks/runtime/caller.rb +19 -59
- data/lib/hecks/runtime/capability_graph.rb +5 -21
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +16 -78
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +23 -160
- data/lib/hecks/runtime/command_interpreter.rb +124 -306
- data/lib/hecks/runtime/command_rules/admissibility.rb +95 -366
- data/lib/hecks/runtime/command_rules/arithmetic.rb +66 -196
- data/lib/hecks/runtime/command_rules/authorization.rb +13 -45
- data/lib/hecks/runtime/command_rules/emission.rb +8 -21
- data/lib/hecks/runtime/command_rules/references.rb +23 -202
- data/lib/hecks/runtime/dependency_planning.rb +30 -102
- data/lib/hecks/runtime/dispatcher.rb +82 -241
- data/lib/hecks/runtime/entity_element.rb +40 -462
- data/lib/hecks/runtime/entity_interpreter.rb +64 -219
- data/lib/hecks/runtime/errors.rb +32 -115
- data/lib/hecks/runtime/event.rb +3 -25
- data/lib/hecks/runtime/identity.rb +18 -154
- data/lib/hecks/runtime/instance.rb +18 -150
- data/lib/hecks/runtime/interpreting.rb +11 -70
- data/lib/hecks/runtime/invocation.rb +28 -164
- data/lib/hecks/runtime/loader.rb +48 -186
- data/lib/hecks/runtime/outbox.rb +38 -261
- data/lib/hecks/runtime/policy_interpreter.rb +38 -200
- data/lib/hecks/runtime/port_operation_interpreter.rb +26 -87
- data/lib/hecks/runtime/query_interpreter.rb +45 -187
- data/lib/hecks/runtime/reaction_invocation.rb +36 -138
- data/lib/hecks/runtime/read_model_interpreter.rb +117 -208
- data/lib/hecks/runtime/rebuild_sweep.rb +8 -54
- data/lib/hecks/runtime/reference_hop.rb +8 -81
- data/lib/hecks/runtime/refusal_wording.rb +8 -89
- data/lib/hecks/runtime/registry/saga_persistence.rb +10 -102
- data/lib/hecks/runtime/registry/verification.rb +52 -225
- data/lib/hecks/runtime/registry/world_defaults.rb +4 -53
- data/lib/hecks/runtime/registry.rb +99 -244
- data/lib/hecks/runtime/remote_dispatcher.rb +37 -152
- data/lib/hecks/runtime/routing.rb +4 -15
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +14 -61
- data/lib/hecks/runtime/saga_interpreter.rb +79 -263
- data/lib/hecks/runtime/saga_pending_dispatch.rb +2 -43
- data/lib/hecks/runtime/tenant_check.rb +6 -68
- data/lib/hecks/runtime/tenant_scope.rb +3 -28
- data/lib/hecks/runtime/value/admission.rb +16 -67
- data/lib/hecks/runtime/value/coercion.rb +155 -641
- data/lib/hecks/runtime/value/entity_list_coercion.rb +26 -219
- data/lib/hecks/runtime/value.rb +12 -84
- data/lib/hecks/runtime.rb +17 -65
- data/lib/hecks/storehouse.rb +141 -568
- data/lib/hecks/tenancy/bluebook/tenancy.bluebook +8 -32
- data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +6 -23
- data/lib/hecks/vendoring/git_environment.rb +2 -8
- data/lib/hecks/vendoring/git_source.rb +4 -10
- data/lib/hecks/vendoring.rb +7 -46
- data/lib/hecks/version.rb +3 -14
- data/lib/hecks.rb +26 -81
- data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +8 -46
- data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +11 -80
- data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +10 -99
- metadata +3 -2
|
@@ -1,20 +1,13 @@
|
|
|
1
1
|
Hecks.bluebook "Identity" do
|
|
2
2
|
vision "Authentication proves an identifier; the organization decides what that identity means."
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
# (
|
|
6
|
-
# `Governance` (role/scope RBAC beside it) stays `supporting`
|
|
7
|
-
# instead, since ITS OWN model is bespoke to this codebase's actor/
|
|
8
|
-
# role/scope shape, not a drop-in replaceable concept the way an
|
|
9
|
-
# identity provider is.
|
|
3
|
+
# Generic, not `supporting`: an OIDC-shaped external identifier is the textbook generic
|
|
4
|
+
# subdomain. Governance's role/scope RBAC is bespoke to this codebase, so it stays
|
|
5
|
+
# `supporting` (ADR 0025).
|
|
10
6
|
generic
|
|
11
7
|
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
# field mapping lives on the consuming hecksagon's `translates` ACL
|
|
16
|
-
# (any field; this chapter does not list which). Link's reference is
|
|
17
|
-
# `identity`, not `identity_id` and not `to:`.
|
|
8
|
+
# What this chapter answers for every attaching domain, declared rather than named as
|
|
9
|
+
# Governance's `provides "authorization"` is. Field mapping lives on the consuming
|
|
10
|
+
# hecksagon's `translates` ACL; Link's reference is `identity`, not `identity_id` or `to:`.
|
|
18
11
|
provides "identity",
|
|
19
12
|
register: "Identity.Register",
|
|
20
13
|
link: "ExternalIdentifier.Link",
|
|
@@ -32,10 +25,8 @@ Hecks.bluebook "Identity" do
|
|
|
32
25
|
invariant("an identity id is present") { !value.to_s.empty? }
|
|
33
26
|
end
|
|
34
27
|
|
|
35
|
-
# No natural key exists for
|
|
36
|
-
#
|
|
37
|
-
# before dispatching (see spec/ports/identity_generation_spec.rb),
|
|
38
|
-
# the same pattern proven there against Pizzas.
|
|
28
|
+
# No natural key exists for a new identity: the caller mints `identity_id` via
|
|
29
|
+
# `Ports::IdentityGeneration.uuid` before dispatching.
|
|
39
30
|
command "Register" do
|
|
40
31
|
role "Identity registrar"
|
|
41
32
|
goal "Recognize an identity"
|
|
@@ -70,9 +61,7 @@ Hecks.bluebook "Identity" do
|
|
|
70
61
|
invariant("a subject is present") { !value.to_s.empty? }
|
|
71
62
|
end
|
|
72
63
|
|
|
73
|
-
# `key` is
|
|
74
|
-
# (e.g. SHA256 of issuer+subject), same as any other identity
|
|
75
|
-
# field this domain never mints itself.
|
|
64
|
+
# `key` is not derived here; the caller derives it (e.g. SHA256 of issuer+subject).
|
|
76
65
|
command "Link" do
|
|
77
66
|
role "Identity registrar"
|
|
78
67
|
goal "Associate an external authenticated subject with an identity"
|
|
@@ -85,12 +74,8 @@ Hecks.bluebook "Identity" do
|
|
|
85
74
|
emits ExternalIdentifierLinked
|
|
86
75
|
end
|
|
87
76
|
|
|
88
|
-
#
|
|
89
|
-
#
|
|
90
|
-
# is a caller-side derivation, deliberately not reproduced here —
|
|
91
|
-
# see `Link`'s own comment). `identity` rides the row already,
|
|
92
|
-
# from `reference_to Identity` above, so a caller reads it straight
|
|
93
|
-
# off the match rather than needing a second query.
|
|
77
|
+
# The OIDC-shaped lookup: a token hands over `(issuer, subject)`, never `key`. `identity`
|
|
78
|
+
# rides the row from `reference_to Identity`, so no second query is needed.
|
|
94
79
|
query "ResolvedBy" do
|
|
95
80
|
description "The external identifier linked to this exact (issuer, subject) pair, if any."
|
|
96
81
|
attribute :issuer, Issuer
|
|
@@ -2,12 +2,7 @@ Hecks.bluebook "Privacy" do
|
|
|
2
2
|
vision "Which fields of a domain's own aggregates are sensitive is a fact about that domain, declared apart from it — the domain itself never spells out that one of its own attributes is PII or PHI."
|
|
3
3
|
supporting
|
|
4
4
|
|
|
5
|
-
# A
|
|
6
|
-
# "Deployment"` matches every other wiring-time command in this
|
|
7
|
-
# codebase (`Hecksagon::UsesFramework`, `Tenancy::Tenant.Register`):
|
|
8
|
-
# something outside the domain's own bluebook decides a field is
|
|
9
|
-
# sensitive, the same way persistence binds are a wiring decision
|
|
10
|
-
# and not baked into an aggregate's own declaration.
|
|
5
|
+
# A domain never marks itself: `Mark` is a wiring-time command (role "Deployment").
|
|
11
6
|
aggregate "Marking" do
|
|
12
7
|
description "One attribute of one domain's own aggregate, flagged sensitive — and the role required to read it unredacted."
|
|
13
8
|
|
|
@@ -23,20 +18,13 @@ Hecks.bluebook "Privacy" do
|
|
|
23
18
|
invariant("a marking names the domain it applies to") { !value.to_s.empty? }
|
|
24
19
|
end
|
|
25
20
|
|
|
26
|
-
#
|
|
27
|
-
# cross-object `where` clause already use — `"attendee.medications"`,
|
|
28
|
-
# not a bare leaf name, so a marking can reach into a nested value
|
|
29
|
-
# object rather than only a top-level attribute.
|
|
21
|
+
# Dotted, e.g. "attendee.medications", so a marking can reach a nested value object.
|
|
30
22
|
value_object "AttributePath" do
|
|
31
23
|
attribute :value, String
|
|
32
24
|
invariant("a marking names an attribute path") { !value.to_s.empty? }
|
|
33
25
|
end
|
|
34
26
|
|
|
35
|
-
#
|
|
36
|
-
# domain finds itself needing, none of it enumerated here. This
|
|
37
|
-
# bluebook is the mechanism (mark, gate, redact); it does not also
|
|
38
|
-
# own the vocabulary of sensitivity categories that exist in the
|
|
39
|
-
# world.
|
|
27
|
+
# Open-ended on purpose ("pii", "phi", ...): this bluebook does not own the vocabulary.
|
|
40
28
|
value_object "Category" do
|
|
41
29
|
attribute :value, String
|
|
42
30
|
invariant("a marking is categorized") { !value.to_s.empty? }
|
|
@@ -75,15 +63,8 @@ Hecks.bluebook "Privacy" do
|
|
|
75
63
|
end
|
|
76
64
|
end
|
|
77
65
|
|
|
78
|
-
#
|
|
79
|
-
#
|
|
80
|
-
# handle a caller obtains from `Ports::KeyVault.issue` before
|
|
81
|
-
# dispatching `Issue`, the same "nothing is minted inside a bluebook"
|
|
82
|
-
# convention `Identity::Register`'s own `identity_id` and
|
|
83
|
-
# `Delivery::Record`'s own `message_id` already hold to (the
|
|
84
|
-
# expression sublanguage cannot call a port at all). The key material
|
|
85
|
-
# itself never appears here or on any emitted event — only the fact
|
|
86
|
-
# that a reference exists, and the fact that it was destroyed.
|
|
66
|
+
# Cryptoshredding: erasure without rewriting events. `key_reference` is an opaque handle
|
|
67
|
+
# from `Ports::KeyVault.issue`, obtained before `Issue`; key material never appears here.
|
|
87
68
|
aggregate "SubjectKey" do
|
|
88
69
|
description "One data subject's own encryption key, from the moment it exists to the moment it is destroyed."
|
|
89
70
|
|
|
@@ -108,9 +89,7 @@ Hecks.bluebook "Privacy" do
|
|
|
108
89
|
invariant("a key carries the vault's own opaque reference to it") { !value.to_s.empty? }
|
|
109
90
|
end
|
|
110
91
|
|
|
111
|
-
# `Shred`
|
|
112
|
-
# `Compliance::PrivacyReview`'s `Clear`/`Escalate` already use rather
|
|
113
|
-
# than an optional timestamp plus a hand-written `given`.
|
|
92
|
+
# Guards `Shred` against running twice.
|
|
114
93
|
lifecycle :status, default: "active" do
|
|
115
94
|
transition "Shred" => "shredded", from: "active"
|
|
116
95
|
end
|
|
@@ -130,12 +109,8 @@ Hecks.bluebook "Privacy" do
|
|
|
130
109
|
emits SubjectKeyIssued
|
|
131
110
|
end
|
|
132
111
|
|
|
133
|
-
#
|
|
134
|
-
#
|
|
135
|
-
# this is ever dispatched, the same boundary `send_issue.rb` draws
|
|
136
|
-
# around `Delivery::Record` for an already-sent email. This
|
|
137
|
-
# command's own job is to make an already-irreversible fact
|
|
138
|
-
# durable, not to cause it.
|
|
112
|
+
# Records the destruction, never performs it: `Ports::KeyVault.destroy` runs in
|
|
113
|
+
# driving-side code before this is dispatched.
|
|
139
114
|
command "Shred" do
|
|
140
115
|
role "Privacy officer"
|
|
141
116
|
goal "Mark this subject's key destroyed, so its ciphertext is recorded as permanently unrecoverable"
|
data/lib/hecks/framework.rb
CHANGED
|
@@ -1,67 +1,12 @@
|
|
|
1
1
|
require_relative "runtime/registry"
|
|
2
2
|
|
|
3
3
|
module Hecks
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
# domain-agnostic chapters no single example owns, shared by reference
|
|
7
|
-
# rather than copied into every domain that wants one.
|
|
8
|
-
#
|
|
9
|
-
# ## Where it lives
|
|
10
|
-
#
|
|
11
|
-
# Under `lib/`, not a top-level sibling — a real consumer (embryonaut)
|
|
12
|
-
# vendors only `lib/` (`bin/vendor-hecks`, and this gem's own
|
|
13
|
-
# `hecks.gemspec`, both glob `lib/**/*`), so a `framework/`
|
|
14
|
-
# sitting beside `lib/` rather than inside it packaged and vendored
|
|
15
|
-
# cleanly but left `uses_framework` finding nothing at runtime —
|
|
16
|
-
# `Framework::ROOT` pointed at a directory that simply never shipped.
|
|
17
|
-
# Nothing in this repo's own suite caught it, since every spec here
|
|
18
|
-
# reads the working tree directly; only vendoring into a real consumer
|
|
19
|
-
# did. Same reasoning `lib/hecks/language/bluebook/` already
|
|
20
|
-
# settled for the self-hosted grammar's own `.bluebook` files —
|
|
21
|
-
# non-Ruby data a module owns lives inside `lib/` with the code that
|
|
22
|
-
# reads it, not beside it.
|
|
23
|
-
#
|
|
24
|
-
# ## Derived, not hand-listed
|
|
25
|
-
#
|
|
26
|
-
# Derived from the directory, not hand-listed a second time — the same
|
|
27
|
-
# reasoning `Assembly::CONTRACTS` gives for reading the language's own
|
|
28
|
-
# fields from a table instead of restating them: a member added here
|
|
29
|
-
# and forgotten in a list would be a member `uses_framework` could
|
|
30
|
-
# never find, and a hand-kept list is exactly the shape that goes
|
|
31
|
-
# stale in silence. `spec/corpus_spec.rb`'s own `FRAMEWORK_MEMBERS`
|
|
32
|
-
# glob is the precedent this mirrors.
|
|
33
|
-
#
|
|
34
|
-
# ## Naming
|
|
35
|
-
#
|
|
36
|
-
# Named by file stem, capitalized — `governance.bluebook` holds
|
|
37
|
-
# `Hecks.bluebook "Governance"`, the same one-to-one spelling every
|
|
38
|
-
# other chapter in this codebase already keeps between its filename
|
|
39
|
-
# and its declared name.
|
|
4
|
+
# Registry of framework bluebooks (Governance, Identity, ...) in `lib/hecks/framework/bluebook/`.
|
|
5
|
+
# Members are derived from the directory and named by capitalized file stem.
|
|
40
6
|
module Framework
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
# constant points at, because `uses_framework` runs `Kernel.load`
|
|
45
|
-
# against `ROOT`, not against anything inside the copied domain
|
|
46
|
-
# directory — there is nothing here for a relocated copy to break,
|
|
47
|
-
# the way a symlink carried along with the copy would.
|
|
48
|
-
#
|
|
49
|
-
# Only the bluebook — a framework member's own `.hecksagon`, if it
|
|
50
|
-
# has one, is not auto-loaded. Persistence is a wiring decision, the
|
|
51
|
-
# same as any other aggregate's, and belongs to whoever is doing the
|
|
52
|
-
# deploying, not to a default baked into the framework member
|
|
53
|
-
# itself: a consuming app needs `Governance::RoleAssignment` durable
|
|
54
|
-
# (Postgres, say), and a framework member hard-coding Memory for its
|
|
55
|
-
# own specs would silently make that decision for every app that
|
|
56
|
-
# attaches it. The consuming app declares its own, separate
|
|
57
|
-
# `Hecks.hecksagon "Governance" do ... end` block for that — not
|
|
58
|
-
# binds folded into its own hecksagon, which would build but never
|
|
59
|
-
# resolve: `Ports::Persistence::BindingPolicy.resolve` looks up
|
|
60
|
-
# `registry.hecksagon` by the aggregate's own domain name, not the
|
|
61
|
-
# domain doing the binding, the one invariant this runtime holds
|
|
62
|
-
# everywhere else too. See `examples/banking/bluebook/banking.hecksagon`
|
|
63
|
-
# for the pattern — a real `.hecksagon` file can hold more than one
|
|
64
|
-
# `Hecks.hecksagon` call, one per domain it wires.
|
|
7
|
+
# Directory the members load from, never a copy, so relocated domain copies still resolve.
|
|
8
|
+
# Lives under `lib/` because consumers vendor only `lib/`.
|
|
9
|
+
# Only the bluebook loads: persistence is the consumer's own `Hecks.hecksagon` block.
|
|
65
10
|
ROOT = File.expand_path("framework/bluebook", __dir__).freeze
|
|
66
11
|
|
|
67
12
|
# Every framework member available to attach, by declared name.
|
|
@@ -74,11 +19,7 @@ module Hecks
|
|
|
74
19
|
end
|
|
75
20
|
end
|
|
76
21
|
|
|
77
|
-
# Every member whose
|
|
78
|
-
# read off the member's real IR (each loaded into a scratch registry,
|
|
79
|
-
# never the caller's), not off its name. Used where a check needs to
|
|
80
|
-
# say which member would satisfy it (`refuse_ungoverned_roles!`'s own
|
|
81
|
-
# suggestion, `Fuzzing::TargetCapabilities`).
|
|
22
|
+
# Every member whose bluebook declares `provides capability`, read from its IR, not its name.
|
|
82
23
|
#
|
|
83
24
|
# @param capability [String, Symbol] the capability name to look for
|
|
84
25
|
# @return [Array<String>] the names of every framework member that provides it,
|
|
@@ -101,9 +42,7 @@ module Hecks
|
|
|
101
42
|
lib = File.expand_path("..", __dir__)
|
|
102
43
|
registry = Runtime::Registry.new
|
|
103
44
|
Hecks.with_registry(registry) do
|
|
104
|
-
#
|
|
105
|
-
# source is recovered through the extraction port) — the seed
|
|
106
|
-
# `Grammar#grammar_chapters` and `bin/model_check` use.
|
|
45
|
+
# A chapter needs these four to build (predicate source is recovered via extraction).
|
|
107
46
|
Kernel.load(File.join(lib, "hecks/ports/persistence.port"))
|
|
108
47
|
Kernel.load(File.join(lib, "hecks/ports/extraction.port"))
|
|
109
48
|
Kernel.load(File.join(lib, "hecks/adapters/driven/memory.adapter"))
|
|
@@ -113,18 +52,10 @@ module Hecks
|
|
|
113
52
|
registry.bluebook(name.to_s)
|
|
114
53
|
end
|
|
115
54
|
|
|
116
|
-
#
|
|
117
|
-
#
|
|
118
|
-
#
|
|
119
|
-
#
|
|
120
|
-
# block). `Kernel.load` always re-executes the file, unlike
|
|
121
|
-
# `require`, so a second call would re-run `Hecks.bluebook
|
|
122
|
-
# "Governance"` a second time — and the self-hosting meta-domain
|
|
123
|
-
# records every declaration as a real dispatched command against its
|
|
124
|
-
# own ledger, so a second `Declare` for the same aggregate is a real
|
|
125
|
-
# `AlreadyExists`, not a no-op. Skipped once the member's bluebook is
|
|
126
|
-
# already registered in this registry — the same chapter, not merely
|
|
127
|
-
# a same-named one from a stale prior boot.
|
|
55
|
+
# Loads a member's bluebook unless this registry already holds it.
|
|
56
|
+
#
|
|
57
|
+
# `Kernel.load` re-executes the file, and a second `Declare` of the same aggregate is
|
|
58
|
+
# `AlreadyExists`, so repeated `uses_framework` calls in one boot must skip.
|
|
128
59
|
#
|
|
129
60
|
# @param name [String, Symbol] the member's name, such as `"Governance"`
|
|
130
61
|
# @return [Boolean, nil] true when this call loaded the member's bluebook, nil when
|
data/lib/hecks/freezer.rb
CHANGED
|
@@ -1,38 +1,10 @@
|
|
|
1
1
|
module Hecks
|
|
2
|
-
# The one place that
|
|
3
|
-
#
|
|
4
|
-
# Freezing here has been fixed four times in four places, each time by
|
|
5
|
-
# topping the container and leaving the contents: list attributes, the
|
|
6
|
-
# event log, query rows, and value objects. `.freeze` on a Hash stops a
|
|
7
|
-
# key being added or removed and nothing else — the String, Array or
|
|
8
|
-
# Hash a field holds stays mutable, so a caller reaches straight
|
|
9
|
-
# through and edits in place. Each fix looked complete and none was.
|
|
10
|
-
#
|
|
11
|
-
# ## What should be frozen, and why it is not everything
|
|
12
|
-
#
|
|
13
|
-
# a value object has no identity to change over. `with` already
|
|
14
|
-
# answers a new one rather than mutating, so freezing it through is
|
|
15
|
-
# what it always claimed to be.
|
|
16
|
-
#
|
|
17
|
-
# an emitted event is a record of something that happened. A mutable
|
|
18
|
-
# audit trail is not one.
|
|
19
|
-
#
|
|
20
|
-
# a query row is an answer, not a handle — mutating one edits nobody's
|
|
21
|
-
# state and silently disagrees with the store.
|
|
22
|
-
#
|
|
23
|
-
# an instance's state is not frozen, deliberately: the interpreter
|
|
24
|
-
# builds it up across a dispatch, and a command's whole job is to
|
|
25
|
-
# change it. Its values are frozen; the holder is not.
|
|
26
|
-
#
|
|
27
|
-
# a command's arguments are not frozen either. They arrive from
|
|
28
|
-
# outside, are normalised and coerced on the way in, and the coerced
|
|
29
|
-
# result is what becomes a frozen value.
|
|
2
|
+
# The one place that freezes a domain value all the way down, not just its container.
|
|
3
|
+
# Instance state and command arguments are deliberately left unfrozen; values and events are.
|
|
30
4
|
module Freezer
|
|
31
5
|
module_function
|
|
32
6
|
|
|
33
|
-
#
|
|
34
|
-
# a Value froze itself when it was built. What is left is the mutable
|
|
35
|
-
# trio, and each has to be walked rather than topped.
|
|
7
|
+
# Freezes a Hash, Array or String and everything inside it.
|
|
36
8
|
#
|
|
37
9
|
# @param held [Object] any domain value
|
|
38
10
|
# @return [Object] `held`, recursively frozen if it is a Hash, Array, or
|
|
@@ -46,17 +18,13 @@ module Hecks
|
|
|
46
18
|
end
|
|
47
19
|
end
|
|
48
20
|
|
|
49
|
-
#
|
|
50
|
-
# first thing that is reachable and mutable, which is what makes a
|
|
51
|
-
# failure message worth reading.
|
|
21
|
+
# True when `held` and everything reachable from it is frozen.
|
|
52
22
|
#
|
|
53
23
|
# @param held [Object] any domain value
|
|
54
24
|
# @return [Boolean] true if `held` and everything reachable from it is frozen
|
|
55
25
|
def deeply_frozen?(held) = unfrozen_within(held).nil?
|
|
56
26
|
|
|
57
27
|
# The path to the first mutable thing reachable from `held`, or nil.
|
|
58
|
-
# A path rather than a boolean because "something in this event is
|
|
59
|
-
# mutable" is not an actionable sentence.
|
|
60
28
|
#
|
|
61
29
|
# @param held [Object] any domain value
|
|
62
30
|
# @param path [Array<String>] the owner path accumulated by the recursive
|
|
@@ -72,9 +40,7 @@ module Hecks
|
|
|
72
40
|
end
|
|
73
41
|
end
|
|
74
42
|
|
|
75
|
-
#
|
|
76
|
-
# `frozen?` of them and trusting the answer has bitten enough people
|
|
77
|
-
# that it is worth being explicit.
|
|
43
|
+
# Explicit rather than trusting `frozen?` on immediates.
|
|
78
44
|
#
|
|
79
45
|
# @param held [Object] any domain value
|
|
80
46
|
# @return [Boolean] true if `held` is nil, true, false, a Numeric, or a Symbol
|
|
@@ -6,21 +6,9 @@ Hecks.bluebook "Expression" do
|
|
|
6
6
|
aggregate "Operator" do
|
|
7
7
|
description "One admitted operation — its symbol, its precedence, and how it reads in every target that must evaluate it."
|
|
8
8
|
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
# (whatever matches nothing else falls through to the inner grammar).
|
|
13
|
-
# Its inner grammar has three more: integer/float/string/bool/nil/
|
|
14
|
-
# array literals and the dotted-lookup fallback are TERMINAL
|
|
15
|
-
# productions — they recognize text, they do not combine operands,
|
|
16
|
-
# and they have nothing meaningful to render per target (a literal's
|
|
17
|
-
# spelling does not differ between targets the way an operation's
|
|
18
|
-
# might — `rust/src/kernel/expr.rs`'s own `Expr::Array` is a LEAF
|
|
19
|
-
# there too, for the identical reason, not routed through
|
|
20
|
-
# `OperatorCategory`).
|
|
21
|
-
# Forcing them into this shape would stretch `renderings` and the
|
|
22
|
-
# Arity invariant past what they mean. They stay declared only in
|
|
23
|
-
# prose — named here rather than silently left out.
|
|
9
|
+
# Not operators, so not declared here: parenthesization, the bare-leaf fallback,
|
|
10
|
+
# and the terminal literals and dotted lookup. They recognize text rather than
|
|
11
|
+
# combine operands, and a literal reads the same in every target.
|
|
24
12
|
identified_by :symbol
|
|
25
13
|
|
|
26
14
|
attribute :symbol, OperatorSymbol
|
|
@@ -54,47 +42,34 @@ Hecks.bluebook "Expression" do
|
|
|
54
42
|
|
|
55
43
|
value_object "Arity" do
|
|
56
44
|
attribute :value, Integer
|
|
57
|
-
#
|
|
58
|
-
#
|
|
59
|
-
#
|
|
60
|
-
# canonical form for the same source, waiting for the first multi-line
|
|
61
|
-
# rule anyone wrote. Every predicate here was kept on one line to dodge
|
|
62
|
-
# that. The join is continuation-aware now, so this case holds the fix:
|
|
63
|
-
# if it regresses, the canonical text of THIS invariant changes and the
|
|
64
|
-
# golden IR goes red.
|
|
45
|
+
# Written across lines on purpose: it pins continuation-aware line joining in
|
|
46
|
+
# extraction. If that regresses, this invariant's canonical text changes and
|
|
47
|
+
# the golden IR goes red.
|
|
65
48
|
invariant("an operator takes one, two or three operands") do
|
|
66
49
|
value > 0 &&
|
|
67
50
|
value <= 3
|
|
68
51
|
end
|
|
69
52
|
end
|
|
70
53
|
|
|
71
|
-
#
|
|
72
|
-
#
|
|
73
|
-
#
|
|
74
|
-
# to is not derivable from its symbol alone (`+` reads like it could be
|
|
75
|
-
# either), so it is its own column rather than inferred.
|
|
54
|
+
# The outer grammar checks `.include?`, comparators and `!` before falling through
|
|
55
|
+
# to the inner arithmetic and dotted-lookup grammar. The symbol alone does not say
|
|
56
|
+
# which one an operator belongs to, so it is its own column.
|
|
76
57
|
value_object "Grammar" do
|
|
77
58
|
attribute :value, String
|
|
78
59
|
invariant("an operator belongs to one of the two stacked grammars") { !value.to_s.empty? }
|
|
79
60
|
end
|
|
80
61
|
|
|
81
|
-
#
|
|
82
|
-
# (
|
|
83
|
-
#
|
|
84
|
-
# (`||`, comparators), strip a leading marker (`!`), strip a trailing
|
|
85
|
-
# suffix (`.empty?`), or match a call-with-argument pattern
|
|
86
|
-
# (`.include?(needle)`).
|
|
62
|
+
# How the check recognizes an operator's text: split at a top-level occurrence
|
|
63
|
+
# (`||`), strip a leading marker (`!`) or trailing suffix (`.empty?`), or match a
|
|
64
|
+
# call pattern (`.include?(needle)`).
|
|
87
65
|
value_object "Strategy" do
|
|
88
66
|
attribute :value, String
|
|
89
67
|
invariant("an operator names how its check recognizes it") { !value.to_s.empty? }
|
|
90
68
|
end
|
|
91
69
|
|
|
92
|
-
#
|
|
93
|
-
#
|
|
94
|
-
#
|
|
95
|
-
# before `>` before `==` before `!=`, so `<` splitting does not fire
|
|
96
|
-
# inside `>=`). Scoped per `grammar`, mirroring Normalisation's own
|
|
97
|
-
# Position column below — each grammar starts its own count at 1.
|
|
70
|
+
# The check order within a grammar, counted from 1 per grammar. It breaks the tie
|
|
71
|
+
# precedence cannot: the six comparators share a tier, and `>=` must be tried
|
|
72
|
+
# before `>` so a split on `>` does not fire inside `>=`.
|
|
98
73
|
value_object "Position" do
|
|
99
74
|
attribute :value, Integer
|
|
100
75
|
invariant("an operator sits somewhere in its grammar's check order") { value > 0 }
|
|
@@ -18,12 +18,9 @@ Hecks.bluebook "Translation" do
|
|
|
18
18
|
transition "Retire" => "retired", from: "admitted"
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
# these are TranslationAggregateBuilder's own rule methods ; "retired" is
|
|
25
|
-
# the edge-level declaration (TranslationBuilder#retired), in the set
|
|
26
|
-
# because it is one admitted way a shape survives — by not surviving.
|
|
21
|
+
# The closed set of rule kinds, kept as data so a conformance spec can hold the
|
|
22
|
+
# builder to it. All but "retired" are TranslationAggregateBuilder rule methods;
|
|
23
|
+
# "retired" is the edge-level declaration (TranslationBuilder#retired).
|
|
27
24
|
value_object "Kind" do
|
|
28
25
|
attribute :value, String,
|
|
29
26
|
one_of: ["rename", "move", "convert", "drop", "retype", "retired", "compute", "rekey",
|
data/lib/hecks/grammar.rb
CHANGED
|
@@ -1,32 +1,23 @@
|
|
|
1
1
|
require "json"
|
|
2
2
|
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
# point loads ever requires this file back, so the require is acyclic.
|
|
3
|
+
# Loads the whole framework on purpose; nothing the entry point loads
|
|
4
|
+
# requires this file back, so the require is acyclic.
|
|
6
5
|
require_relative "../hecks"
|
|
7
6
|
|
|
8
7
|
module Hecks
|
|
9
|
-
# The sublanguage grammar domains (grammar/*.bluebook) and the one boot
|
|
10
|
-
#
|
|
11
|
-
# through its own admission ledger, so anything derived from it (the
|
|
12
|
-
# operator projections, the conformance specs) reads the set that
|
|
13
|
-
# actually survived the Admit gates, never a hand-copied list.
|
|
8
|
+
# The sublanguage grammar domains (grammar/*.bluebook) and the one boot path
|
|
9
|
+
# for reading them as data, replayed through the expression admission ledger.
|
|
14
10
|
#
|
|
15
|
-
# Booted on call, never at require: the Prism adapter normalises
|
|
16
|
-
#
|
|
17
|
-
# expression machinery cannot boot the chapter that configures it —
|
|
18
|
-
# this module exists precisely so generators and specs boot it in a
|
|
19
|
-
# scratch registry instead.
|
|
11
|
+
# Booted on call, never at require: the Prism adapter normalises predicates
|
|
12
|
+
# while a bluebook loads, so the expression machinery cannot boot its own chapter.
|
|
20
13
|
module Grammar
|
|
21
14
|
DIR = File.expand_path("grammar", __dir__)
|
|
22
15
|
LEDGER = File.join(DIR, "expression_operators.json")
|
|
23
16
|
|
|
24
17
|
module_function
|
|
25
18
|
|
|
26
|
-
#
|
|
27
|
-
# its real commands
|
|
28
|
-
# a half-admitted ledger would project a table the gates never
|
|
29
|
-
# accepted.
|
|
19
|
+
# Boots the expression chapter and replays the admission ledger through
|
|
20
|
+
# its real commands; a refused step raises.
|
|
30
21
|
#
|
|
31
22
|
# @return [Runtime::Dispatcher] the dispatcher bound to the booted, replayed
|
|
32
23
|
# expression chapter
|
|
@@ -104,16 +95,9 @@ module Hecks
|
|
|
104
95
|
registry.repository("Expression", aggregate).all
|
|
105
96
|
end
|
|
106
97
|
|
|
107
|
-
# The operators the language
|
|
108
|
-
# the
|
|
109
|
-
#
|
|
110
|
-
# operator table the ledger admits. An operator one of those
|
|
111
|
-
# predicates uses is self-bearing: retire it and the language can no
|
|
112
|
-
# longer read its own rules — found the hard way, as a projection
|
|
113
|
-
# missing `!=` that could not boot the chapter to fix itself. This
|
|
114
|
-
# derives the set, with a usage site per operator, so the generator
|
|
115
|
-
# and the conformance spec can refuse the retirement by name instead
|
|
116
|
-
# of wedging.
|
|
98
|
+
# The operators the language's own guards and invariants (Bluebook, World and
|
|
99
|
+
# the grammar chapters) evaluate through. Retiring one would leave the
|
|
100
|
+
# language unable to read its own rules, so callers refuse it by name.
|
|
117
101
|
#
|
|
118
102
|
# @return [Hash{String => Array<String>}] each self-bearing operator symbol
|
|
119
103
|
# mapped to the `"Chapter Aggregate.command"`/`"Chapter Aggregate::ValueObject"`
|
|
@@ -147,8 +131,7 @@ module Hecks
|
|
|
147
131
|
sites.transform_values(&:uniq)
|
|
148
132
|
end
|
|
149
133
|
|
|
150
|
-
# Every grammar/*.bluebook chapter, booted
|
|
151
|
-
# boots them — each alone, in a scratch registry.
|
|
134
|
+
# Every grammar/*.bluebook chapter, each booted alone in a scratch registry.
|
|
152
135
|
#
|
|
153
136
|
# @return [Array<Class>] each grammar chapter, booted alone in its own scratch
|
|
154
137
|
# registry
|
|
@@ -167,9 +150,8 @@ module Hecks
|
|
|
167
150
|
end
|
|
168
151
|
end
|
|
169
152
|
|
|
170
|
-
# Which admitted operators one canonical text evaluates through
|
|
171
|
-
# the evaluator's own parse
|
|
172
|
-
# walked for the resolver's arithmetic.
|
|
153
|
+
# Which admitted operators one canonical text evaluates through, found by
|
|
154
|
+
# walking the evaluator's own parse.
|
|
173
155
|
#
|
|
174
156
|
# @param canonical [String] canonical expression text to parse
|
|
175
157
|
# @return [Array<String>] operator symbols the expression evaluates through, or
|
|
@@ -184,15 +166,8 @@ module Hecks
|
|
|
184
166
|
walk_operators(node, evaluator).uniq
|
|
185
167
|
end
|
|
186
168
|
|
|
187
|
-
#
|
|
188
|
-
#
|
|
189
|
-
# nodes, and the generic Struct fallback) — each branch does the
|
|
190
|
-
# same one thing (name the node's own operator, recurse into its
|
|
191
|
-
# children) and the branches don't interact, but the ABC score adds
|
|
192
|
-
# every branch's cost together. Splitting the case out per node type
|
|
193
|
-
# would trade one place that shows the whole operator vocabulary for
|
|
194
|
-
# several that each show a fragment, with no reduction in real
|
|
195
|
-
# complexity.
|
|
169
|
+
# One case over the closed set of AST node types, kept together so the whole
|
|
170
|
+
# operator vocabulary reads in one place.
|
|
196
171
|
# @param node [Object] an evaluator/resolver AST node, or a Struct fallback
|
|
197
172
|
# @param evaluator [Module] `Bluebook::Expression::Evaluator`, passed through
|
|
198
173
|
# so nested calls don't re-resolve the constant
|