hecks 2.7.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 +11 -0
- 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 +18 -99
- 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 +15 -37
- 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 +32 -142
- 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 +17 -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 +38 -26
- 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 +17 -65
- 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 -189
- 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 -106
- 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 +54 -268
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +47 -308
- 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 +10 -91
- data/lib/hecks/bluebook/model_check.rb +102 -600
- 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 +84 -0
- data/lib/hecks/cli/document.rb +86 -0
- data/lib/hecks/cli/ir.rb +45 -0
- data/lib/hecks/cli/mcp.rb +31 -0
- data/lib/hecks/cli/mcp_door.rb +366 -0
- data/lib/hecks/cli/model_check.rb +203 -0
- data/lib/hecks/cli/project_cli.rb +90 -0
- data/lib/hecks/cli/project_diagrams.rb +36 -0
- data/lib/hecks/cli/run.rb +173 -0
- data/lib/hecks/cli/smoke_test.rb +45 -0
- data/lib/hecks/cli/stores.rb +53 -0
- data/lib/hecks/cli.rb +160 -0
- 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 +98 -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 +95 -0
- 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 +62 -65
- 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 +7 -26
- 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 +22 -122
- 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 +151 -679
- 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 +9 -16
- 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 +46 -138
- 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 +93 -0
- data/lib/hecks/release/runner/commands.rb +66 -0
- data/lib/hecks/release/runner/console.rb +52 -0
- data/lib/hecks/release/runner/gem_publisher.rb +43 -0
- data/lib/hecks/release/runner/git.rb +48 -0
- data/lib/hecks/release/runner/npm_publisher.rb +75 -0
- data/lib/hecks/release/runner/preflight.rb +104 -0
- data/lib/hecks/release/runner/published.rb +55 -0
- data/lib/hecks/release/runner/tagger.rb +80 -0
- data/lib/hecks/release/runner.rb +215 -0
- 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 +125 -307
- 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 +65 -220
- 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 +139 -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 +103 -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 +146 -567
- 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/vocabulary.rb +5 -0
- data/lib/hecks.rb +32 -82
- 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 +30 -59
- data/lib/hecks/bench/cli.rb +0 -74
- data/lib/hecks/bench/environment.rb +0 -100
- data/lib/hecks/bench/postgres_probe.rb +0 -41
- data/lib/hecks/bench/report.rb +0 -116
- data/lib/hecks/bench/ruby_runner.rb +0 -151
- data/lib/hecks/bench/run.rb +0 -55
- data/lib/hecks/bench/rust_runner.rb +0 -165
- data/lib/hecks/bench/stats.rb +0 -75
- data/lib/hecks/bench/suite.rb +0 -172
- data/lib/hecks/bench/workload.rb +0 -137
- data/lib/hecks/bench.rb +0 -28
- data/lib/hecks/codemod.rb +0 -443
- data/lib/hecks/corpus.rb +0 -479
- data/lib/hecks/doc/reference.rb +0 -585
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +0 -684
- data/lib/hecks/fuzzing/combination_miner.rb +0 -178
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +0 -469
- data/lib/hecks/fuzzing/coverage_campaign.rb +0 -161
- data/lib/hecks/fuzzing/differential.rb +0 -192
- data/lib/hecks/fuzzing/domain_generator.rb +0 -871
- data/lib/hecks/fuzzing/era_boundary.rb +0 -154
- data/lib/hecks/fuzzing/form_census.rb +0 -285
- data/lib/hecks/fuzzing/generated_domain_check.rb +0 -171
- data/lib/hecks/fuzzing/invalid_value_generator.rb +0 -125
- data/lib/hecks/fuzzing/isolated_boot.rb +0 -658
- data/lib/hecks/fuzzing/nondeterministic.rb +0 -79
- data/lib/hecks/fuzzing/persistence_parity.rb +0 -253
- data/lib/hecks/fuzzing/properties/corrections.rb +0 -125
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +0 -688
- data/lib/hecks/fuzzing/properties/guards.rb +0 -398
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +0 -399
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +0 -137
- data/lib/hecks/fuzzing/properties/outbox.rb +0 -180
- data/lib/hecks/fuzzing/properties/querying.rb +0 -260
- data/lib/hecks/fuzzing/properties.rb +0 -267
- data/lib/hecks/fuzzing/qa_settings.rb +0 -164
- data/lib/hecks/fuzzing/replay.rb +0 -930
- data/lib/hecks/fuzzing/rotation_priority.rb +0 -114
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +0 -139
- data/lib/hecks/fuzzing/self_consistency.rb +0 -825
- data/lib/hecks/fuzzing/sequence_generator/adversary.rb +0 -532
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +0 -171
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +0 -127
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +0 -116
- data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +0 -138
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +0 -344
- data/lib/hecks/fuzzing/sequence_generator.rb +0 -311
- data/lib/hecks/fuzzing/shrinker.rb +0 -309
- data/lib/hecks/fuzzing/structural_skips.rb +0 -53
- data/lib/hecks/fuzzing/sweep_depth.rb +0 -61
- data/lib/hecks/fuzzing/target_capabilities.rb +0 -255
- data/lib/hecks/fuzzing/value_generator.rb +0 -340
- data/lib/hecks/fuzzing.rb +0 -23
- data/lib/hecks/grammar/evolve.rb +0 -524
- data/lib/hecks/query_ir.rb +0 -482
|
@@ -236,6 +236,21 @@
|
|
|
236
236
|
"verb": "Bluebook::Query.Option",
|
|
237
237
|
"role": "Language"
|
|
238
238
|
},
|
|
239
|
+
{
|
|
240
|
+
"scope": "bluebook:read_model.all",
|
|
241
|
+
"verb": "Bluebook::ReadModel.All",
|
|
242
|
+
"role": "Language"
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
"scope": "bluebook:read_model.any",
|
|
246
|
+
"verb": "Bluebook::ReadModel.Any",
|
|
247
|
+
"role": "Language"
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
"scope": "bluebook:read_model.avg",
|
|
251
|
+
"verb": "Bluebook::ReadModel.Avg",
|
|
252
|
+
"role": "Language"
|
|
253
|
+
},
|
|
239
254
|
{
|
|
240
255
|
"scope": "bluebook:read_model.count",
|
|
241
256
|
"verb": "Bluebook::ReadModel.Count",
|
|
@@ -256,16 +271,36 @@
|
|
|
256
271
|
"verb": "Bluebook::ReadModel.GroupBy",
|
|
257
272
|
"role": "Language"
|
|
258
273
|
},
|
|
274
|
+
{
|
|
275
|
+
"scope": "bluebook:read_model.max",
|
|
276
|
+
"verb": "Bluebook::ReadModel.Max",
|
|
277
|
+
"role": "Language"
|
|
278
|
+
},
|
|
259
279
|
{
|
|
260
280
|
"scope": "bluebook:read_model.median",
|
|
261
281
|
"verb": "Bluebook::ReadModel.Median",
|
|
262
282
|
"role": "Language"
|
|
263
283
|
},
|
|
284
|
+
{
|
|
285
|
+
"scope": "bluebook:read_model.min",
|
|
286
|
+
"verb": "Bluebook::ReadModel.Min",
|
|
287
|
+
"role": "Language"
|
|
288
|
+
},
|
|
264
289
|
{
|
|
265
290
|
"scope": "bluebook:read_model.option",
|
|
266
291
|
"verb": "Bluebook::ReadModel.Option",
|
|
267
292
|
"role": "Language"
|
|
268
293
|
},
|
|
294
|
+
{
|
|
295
|
+
"scope": "bluebook:read_model.percentile",
|
|
296
|
+
"verb": "Bluebook::ReadModel.Percentile",
|
|
297
|
+
"role": "Language"
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
"scope": "bluebook:read_model.sum",
|
|
301
|
+
"verb": "Bluebook::ReadModel.Sum",
|
|
302
|
+
"role": "Language"
|
|
303
|
+
},
|
|
269
304
|
{
|
|
270
305
|
"scope": "bluebook:syntax.argument",
|
|
271
306
|
"verb": "Bluebook::Syntax.Argument",
|
|
@@ -25,14 +25,8 @@ Hecks.bluebook "Port" do
|
|
|
25
25
|
attribute :value, String, one_of: ["reply", "effect"]
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
# and `signal`, which only ever describe the door itself. Optional
|
|
31
|
-
# the same way `verb` is (a port declared with none is exactly
|
|
32
|
-
# today's pre-existing behavior, unchecked past `verify!`'s existing
|
|
33
|
-
# gates), and a plain list of method names rather than a richer
|
|
34
|
-
# shape — the same restraint `AdapterField` already takes for
|
|
35
|
-
# `field`/`secret`.
|
|
28
|
+
# The method contract: what an adapter must `respond_to?` for a dispatch through this door.
|
|
29
|
+
# A port that declares none is unchecked beyond `verify!`.
|
|
36
30
|
value_object "PortAnswer" do
|
|
37
31
|
attribute :value, String
|
|
38
32
|
invariant("an answer names a real method") { !value.to_s.empty? }
|
|
@@ -43,12 +37,7 @@ Hecks.bluebook "Port" do
|
|
|
43
37
|
goal "Open a resource door a domain's own aggregates may call by verb"
|
|
44
38
|
|
|
45
39
|
attribute :name, PortName
|
|
46
|
-
#
|
|
47
|
-
# .rb's own "signal says whether the domain gets a value back..."
|
|
48
|
-
# builds a port with only `signal`, never calling `verb` at all;
|
|
49
|
-
# `def verb(value)` has no default, unlike `signal`'s `:reply`).
|
|
50
|
-
# Same asymmetry world.bluebook's own Declare command already has
|
|
51
|
-
# for `realm`/`latest`.
|
|
40
|
+
# Optional: a port may declare only `signal`; `verb` has no default, unlike `signal`.
|
|
52
41
|
attribute :verb, PortVerb, optional: true
|
|
53
42
|
attribute :signal, PortSignal
|
|
54
43
|
|
|
@@ -71,9 +60,7 @@ Hecks.bluebook "Port" do
|
|
|
71
60
|
emits "PortAnswerAdded"
|
|
72
61
|
end
|
|
73
62
|
|
|
74
|
-
#
|
|
75
|
-
# they describe; SyntaxBoot discovers every aggregate-local seed table.
|
|
76
|
-
# Contexts represented here: File, Port.
|
|
63
|
+
# Keyword rows for File and Port; SyntaxBoot discovers every aggregate-local seed table.
|
|
77
64
|
value_object "KeywordSeed" do
|
|
78
65
|
attribute :word, String
|
|
79
66
|
attribute :context, String, admits: "Syntax::Context"
|
|
@@ -24,12 +24,8 @@ Hecks.bluebook "Translation" do
|
|
|
24
24
|
invariant("a name says something") { !value.to_s.empty? }
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
# migration needs), the same shape `AggregateBuilder#provenance`/
|
|
30
|
-
# `CommandBuilder#provenance` already capture as plain, unvalidated
|
|
31
|
-
# text (`LiteralText`, aggregate.bluebook) rather than a fixed
|
|
32
|
-
# attribute shape a closed self-hosted record could enumerate.
|
|
27
|
+
# `convert` values and `backfill` defaults are open-ended literals, so they are held as
|
|
28
|
+
# unvalidated text, like `provenance` (`LiteralText`, aggregate.bluebook).
|
|
33
29
|
value_object "TranslationLiteralText" do
|
|
34
30
|
attribute :value, String
|
|
35
31
|
end
|
|
@@ -60,9 +56,7 @@ Hecks.bluebook "Translation" do
|
|
|
60
56
|
emits "TranslationAggregateRetired"
|
|
61
57
|
end
|
|
62
58
|
|
|
63
|
-
#
|
|
64
|
-
# they describe; SyntaxBoot discovers every aggregate-local seed table.
|
|
65
|
-
# Contexts represented here: File, Translation.
|
|
59
|
+
# Syntax seed rows for the words this aggregate spells; SyntaxBoot discovers them.
|
|
66
60
|
value_object "KeywordSeed" do
|
|
67
61
|
attribute :word, String
|
|
68
62
|
attribute :context, String, admits: "Syntax::Context"
|
|
@@ -6,22 +6,8 @@ Hecks.bluebook "Translation" do
|
|
|
6
6
|
|
|
7
7
|
identified_by TranslationAggregateName, as: :name
|
|
8
8
|
|
|
9
|
-
# `
|
|
10
|
-
# field,
|
|
11
|
-
# below uses. Found live, not by inspection: reusing one value-
|
|
12
|
-
# object type for BOTH an aggregate's own identity field and a
|
|
13
|
-
# sibling non-identity field on the same aggregate broke the
|
|
14
|
-
# single-field-VO identity-unwrap path — the stored `id` came back
|
|
15
|
-
# as a stringified Hash (`"{:value=>\"Account\"}"`) instead of the
|
|
16
|
-
# bare scalar (`"Account"`), so a self-reference to this aggregate
|
|
17
|
-
# could never find the record `Declare` had just created. Reusing
|
|
18
|
-
# the SAME type across MULTIPLE identity fields (Translation's own
|
|
19
|
-
# `TranslationEraName`, for both `from` and `to`) is unaffected —
|
|
20
|
-
# confirmed directly, not assumed — so the real trigger is identity
|
|
21
|
-
# + non-identity sharing, not reuse itself. A genuine framework bug,
|
|
22
|
-
# out of scope to fix here; every other self-hosted construct in
|
|
23
|
-
# this language already avoids it by convention (a dedicated type
|
|
24
|
-
# per identity field), which this now matches too.
|
|
9
|
+
# A dedicated identity type: sharing `TranslationName` with a non-identity field breaks the
|
|
10
|
+
# single-field identity unwrap, storing the id as a stringified Hash instead of a scalar.
|
|
25
11
|
attribute :was, TranslationName, optional: true
|
|
26
12
|
|
|
27
13
|
value_object "TranslationAggregateName" do
|
|
@@ -47,11 +33,8 @@ Hecks.bluebook "Translation" do
|
|
|
47
33
|
attribute :rekeys, list_of(TranslationRekey)
|
|
48
34
|
attribute :backfills, list_of(TranslationBackfill)
|
|
49
35
|
|
|
50
|
-
# Field names
|
|
51
|
-
#
|
|
52
|
-
# TranslationJudge dispatches from, not the builder's own local
|
|
53
|
-
# parameter names (`move(old_path, to:)`'s `old_path` becomes the
|
|
54
|
-
# struct's own `from`).
|
|
36
|
+
# Field names mirror the Struct records in lib/hecks/bluebook/translation.rb, not the
|
|
37
|
+
# builder's parameter names (`move(old_path, to:)` stores `old_path` as `from`).
|
|
55
38
|
value_object "TranslationRename" do
|
|
56
39
|
attribute :from, TranslationName
|
|
57
40
|
attribute :to, TranslationName
|
|
@@ -199,9 +182,7 @@ Hecks.bluebook "Translation" do
|
|
|
199
182
|
emits "TranslationBackfillAdded"
|
|
200
183
|
end
|
|
201
184
|
|
|
202
|
-
#
|
|
203
|
-
# they describe; SyntaxBoot discovers every aggregate-local seed table.
|
|
204
|
-
# Contexts represented here: TranslationAggregate.
|
|
185
|
+
# Syntax seed rows for the words this aggregate spells; SyntaxBoot discovers them.
|
|
205
186
|
value_object "KeywordSeed" do
|
|
206
187
|
attribute :word, String
|
|
207
188
|
attribute :context, String, admits: "Syntax::Context"
|
|
@@ -7,9 +7,7 @@ Hecks.bluebook "World" do
|
|
|
7
7
|
# so the bare reference name would collide with it.
|
|
8
8
|
belongs_to World, as: :world_ref
|
|
9
9
|
|
|
10
|
-
#
|
|
11
|
-
# verb — that is what a binding IS — so the verb names the wiring, and the
|
|
12
|
-
# world says whose.
|
|
10
|
+
# One world binds one adapter per verb, so the verb names the wiring and the world says whose.
|
|
13
11
|
identified_by :world, :verb
|
|
14
12
|
|
|
15
13
|
attribute :world, WiringText
|
|
@@ -59,9 +59,8 @@ Hecks.bluebook "World" do
|
|
|
59
59
|
emits "WorldDeclared"
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
-
#
|
|
63
|
-
#
|
|
64
|
-
# Contexts represented here: File, World.
|
|
62
|
+
# Spelling rows for World keywords; SyntaxBoot discovers every
|
|
63
|
+
# aggregate-local seed table like this one.
|
|
65
64
|
value_object "KeywordSeed" do
|
|
66
65
|
attribute :word, String
|
|
67
66
|
attribute :context, String, admits: "Syntax::Context"
|
|
@@ -77,10 +76,9 @@ Hecks.bluebook "World" do
|
|
|
77
76
|
member word: "world", context: "File", body: "keywords", inner: "World", opens: "World", fills: ""
|
|
78
77
|
member word: "realm", context: "World", body: "none", inner: "", opens: "", fills: "realm", calls: "realm_impl"
|
|
79
78
|
member word: "latest", context: "World", body: "none", inner: "", opens: "", fills: "latest", calls: "latest_impl"
|
|
80
|
-
#
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
# hecksagon bind still win; see docs/implemented/reference/world.md.
|
|
79
|
+
# The connection string and persistence adapter every chapter of a
|
|
80
|
+
# project would otherwise repeat, written once here; a chapter's own
|
|
81
|
+
# world or hecksagon bind still wins.
|
|
84
82
|
member word: "default_database", context: "World", body: "none", inner: "", opens: "", fills: "default_database", calls: "default_database_impl"
|
|
85
83
|
member word: "default_adapter", context: "World", body: "none", inner: "", opens: "", fills: "default_adapter", calls: "default_adapter_impl"
|
|
86
84
|
|
data/lib/hecks/literal.rb
CHANGED
|
@@ -1,45 +1,13 @@
|
|
|
1
1
|
module Hecks
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
-
# Several `to_h` fields hold a value the author wrote in a bluebook —
|
|
5
|
-
# `where(status: { eq: "open" })`, `then_set append: { direction: { value:
|
|
6
|
-
# "credit" } }`, `dispatch ... with: { number: :source }`, an attribute's
|
|
7
|
-
# `default:` — as text, because the export has to stand on its own and a
|
|
8
|
-
# String field cannot say "this one was a Symbol". Every such field is the
|
|
9
|
-
# same question and now gets the same answer.
|
|
10
|
-
#
|
|
11
|
-
# It was three answers before, and they disagreed on both axes that matter.
|
|
12
|
-
# `Mutation#appended_fields` spelled a Symbol bare and everything else
|
|
13
|
-
# `inspect`; `QuerySpecification.render_value` spelled a Symbol with a colon
|
|
14
|
-
# and everything else `to_s`. So `:amount` crossed as "amount" in a mutation
|
|
15
|
-
# and ":amount" in a saga binding — the same value, two spellings, and each
|
|
16
|
-
# reader had to know which field it was looking at. Worse, `to_s`/`inspect`
|
|
17
|
-
# on a Hash is Ruby's own rendering, which moved under us: 3.3 writes
|
|
18
|
-
# `{:value=>"credit"}` and 3.4 writes `{value: "credit"}` for the identical
|
|
19
|
-
# Hash, so the wire format was silently pinned to an interpreter version.
|
|
20
|
-
#
|
|
21
|
-
# Self-describing is the rule, stated once here rather than inherited from
|
|
22
|
-
# whatever `inspect` happens to do: a symbol wears its colon, a string wears
|
|
23
|
-
# its quotes, a hash wears `{key: value}` braces, a list wears its brackets,
|
|
24
|
-
# and a number, a boolean and nil are bare. `read` is the exact inverse, and
|
|
25
|
-
# is the only thing that should ever take one of these strings apart.
|
|
26
|
-
# A mutation source that reads the record's own state — `sets :positions,
|
|
27
|
-
# append: { knights: state(:knights) }`. A bare Symbol in a mutation
|
|
28
|
-
# source always names a command argument (and imports it as one when
|
|
29
|
-
# the target's own field carries the same name — `CommandBuilder
|
|
30
|
-
# #resolve_append_fields!`); before this there was no way to say "the
|
|
31
|
-
# value this field already holds", so a command could not snapshot its
|
|
32
|
-
# own record — chess's threefold repetition needs exactly that, a
|
|
33
|
-
# position copied off the board every ply. Spelled `state(:name)` on
|
|
34
|
-
# the wire, read back by `Literal.read`; classified `kind: "state"` in
|
|
35
|
-
# a set's own source (`Behaviour::Mutation#classified_source`).
|
|
2
|
+
# A mutation source that reads the record's own state: `append: { knights: state(:knights) }`.
|
|
3
|
+
# A bare Symbol in a mutation source names a command argument, so this is the only way to say it.
|
|
36
4
|
StateRef = Struct.new(:name) do
|
|
37
5
|
def to_s = "state(:#{name})"
|
|
38
6
|
end
|
|
39
7
|
|
|
40
|
-
# The
|
|
41
|
-
#
|
|
42
|
-
#
|
|
8
|
+
# The one wire spelling for a Ruby literal captured from a bluebook: a symbol wears its
|
|
9
|
+
# colon, a string its quotes, a hash `{key: value}`, a list brackets; the rest are bare.
|
|
10
|
+
# Stated here, not left to `inspect`, whose Hash rendering differs between Ruby 3.3 and 3.4.
|
|
43
11
|
module Literal
|
|
44
12
|
module_function
|
|
45
13
|
|
|
@@ -63,16 +31,9 @@ module Hecks
|
|
|
63
31
|
end
|
|
64
32
|
end
|
|
65
33
|
|
|
66
|
-
#
|
|
67
|
-
#
|
|
68
|
-
# never rendered, and those must stay the strings they are.
|
|
34
|
+
# Parses a wire spelling back into a Ruby value; the exact inverse of `render`.
|
|
35
|
+
# A bare word stays a String, since some fields are stored as plain text, never rendered.
|
|
69
36
|
#
|
|
70
|
-
# The exact inverse of `render`'s `case`, above — one ordered guard per
|
|
71
|
-
# spelling `render` can produce (plus the bare-word tolerance this
|
|
72
|
-
# comment already explains). Each guard is a single self-contained
|
|
73
|
-
# `return`; splitting them into named predicates would just rename
|
|
74
|
-
# each line without changing what it does, and would separate this
|
|
75
|
-
# method from the `render` it is the deliberate mirror of.
|
|
76
37
|
# @param text [String, #to_s] wire spelling produced by `render`, or a bare word
|
|
77
38
|
# @return [Object] nil, true, false, Integer, Float, Symbol, StateRef, String,
|
|
78
39
|
# Hash, or Array — or `text` itself, stripped, when it matches no known spelling
|
|
@@ -131,10 +92,7 @@ module Hecks
|
|
|
131
92
|
# @return [Array<Object>] the parsed values, each read recursively via `read`
|
|
132
93
|
def read_array(raw) = split_items(raw[1..-2]).map { |item| read(item) }
|
|
133
94
|
|
|
134
|
-
#
|
|
135
|
-
# quoted string or a nested brace/bracket. Scanned rather than
|
|
136
|
-
# `String#split(", ")`, which tore `"a, b"` in half and lost the second
|
|
137
|
-
# field of anything nested.
|
|
95
|
+
# Splits on separator commas only, never one inside a quoted string or nested brace/bracket.
|
|
138
96
|
#
|
|
139
97
|
# @param body [String] the text between a literal's outer braces or brackets
|
|
140
98
|
# @return [Array<String>] each item's raw text, stripped, with empty items dropped
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
require_relative "runtime/errors"
|
|
2
|
+
|
|
3
|
+
module Hecks
|
|
4
|
+
# What a spawned bin/hecks_mcp_door may do: every tool by default, or only
|
|
5
|
+
# reader tools against named domains in reader mode — reach, not identity (ADR 0072).
|
|
6
|
+
class McpDoorScope
|
|
7
|
+
ENV_PREFIX = "HECKS_DOOR_".freeze
|
|
8
|
+
TOOLS_VARIABLE = "HECKS_DOOR_TOOLS".freeze
|
|
9
|
+
DOMAINS_VARIABLE = "HECKS_DOOR_DOMAINS".freeze
|
|
10
|
+
READERS = "readers".freeze
|
|
11
|
+
EXIT_STATUS = 2
|
|
12
|
+
|
|
13
|
+
# The tools a reader door serves — each reads a domain or the door's own
|
|
14
|
+
# audit log and writes no domain state. `validate` still boots its
|
|
15
|
+
# domain, so it stays bound to the allowed set like every other tool.
|
|
16
|
+
READER_TOOLS = %w[query events state catalog describe validate domains history follow].freeze
|
|
17
|
+
|
|
18
|
+
# Unrestricted when no HECKS_DOOR_* variable is set.
|
|
19
|
+
def self.from_env(env = ENV)
|
|
20
|
+
problems = setting_problems(env)
|
|
21
|
+
raise ArgumentError, problems.join("\n") unless problems.empty?
|
|
22
|
+
return new(allowed_domains: nil) unless env[TOOLS_VARIABLE]
|
|
23
|
+
|
|
24
|
+
new(allowed_domains: env[DOMAINS_VARIABLE].split(File::PATH_SEPARATOR).reject(&:empty?))
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Refuses to stderr, not stdout, which carries the MCP protocol.
|
|
28
|
+
def self.start!(server:, env: ENV, stderr: $stderr)
|
|
29
|
+
from_env(env)
|
|
30
|
+
rescue ArgumentError, Runtime::TypeMismatch => e
|
|
31
|
+
e.message.each_line { |line| stderr.puts("#{server}: refusing to start: #{line.chomp}") }
|
|
32
|
+
exit(EXIT_STATUS)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.setting_problems(env)
|
|
36
|
+
unknown = env.keys.select { |name| name.start_with?(ENV_PREFIX) } - [TOOLS_VARIABLE, DOMAINS_VARIABLE]
|
|
37
|
+
problems = unknown.map do |name|
|
|
38
|
+
"environment #{name} is not accepted; the door takes only #{TOOLS_VARIABLE} and #{DOMAINS_VARIABLE}"
|
|
39
|
+
end
|
|
40
|
+
problems + mode_problems(env[TOOLS_VARIABLE], env[DOMAINS_VARIABLE])
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def self.mode_problems(tools, domains)
|
|
44
|
+
if tools.nil?
|
|
45
|
+
domains.nil? ? [] : ["#{DOMAINS_VARIABLE} is set without #{TOOLS_VARIABLE}=#{READERS}; it only narrows a reader door"]
|
|
46
|
+
elsif tools != READERS
|
|
47
|
+
["#{TOOLS_VARIABLE}=#{tools.inspect} is not accepted; the only value is #{READERS.inspect}"]
|
|
48
|
+
elsif domains.to_s.split(File::PATH_SEPARATOR).none? { |path| !path.empty? }
|
|
49
|
+
["#{TOOLS_VARIABLE}=#{READERS} needs #{DOMAINS_VARIABLE}, the domains this door may read"]
|
|
50
|
+
else
|
|
51
|
+
[]
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# The named domains, resolved against Storehouse::BOOT_ROOT; nil when unrestricted.
|
|
56
|
+
attr_reader :allowed_domains
|
|
57
|
+
|
|
58
|
+
def initialize(allowed_domains:)
|
|
59
|
+
@allowed_domains = allowed_domains&.map { |path| Storehouse.confine!(path, DOMAINS_VARIABLE) }.freeze
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def restricted?
|
|
63
|
+
!@allowed_domains.nil?
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def permits_tool?(name)
|
|
67
|
+
!restricted? || READER_TOOLS.include?(name)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def refusal(name)
|
|
71
|
+
{ ok: false,
|
|
72
|
+
error: "#{name.inspect} is refused: this door runs in reader mode (#{TOOLS_VARIABLE}=#{READERS}), " \
|
|
73
|
+
"which serves only #{READER_TOOLS.join(', ')}" }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Checked before anything boots, so a path outside the allowed set never reaches Kernel.load.
|
|
77
|
+
def admit_domain!(domain)
|
|
78
|
+
return domain unless restricted?
|
|
79
|
+
return domain if @allowed_domains.include?(Storehouse.confine!(domain, "domain"))
|
|
80
|
+
|
|
81
|
+
raise Runtime::TypeMismatch,
|
|
82
|
+
"domain: #{domain.inspect} is refused: this door runs in reader mode (#{TOOLS_VARIABLE}=#{READERS}) " \
|
|
83
|
+
"and reads only #{DOMAINS_VARIABLE}: #{@allowed_domains.join(', ')}"
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def notes
|
|
87
|
+
return [] unless restricted?
|
|
88
|
+
|
|
89
|
+
["Reader mode (#{TOOLS_VARIABLE}=#{READERS}): serves #{READER_TOOLS.join(', ')}; " \
|
|
90
|
+
"refuses dispatch (with dry_run and steps), behaviors and every other tool.",
|
|
91
|
+
"domain: boots only #{DOMAINS_VARIABLE}: #{@allowed_domains.join(', ')}.",
|
|
92
|
+
"Reader mode limits reach and identifies no one; it is not authentication."]
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -1,41 +1,8 @@
|
|
|
1
1
|
require "socket"
|
|
2
2
|
|
|
3
3
|
module Hecks
|
|
4
|
-
#
|
|
5
|
-
# `
|
|
6
|
-
# speak to anything but a local parent, and it says on stderr what the
|
|
7
|
-
# process does and does not protect.
|
|
8
|
-
#
|
|
9
|
-
# ## Why a gate and not a comment
|
|
10
|
-
#
|
|
11
|
-
# Both servers have no authentication. What keeps a stranger away from
|
|
12
|
-
# them is that only a process that can spawn them can write to their
|
|
13
|
-
# stdin. That holds until someone wraps one in `socat TCP-LISTEN:... EXEC:`
|
|
14
|
-
# or an `inetd`-style listener, which hands the process a network socket
|
|
15
|
-
# as stdin/stdout without changing a line of the server. The gate turns
|
|
16
|
-
# that setup into a refusal at startup instead of an exposure nobody
|
|
17
|
-
# noticed.
|
|
18
|
-
#
|
|
19
|
-
# ## What it checks
|
|
20
|
-
#
|
|
21
|
-
# - **Arguments** — none, except `--stdio`. A `--port` or `--http` flag is
|
|
22
|
-
# refused rather than ignored, so a caller that believes it started a
|
|
23
|
-
# network server finds out immediately.
|
|
24
|
-
# - **Environment** — no `HECKS_MCP_*` variable except
|
|
25
|
-
# `HECKS_MCP_TRANSPORT=stdio`. The servers take no configuration, so an
|
|
26
|
-
# unknown option in that namespace fails closed.
|
|
27
|
-
# - **Descriptors** — stdin and stdout must not be internet-protocol sockets
|
|
28
|
-
# (`AF_INET` or `AF_INET6`). A pipe, a file, a terminal and a Unix-domain socket all pass;
|
|
29
|
-
# the last matters because some MCP clients spawn servers over a
|
|
30
|
-
# `socketpair`, which is local to the machine.
|
|
31
|
-
#
|
|
32
|
-
# ## What it does not do
|
|
33
|
-
#
|
|
34
|
-
# It does not authenticate anyone and it cannot see a proxy that copies
|
|
35
|
-
# bytes from a network socket into an ordinary pipe. It closes the
|
|
36
|
-
# configurations that announce themselves; the ADR on MCP authentication
|
|
37
|
-
# (`docs/decisions/0062-mcp-servers-need-real-authentication-before-any-network-transport.md`)
|
|
38
|
-
# covers what a network transport would need.
|
|
4
|
+
# Startup gate for the stdio MCP servers in `bin/`: refuses network sockets, extra flags and
|
|
5
|
+
# unknown `HECKS_MCP_*` variables. It is not authentication (ADR 0062).
|
|
39
6
|
module McpStdioGuard
|
|
40
7
|
ACCEPTED_ARGS = %w[--stdio].freeze
|
|
41
8
|
ENV_PREFIX = "HECKS_MCP_".freeze
|
|
@@ -71,12 +38,8 @@ module Hecks
|
|
|
71
38
|
(COMMON_NOTES + notes).map { |line| "#{server}: #{line}" }
|
|
72
39
|
end
|
|
73
40
|
|
|
74
|
-
# Refuses to continue on a non-stdio setup.
|
|
75
|
-
#
|
|
76
|
-
# A server calls this before it requires anything heavy, so a misconfigured start
|
|
77
|
-
# fails in milliseconds and before any protocol byte is answered. Everything goes
|
|
78
|
-
# to `stderr`: stdout carries the MCP protocol, and one stray line there corrupts
|
|
79
|
-
# the client's framing.
|
|
41
|
+
# Refuses to continue on a non-stdio setup. Everything goes to `stderr`: stdout
|
|
42
|
+
# carries the MCP protocol, and a stray line there corrupts the client's framing.
|
|
80
43
|
#
|
|
81
44
|
# @param server [String] the server's name, used as the line prefix
|
|
82
45
|
# @param argv [Array<String>] the command-line arguments
|