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
|
@@ -5,48 +5,25 @@ module Hecks
|
|
|
5
5
|
module Bluebook
|
|
6
6
|
Invariant = Struct.new(:description, :canonical, :predicate, :ast, keyword_init: true)
|
|
7
7
|
|
|
8
|
-
# A value object
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
# calls `.new` on one — coercion builds `Runtime::Value` wrappers, and
|
|
13
|
-
# invariants run as canonical text through the Evaluator. The runtime
|
|
14
|
-
# reaches a shape through `aggregate.value_object(name)`, the IR's own
|
|
15
|
-
# finder ; there is no constant nesting and no second index.
|
|
16
|
-
#
|
|
17
|
-
# `to_h` does not move. It is a byte-for-byte contract pinned by the
|
|
18
|
-
# golden fixtures, so it keeps spelling the short declared name, which
|
|
19
|
-
# is what `hecks_name` carries. Declarations in the graph, strings in the
|
|
20
|
-
# export.
|
|
8
|
+
# A value object: a declaration holder, never instantiated.
|
|
9
|
+
# `ValueObjectBuilder` returns a subclass carrying attributes, invariants and members;
|
|
10
|
+
# reach one through `aggregate.value_object(name)`.
|
|
11
|
+
# `to_h` spells the short declared name (`hecks_name`), a contract pinned by golden fixtures.
|
|
21
12
|
class ValueObject
|
|
22
13
|
extend Construct
|
|
23
|
-
# Extended, not included
|
|
24
|
-
# emission is a class method. See Hecks::IR's own note on
|
|
25
|
-
# the two shapes.
|
|
14
|
+
# Extended, not included: this construct is a class, so emission is a class method.
|
|
26
15
|
extend Hecks::IR
|
|
27
16
|
extend Behaviour::ValueObject
|
|
28
17
|
|
|
29
18
|
emits_ir(
|
|
30
19
|
name: :hecks_name,
|
|
31
20
|
attributes: many(:attributes),
|
|
32
|
-
# `ast
|
|
33
|
-
#
|
|
34
|
-
# replacing it (`canonical` stays the human-facing/doctest-facing
|
|
35
|
-
# form; parsing it back would just re-derive what `ast` already
|
|
36
|
-
# states directly). Ground truth and the full reasoning:
|
|
37
|
-
# `Expression::AstJson`'s own header — built for `rust/host`'s
|
|
38
|
-
# own mint-time invariant check (`reference_validate.rs`), which
|
|
39
|
-
# has no kernel crate to parse `canonical` with.
|
|
21
|
+
# `ast` sits beside `canonical` because rust/host's mint-time invariant check
|
|
22
|
+
# has no kernel crate to parse `canonical` with (see `Expression::AstJson`).
|
|
40
23
|
invariants: -> { invariants.map { |rule| Expression::AstJson.rule_row(rule) } },
|
|
41
24
|
closed_set: :closed_set?,
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
# (`StatementFrequency#retention_months`, statements.bluebook), not
|
|
45
|
-
# only `String` — and stringifying it on the way out would erase
|
|
46
|
-
# that: `84` and `"84"` (a member some other row might legitimately
|
|
47
|
-
# spell as text) would become indistinguishable once they reached
|
|
48
|
-
# `to_h`. The declared name still moves (`field.to_s`) — that half
|
|
49
|
-
# was never a Ruby object with a type to lose.
|
|
25
|
+
# Only the field name is stringified: a member value can be an Integer, and
|
|
26
|
+
# stringifying it would make `84` and `"84"` indistinguishable in `to_h`.
|
|
50
27
|
members: -> { members.map { |member| member.map { |field, value| [field.to_s, value] } } }
|
|
51
28
|
)
|
|
52
29
|
|
|
@@ -57,10 +34,8 @@ module Hecks
|
|
|
57
34
|
# the bluebook declares and the thing Ruby holds are one object.
|
|
58
35
|
#
|
|
59
36
|
# @param name [String, Symbol] the value object's declared type name
|
|
60
|
-
# @param attributes [Array<Bluebook::Attribute>] the value object's declared
|
|
61
|
-
#
|
|
62
|
-
# @param invariants [Array<Bluebook::Invariant>] the rules checked against every
|
|
63
|
-
# instance of this value object
|
|
37
|
+
# @param attributes [Array<Bluebook::Attribute>] the value object's declared fields
|
|
38
|
+
# @param invariants [Array<Bluebook::Invariant>] the rules checked against every instance
|
|
64
39
|
# @param members [Array<Hash{Symbol => Object}>] the declared `one_of` members, one
|
|
65
40
|
# row of field values per member
|
|
66
41
|
# @param closed_set [Boolean] whether a `one_of` was declared, even with no
|
data/lib/hecks/bluebook.rb
CHANGED
|
@@ -1,36 +1,19 @@
|
|
|
1
|
-
#
|
|
2
|
-
#
|
|
3
|
-
# Everything a .bluebook file becomes on its way to running: the expression
|
|
4
|
-
# language (expression/), the model itself (the chapter class plus
|
|
5
|
-
# everything it declares), the assembly that turns
|
|
6
|
-
# declarations back into that graph (assembly.rb + assembly/), the authoring
|
|
7
|
-
# DSL (dsl/), and the meta-validator that judges a chapter against the
|
|
8
|
-
# language's own grammar (meta_validator.rb + meta_validator/).
|
|
9
|
-
#
|
|
10
|
-
# The require order below matters: expression and IR load first (pure
|
|
11
|
-
# declarations), assembly's collaborators load before its face, and the DSL
|
|
12
|
-
# loads before the meta-validator that its builders call at build time.
|
|
1
|
+
# Everything a .bluebook file becomes on its way to running: expression language, model,
|
|
2
|
+
# assembly, authoring DSL and meta-validator.
|
|
13
3
|
|
|
14
4
|
module Hecks
|
|
15
|
-
#
|
|
16
|
-
# chapter (bluebook/chapter.rb carries its body). Everything a chapter
|
|
17
|
-
# declares nests under it, as do the ways to build one (`DSL`) and to
|
|
18
|
-
# judge one (`MetaValidator`). Reopening this anywhere must say `class`.
|
|
5
|
+
# `Hecks::Bluebook` is a class defined in bluebook/chapter.rb; reopen it with `class`.
|
|
19
6
|
module Bluebook
|
|
20
7
|
end
|
|
21
8
|
end
|
|
22
9
|
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
# because those files' contents are frozen and cannot say so themselves.
|
|
10
|
+
# Required here because the chapter's frozen files lean on these at class-body level.
|
|
11
|
+
# Load order: expression and IR first, assembly's collaborators before its face, DSL last.
|
|
26
12
|
require_relative "construct"
|
|
27
13
|
require_relative "literal"
|
|
28
14
|
require_relative "query_specification"
|
|
29
15
|
|
|
30
16
|
require_relative "bluebook/expression"
|
|
31
|
-
# **The model itself** — the chapter class's own body first, then everything
|
|
32
|
-
# a chapter declares. Order matters only for reading: each is a bag of
|
|
33
|
-
# declarations with no load-time cross-references.
|
|
34
17
|
require_relative "bluebook/chapter"
|
|
35
18
|
require_relative "bluebook/reference"
|
|
36
19
|
require_relative "bluebook/attribute"
|
data/lib/hecks/cache_dir.rb
CHANGED
|
@@ -3,30 +3,11 @@ require "fileutils"
|
|
|
3
3
|
require "tmpdir"
|
|
4
4
|
|
|
5
5
|
module Hecks
|
|
6
|
-
# The one place the runtime's own scratch files live, outside the gem
|
|
6
|
+
# The one place the runtime's own scratch files live, outside the gem: an
|
|
7
|
+
# installed gem is read-only, and a checkout's `tmp/` isn't this library's to assume.
|
|
7
8
|
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
# installed gem is read-only, and a checkout's `tmp/` is not a place a
|
|
11
|
-
# library gets to assume. Both ask this module for a subdirectory instead.
|
|
12
|
-
#
|
|
13
|
-
# ## Where the root is
|
|
14
|
-
#
|
|
15
|
-
# The first of these that can be made a private directory wins:
|
|
16
|
-
#
|
|
17
|
-
# 1. `$XDG_CACHE_HOME/hecks`, when `XDG_CACHE_HOME` is set to an absolute path
|
|
18
|
-
# 2. `~/.cache/hecks`
|
|
19
|
-
# 3. `<system temp dir>/hecks-<uid>`
|
|
20
|
-
#
|
|
21
|
-
# ## Private, or not used
|
|
22
|
-
#
|
|
23
|
-
# The syntax-boot cache is read back with `Marshal.load`, so a directory
|
|
24
|
-
# another account can write to is a way to run code as this one. A
|
|
25
|
-
# candidate is accepted only if it is owned by the current user and
|
|
26
|
-
# writable by nobody else; the shared temp directory in particular is
|
|
27
|
-
# where a predictable name can be planted by someone else. When no candidate
|
|
28
|
-
# qualifies, a fresh per-process directory stands in: the cache still
|
|
29
|
-
# works within the process and is never shared with a stranger.
|
|
9
|
+
# A candidate root is used only if it is private to the current user, since the
|
|
10
|
+
# syntax-boot cache it holds is read back with `Marshal.load`.
|
|
30
11
|
module CacheDir
|
|
31
12
|
module_function
|
|
32
13
|
|
data/lib/hecks/cli/document.rb
CHANGED
|
@@ -5,23 +5,7 @@ module Hecks
|
|
|
5
5
|
# The command behind `bin/docs`, `bin/narrate`, `hecks docs` and `hecks narrate`:
|
|
6
6
|
# one domain's document, projected from its own bluebook, to stdout.
|
|
7
7
|
#
|
|
8
|
-
#
|
|
9
|
-
# answers the same chapter read back in English, for the subject-matter expert
|
|
10
|
-
# (`Projector::NarrateProjector`). Nothing is written for the caller: redirect it,
|
|
11
|
-
# so the caller decides where a generated file lands and git decides whether it
|
|
12
|
-
# drifted.
|
|
13
|
-
#
|
|
14
|
-
# ## Every failure is a sentence
|
|
15
|
-
#
|
|
16
|
-
# A misspelled aggregate refuses by name rather than printing nothing and exiting
|
|
17
|
-
# 0. A caller cannot tell an empty document from an empty domain, so this refuses
|
|
18
|
-
# instead and names what is actually there.
|
|
19
|
-
#
|
|
20
|
-
# ## Standing in a domain is enough
|
|
21
|
-
#
|
|
22
|
-
# `Adapters::Folder#domain_root` walks up for the nearest `.hecksagon`, which makes
|
|
23
|
-
# the first argument ambiguous. The rule: a directory is a domain, anything else
|
|
24
|
-
# is an aggregate name, and the two-argument form says which is which.
|
|
8
|
+
# Nothing is written for the caller: redirect it, so git decides whether it drifted.
|
|
25
9
|
module Document
|
|
26
10
|
# Build output and other trees under a root that hold no domain a caller means.
|
|
27
11
|
# Matched against the path relative to the root, because a substring test
|
|
@@ -66,10 +50,8 @@ module Hecks
|
|
|
66
50
|
|
|
67
51
|
# Lists every directory under `root` that `Hecks.boot` would accept.
|
|
68
52
|
#
|
|
69
|
-
# Found by their wiring, not their chapters: a `.hecksagon`
|
|
70
|
-
#
|
|
71
|
-
# `.bluebook` files (era translations, the language's own grammar,
|
|
72
|
-
# `spec/fixtures`) are not domains anybody boots.
|
|
53
|
+
# Found by their wiring, not their chapters: a `.hecksagon` says this is a
|
|
54
|
+
# domain, while most `.bluebook` files (era translations, grammar, fixtures) are not.
|
|
73
55
|
#
|
|
74
56
|
# @param root [String] the directory to search under
|
|
75
57
|
# @return [Array<String>] domain directory paths relative to `root`,
|
data/lib/hecks/cli/ir.rb
CHANGED
|
@@ -6,17 +6,15 @@ require_relative "../ports/persistence/plugins/era"
|
|
|
6
6
|
module Hecks
|
|
7
7
|
module CLI
|
|
8
8
|
# The command behind `bin/ir` and `hecks ir`: a booted domain's IR as JSON, the
|
|
9
|
-
# same `to_h` the golden specs pin and `StorageShape` hashes into an era
|
|
10
|
-
# reading rather than asserting on.
|
|
9
|
+
# same `to_h` the golden specs pin and `StorageShape` hashes into an era.
|
|
11
10
|
module Ir
|
|
12
11
|
module_function
|
|
13
12
|
|
|
14
13
|
# Prints the IR `argv` asks for.
|
|
15
14
|
#
|
|
16
|
-
# `--meta` prints the language's own IR,
|
|
17
|
-
# `lib/hecks/language/bluebook/` merged into one. It is reached through
|
|
15
|
+
# `--meta` prints the language's own IR, reached through
|
|
18
16
|
# `Bluebook::MetaValidator.grammar_registry`, the real boot sequence, so it
|
|
19
|
-
#
|
|
17
|
+
# can't drift from what `MetaValidator` loads.
|
|
20
18
|
#
|
|
21
19
|
# @param argv [Array<String>] a domain path and `--translations`, or `--meta`
|
|
22
20
|
# @param program [String] the name the usage message calls this command by
|
data/lib/hecks/cli/mcp.rb
CHANGED
|
@@ -5,9 +5,8 @@ module Hecks
|
|
|
5
5
|
# The command behind `bin/hecks_mcp_door` and `hecks mcp`: the MCP door onto the
|
|
6
6
|
# storehouse bus, over stdio only.
|
|
7
7
|
#
|
|
8
|
-
# This file loads nothing but `McpStdioGuard`, so the transport check runs
|
|
9
|
-
# the framework does.
|
|
10
|
-
# passes.
|
|
8
|
+
# This file loads nothing but `McpStdioGuard`, so the transport check runs
|
|
9
|
+
# before the framework does.
|
|
11
10
|
module Mcp
|
|
12
11
|
# The server name the guard's refusals and warnings carry.
|
|
13
12
|
SERVER = "hecks-mcp-door".freeze
|
data/lib/hecks/cli/mcp_door.rb
CHANGED
|
@@ -4,56 +4,17 @@ require_relative "mcp"
|
|
|
4
4
|
|
|
5
5
|
module Hecks
|
|
6
6
|
module CLI
|
|
7
|
-
# The MCP door onto the storehouse bus:
|
|
8
|
-
#
|
|
9
|
-
#
|
|
7
|
+
# The MCP door onto the storehouse bus: hand-rolled JSON-RPC over stdio, one
|
|
8
|
+
# server per booted domain. All logic and the JSON shape answered with live in
|
|
9
|
+
# `Storehouse`; this is plumbing only. A `role:`/`actor_id:` a caller sends is
|
|
10
|
+
# asserted, not verified, unless Governance is attached.
|
|
10
11
|
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
# ## Identity is asserted, not verified
|
|
19
|
-
#
|
|
20
|
-
# `dispatch` and `query` take `role:` and `actor_id:`, bound for the call through
|
|
21
|
-
# `Hecks.as_caller`, so a role-gated command is checked against them rather than
|
|
22
|
-
# merely documented by `describe`; `dispatch` refuses a role-declaring command
|
|
23
|
-
# called without one. Nothing here verifies the claim beyond the string (or, with
|
|
24
|
-
# Governance attached, a `Governance::RoleAssignment` lookup). The readers take
|
|
25
|
-
# no role, and `query` gates on none.
|
|
26
|
-
#
|
|
27
|
-
# ## Stdio only, enforced
|
|
28
|
-
#
|
|
29
|
-
# The door has no authentication. `Mcp.call` runs
|
|
30
|
-
# `McpStdioGuard.enforce_stdio!` before this file loads, and `serve` prints the
|
|
31
|
-
# warning to stderr, never stdout, which carries the protocol. `domain:` is
|
|
32
|
-
# confined to `Storehouse::BOOT_ROOT` (`confine!`), but a domain within that
|
|
33
|
-
# root still boots real Ruby, so this is a code execution surface for anyone who
|
|
34
|
-
# can write to stdin. A network transport needs authentication first; see
|
|
35
|
-
# `docs/decisions/0062-mcp-servers-need-real-authentication-before-any-network-transport.md`.
|
|
36
|
-
#
|
|
37
|
-
# ## Reader mode
|
|
38
|
-
#
|
|
39
|
-
# Whoever spawns the door can narrow it with `HECKS_DOOR_TOOLS=readers` and
|
|
40
|
-
# `HECKS_DOOR_DOMAINS=<dir>[:<dir>...]` (`Hecks::McpDoorScope`, ADR 0072 decision 2).
|
|
41
|
-
# A reader door serves only `McpDoorScope::READER_TOOLS` (`query`, `events`,
|
|
42
|
-
# `state`, `catalog`, `describe`, `validate`, `domains`, `history`, `follow`), lists
|
|
43
|
-
# only those in `tools/list`, and refuses `dispatch` (so `dry_run` and `steps` too),
|
|
44
|
-
# `behaviors` and any other name with an answer that names the mode. Its `domain:`
|
|
45
|
-
# must resolve to one of the named directories, checked before anything boots, so no
|
|
46
|
-
# other domain's Ruby is loaded. The door keeps no domain loaded between calls, so
|
|
47
|
-
# the named list is the whole allowed set. This limits what one spawned agent can
|
|
48
|
-
# reach; it identifies no one and is not authentication. The names sit outside
|
|
49
|
-
# `HECKS_MCP_*` because the stdio guard refuses every name in that prefix but the
|
|
50
|
-
# transport, and that refusal belongs to ADR 0062. With neither variable set, the
|
|
51
|
-
# door serves every tool as described above.
|
|
52
|
-
#
|
|
53
|
-
# ## One boot per call
|
|
54
|
-
#
|
|
55
|
-
# `Hecks.boot(domain, install_facade: false)` is cheap, and it lets one server
|
|
56
|
-
# answer calls against two domains back to back with no shared, staling state.
|
|
12
|
+
# There is no authentication: `domain:` boots real Ruby confined to
|
|
13
|
+
# `Storehouse::BOOT_ROOT`, so this is a code execution surface for anyone who
|
|
14
|
+
# can write to stdin (ADR 0062). Spawning with `HECKS_DOOR_TOOLS=readers` and
|
|
15
|
+
# `HECKS_DOOR_DOMAINS=<dir>[:<dir>...]` narrows a door to read-only tools and
|
|
16
|
+
# named domains (`McpDoorScope`); this limits what one agent can reach and is
|
|
17
|
+
# not itself authentication.
|
|
57
18
|
module McpDoor
|
|
58
19
|
PROTOCOL_VERSION = "2024-11-05".freeze
|
|
59
20
|
|
|
@@ -271,27 +232,17 @@ module Hecks
|
|
|
271
232
|
|
|
272
233
|
module_function
|
|
273
234
|
|
|
274
|
-
#
|
|
275
|
-
#
|
|
276
|
-
# so a bad setting refuses to start the door before anything is written to stdout.
|
|
277
|
-
#
|
|
278
|
-
# @return [McpDoorScope]
|
|
235
|
+
# Read once, so a bad setting refuses to start the door before anything is
|
|
236
|
+
# written to stdout.
|
|
279
237
|
def scope
|
|
280
238
|
@scope ||= McpDoorScope.start!(server: Mcp::SERVER)
|
|
281
239
|
end
|
|
282
240
|
|
|
283
|
-
# The
|
|
284
|
-
# scope says about `domain:`.
|
|
285
|
-
#
|
|
286
|
-
# @return [Array<String>]
|
|
241
|
+
# The standing notes, then what this door's scope says about `domain:`.
|
|
287
242
|
def warning_notes
|
|
288
243
|
NOTES[0, 2] + (scope.restricted? ? scope.notes : [NOTES[2]])
|
|
289
244
|
end
|
|
290
245
|
|
|
291
|
-
# Prints the stdio warning to stderr, then answers one JSON-RPC request per
|
|
292
|
-
# line of `$stdin` until it closes.
|
|
293
|
-
#
|
|
294
|
-
# @return [void]
|
|
295
246
|
def serve
|
|
296
247
|
McpStdioGuard.warn!(server: Mcp::SERVER, notes: warning_notes)
|
|
297
248
|
$stdout.sync = true
|
|
@@ -315,29 +266,14 @@ module Hecks
|
|
|
315
266
|
end
|
|
316
267
|
end
|
|
317
268
|
|
|
318
|
-
#
|
|
319
|
-
#
|
|
320
|
-
# @param domain [String] the domain directory, e.g. `"examples/banking"`
|
|
321
|
-
# @return [Runtime::Dispatcher, Runtime::RemoteDispatcher] the booted domain
|
|
322
|
-
# @raise [Runtime::TypeMismatch] if `domain` resolves outside `Storehouse::BOOT_ROOT`, or,
|
|
323
|
-
# on a reader door, outside `HECKS_DOOR_DOMAINS`
|
|
324
|
-
# @raise [Runtime::WiringError] if the domain fails to boot
|
|
269
|
+
# `domain:` is confined to `Storehouse::BOOT_ROOT`, and further to a reader
|
|
270
|
+
# door's `HECKS_DOOR_DOMAINS`, before anything boots.
|
|
325
271
|
def boot(domain)
|
|
326
272
|
Hecks.boot(Storehouse.confine!(scope.admit_domain!(domain), "domain"), install_facade: false)
|
|
327
273
|
end
|
|
328
274
|
|
|
329
|
-
#
|
|
330
|
-
#
|
|
331
|
-
# A closed-set dispatch table, one `when` per tool, so the size is the tool
|
|
332
|
-
# count and the shared `rescue` catches every branch's escape once.
|
|
333
|
-
#
|
|
334
|
-
# @param name [String] the tool name, one of `TOOLS`'s own `:name` values
|
|
335
|
-
# @param args [Hash{String => Object}] the tool's JSON arguments, shaped per that
|
|
336
|
-
# tool's `inputSchema`
|
|
337
|
-
# @return [Hash{Symbol => Object}] the delegated `Storehouse` result on a known
|
|
338
|
-
# tool name; `{ok: false, error: String}` for an unknown tool name or any
|
|
339
|
-
# `StandardError` this door did not anticipate (a domain refusal is already
|
|
340
|
-
# `{ok: false, ...}` from inside `Storehouse` itself)
|
|
275
|
+
# One `when` per tool, so the shared `rescue` catches every branch's escape
|
|
276
|
+
# once; a domain refusal is already `{ok: false, ...}` from `Storehouse`.
|
|
341
277
|
def call_tool(name, args) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
342
278
|
case name
|
|
343
279
|
when "dispatch"
|
|
@@ -378,60 +314,29 @@ module Hecks
|
|
|
378
314
|
{ ok: false, error: "no such tool: #{name.inspect} — known: #{TOOLS.map { |t| t[:name] }.join(', ')}" }
|
|
379
315
|
end
|
|
380
316
|
rescue StandardError => e
|
|
381
|
-
#
|
|
382
|
-
#
|
|
383
|
-
# domain path or an argument shape `Facade::JsonDoor` could not symbolize,
|
|
384
|
-
# still answered as structured content rather than an MCP-level `isError`,
|
|
385
|
-
# so a calling agent reads one shape for every outcome.
|
|
317
|
+
# A defect, not a refusal: reaching here means a bad domain path or an
|
|
318
|
+
# argument shape `Facade::JsonDoor` could not symbolize.
|
|
386
319
|
{ ok: false, error: "#{e.class}: #{e.message}" }
|
|
387
320
|
end
|
|
388
321
|
|
|
389
|
-
# Runs one MCP tool call if this door's mode serves it, and refuses it otherwise.
|
|
390
|
-
#
|
|
391
|
-
# @param name [String] the tool name from the `tools/call` request
|
|
392
|
-
# @param args [Hash{String => Object}] the tool's JSON arguments
|
|
393
|
-
# @return [Hash{Symbol => Object}] the `call_tool` result, or `scope.refusal(name)`
|
|
394
|
-
# when a reader door does not serve `name`
|
|
395
322
|
def answer_tool(name, args)
|
|
396
323
|
return scope.refusal(name) unless scope.permits_tool?(name)
|
|
397
324
|
|
|
398
325
|
call_tool(name, args)
|
|
399
326
|
end
|
|
400
327
|
|
|
401
|
-
# Wraps a `call_tool` payload in the MCP `tools/call` result shape.
|
|
402
|
-
#
|
|
403
|
-
# @param payload [Hash{Symbol => Object}] a `call_tool` result
|
|
404
|
-
# @return [Hash{Symbol => Object}] `{content: [{type: "text", text: ...}], isError: Boolean}`,
|
|
405
|
-
# pretty-printing `payload` as the text and setting `isError` from `payload[:ok]`
|
|
406
328
|
def tool_result(payload)
|
|
407
329
|
{ content: [{ type: "text", text: JSON.pretty_generate(payload) }], isError: payload[:ok] == false }
|
|
408
330
|
end
|
|
409
331
|
|
|
410
|
-
# Writes one JSON-RPC success response line to stdout.
|
|
411
|
-
#
|
|
412
|
-
# @param id [String, Integer, nil] the request's own `id`, echoed back
|
|
413
|
-
# @param result [Object] the JSON-serializable result payload
|
|
414
|
-
# @return [void]
|
|
415
332
|
def send_response(id, result)
|
|
416
333
|
puts JSON.generate({ jsonrpc: "2.0", id: id, result: result })
|
|
417
334
|
end
|
|
418
335
|
|
|
419
|
-
# Writes one JSON-RPC error response line to stdout.
|
|
420
|
-
#
|
|
421
|
-
# @param id [String, Integer, nil] the request's own `id`, echoed back; nil when
|
|
422
|
-
# the request itself could not be parsed
|
|
423
|
-
# @param code [Integer] the JSON-RPC error code
|
|
424
|
-
# @param message [String] the error message
|
|
425
|
-
# @return [void]
|
|
426
336
|
def send_error(id, code, message)
|
|
427
337
|
puts JSON.generate({ jsonrpc: "2.0", id: id, error: { code: code, message: message } })
|
|
428
338
|
end
|
|
429
339
|
|
|
430
|
-
# Dispatches one parsed JSON-RPC request to its method and writes the response.
|
|
431
|
-
#
|
|
432
|
-
# @param request [Hash{String => Object}] one parsed JSON-RPC request, with
|
|
433
|
-
# `"id"`, `"method"`, and optional `"params"`
|
|
434
|
-
# @return [void]
|
|
435
340
|
def handle(request)
|
|
436
341
|
id = request["id"]
|
|
437
342
|
method = request["method"]
|
|
@@ -5,26 +5,13 @@ module Hecks
|
|
|
5
5
|
module CLI
|
|
6
6
|
# The command behind `bin/model_check` and `hecks model_check`: static analysis
|
|
7
7
|
# over the IR, printed per domain, exiting non-zero when any error-severity
|
|
8
|
-
# finding is left
|
|
8
|
+
# finding is left — unreachable lifecycle states, dead transitions, unreached
|
|
9
|
+
# saga states, dispatches to a nonexistent command, handlers for an event
|
|
10
|
+
# nothing emits. The runtime checks none of these; a dead transition never
|
|
11
|
+
# fires, in silence.
|
|
9
12
|
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
# unreachable, dispatches to a command that does not exist, and handlers
|
|
13
|
-
# listening for an event nothing emits. The runtime checks none of these: a dead
|
|
14
|
-
# transition never fires, in silence.
|
|
15
|
-
#
|
|
16
|
-
# ## Named domains, or the whole corpus
|
|
17
|
-
#
|
|
18
|
-
# Given domain paths, it boots each and runs one cross-domain check across all
|
|
19
|
-
# of them. Given none, it sweeps the repository's corpus (`Corpus.model_check_members`)
|
|
20
|
-
# and the language's own chapters; that needs `root:`, the repository, so an
|
|
21
|
-
# installed gem without one asks for a domain path instead.
|
|
22
|
-
#
|
|
23
|
-
# ## Options
|
|
24
|
-
#
|
|
25
|
-
# `--strict` makes a `rust_reserved_name` finding an error for every target, not
|
|
26
|
-
# only for those with a Cargo feature under `root`'s `rust/Cargo.toml`.
|
|
27
|
-
# `--profile client` adds `Bluebook::ModelCheck::ClientProfile`'s error findings.
|
|
13
|
+
# Given domain paths it checks just those, cross-domain; given none it sweeps
|
|
14
|
+
# the repository's corpus and the language's own chapters, which needs `root:`.
|
|
28
15
|
module ModelCheck
|
|
29
16
|
# The directory the framework's own `.port` and `.adapter` files live under.
|
|
30
17
|
HECKS_DIR = File.expand_path("..", __dir__)
|
|
@@ -64,10 +51,6 @@ module Hecks
|
|
|
64
51
|
exit(ok ? 0 : 1)
|
|
65
52
|
end
|
|
66
53
|
|
|
67
|
-
# Reads `--profile client` or `--profile=client` and removes it from `argv`.
|
|
68
|
-
#
|
|
69
|
-
# @param argv [Array<String>] the arguments, changed in place
|
|
70
|
-
# @return [Symbol, nil] the requested profile, or nil when none was asked for
|
|
71
54
|
def take_profile(argv)
|
|
72
55
|
inline = argv.find { |arg| arg.start_with?("--profile=") }
|
|
73
56
|
index = argv.index("--profile")
|
|
@@ -79,13 +62,8 @@ module Hecks
|
|
|
79
62
|
name.to_sym
|
|
80
63
|
end
|
|
81
64
|
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
# is checked.
|
|
85
|
-
#
|
|
86
|
-
# @param domain_args [Array<String>] domain directory paths
|
|
87
|
-
# @param options [Options] the run's configuration
|
|
88
|
-
# @return [Boolean] true when every domain passes
|
|
65
|
+
# Examines every named domain against one shared set of known domains and
|
|
66
|
+
# emitted events, so a cross-domain reaction between two of them is checked.
|
|
89
67
|
def check_domains(domain_args, options)
|
|
90
68
|
booted = domain_args.map do |domain_arg|
|
|
91
69
|
[File.basename(domain_arg.chomp("/")), boot(bluebook_dir(domain_arg.chomp("/")) || domain_arg)]
|
|
@@ -93,15 +71,8 @@ module Hecks
|
|
|
93
71
|
examine_all(booted, options)
|
|
94
72
|
end
|
|
95
73
|
|
|
96
|
-
# Boots every corpus member once, then examines each against the set of names
|
|
97
|
-
# every member declares, then examines the language itself.
|
|
98
|
-
#
|
|
99
74
|
# Two passes over the same boots, because a single boot's own registry cannot
|
|
100
75
|
# answer whether a target domain exists anywhere in the corpus.
|
|
101
|
-
#
|
|
102
|
-
# @param root [String] the repository root
|
|
103
|
-
# @param options [Options] the run's configuration
|
|
104
|
-
# @return [Boolean] true when every member and the language pass
|
|
105
76
|
def check_corpus(root, options)
|
|
106
77
|
require_relative "../corpus"
|
|
107
78
|
targets = Corpus.model_check_members(root: root).map { |member| [member.stem, Corpus.source_of(member)] }
|
|
@@ -110,17 +81,8 @@ module Hecks
|
|
|
110
81
|
examine_language(options) && ok
|
|
111
82
|
end
|
|
112
83
|
|
|
113
|
-
#
|
|
114
|
-
#
|
|
115
|
-
#
|
|
116
|
-
# `root:` is the source's parent: a directory source is already the domain's
|
|
117
|
-
# own `bluebook/` folder, and without a root a member declaring
|
|
118
|
-
# `uses_embryonaut_bluebook` refuses with "needs a registry with a root to
|
|
119
|
-
# vendor from".
|
|
120
|
-
#
|
|
121
|
-
# @param source [String] a directory to boot (every bluebook within), or a
|
|
122
|
-
# single `.bluebook` file path
|
|
123
|
-
# @return [Runtime::Registry] the registry populated with the booted bluebooks
|
|
84
|
+
# `root:` is the source's parent, so a member declaring
|
|
85
|
+
# `uses_embryonaut_bluebook` can vendor from it.
|
|
124
86
|
def boot(source)
|
|
125
87
|
root = File.directory?(source) ? File.dirname(source) : nil
|
|
126
88
|
registry = Runtime::Registry.new(root: root)
|
|
@@ -142,10 +104,8 @@ module Hecks
|
|
|
142
104
|
end
|
|
143
105
|
|
|
144
106
|
# A port attaches to its aggregate from the hecksagon, not the bluebook, so a
|
|
145
|
-
# deaf-policy check that
|
|
146
|
-
#
|
|
147
|
-
# as a real boot does. Recording a bind builds IR only, so no adapter needs to
|
|
148
|
-
# resolve here.
|
|
107
|
+
# deaf-policy check that skipped it would miss a policy reacting to an event
|
|
108
|
+
# nothing emits. Recording a bind builds IR only; no adapter resolves here.
|
|
149
109
|
hecksagons = if File.directory?(source)
|
|
150
110
|
Dir.glob(File.join(source, "*.hecksagon"))
|
|
151
111
|
else
|
|
@@ -167,17 +127,6 @@ module Hecks
|
|
|
167
127
|
end
|
|
168
128
|
end
|
|
169
129
|
|
|
170
|
-
# Runs `Bluebook::ModelCheck` over one booted domain's chapters, prints its
|
|
171
|
-
# findings against the allowlist, and reports whether it passes.
|
|
172
|
-
#
|
|
173
|
-
# @param name [String] the domain's display name, for the header and the
|
|
174
|
-
# `ALLOWED_FINDINGS` lookup
|
|
175
|
-
# @param registry [Runtime::Registry] a booted registry holding the domain's chapters
|
|
176
|
-
# @param options [Options] the run's configuration
|
|
177
|
-
# @param known_domains [Set<String>] every bluebook and hecksagon name booted this run
|
|
178
|
-
# @param global_emitted_events [Set<String>] every event any booted chapter emits
|
|
179
|
-
# @return [Boolean] false if an allowlist entry is stale; otherwise true when no
|
|
180
|
-
# error-severity finding is left
|
|
181
130
|
def domain_passes?(name, registry, options, known_domains:, global_emitted_events:)
|
|
182
131
|
puts "── #{name}"
|
|
183
132
|
|
|
@@ -203,12 +152,9 @@ module Hecks
|
|
|
203
152
|
passes?(findings, " clean — #{chapters.size} chapter(s), no dead states, no unreachable protocol steps")
|
|
204
153
|
end
|
|
205
154
|
|
|
206
|
-
#
|
|
207
|
-
#
|
|
208
|
-
#
|
|
209
|
-
#
|
|
210
|
-
# @param options [Options] the run's configuration
|
|
211
|
-
# @return [Boolean] true when neither chapter has an error-severity finding
|
|
155
|
+
# Checked through `MetaValidator.grammar_registry`, the judged graph its
|
|
156
|
+
# conformance specs use, because any one grammar file booted alone is a
|
|
157
|
+
# fraction of the language.
|
|
212
158
|
def examine_language(options)
|
|
213
159
|
ok = true
|
|
214
160
|
["Bluebook", "World"].each do |name|
|
|
@@ -235,16 +181,8 @@ module Hecks
|
|
|
235
181
|
errors.empty?
|
|
236
182
|
end
|
|
237
183
|
|
|
238
|
-
#
|
|
239
|
-
# `
|
|
240
|
-
#
|
|
241
|
-
# The check reads `rust/Cargo.toml` through the repository-only fuzzing
|
|
242
|
-
# tooling, so it is loaded only when there is a `rust/` to read.
|
|
243
|
-
#
|
|
244
|
-
# @param name [String] the domain's display name
|
|
245
|
-
# @param rust_dir [String, nil] the repository's `rust/` directory; nil without a
|
|
246
|
-
# checkout
|
|
247
|
-
# @return [Boolean] true when `rust_dir` declares a feature named after the domain
|
|
184
|
+
# The repository-only fuzzing tooling is loaded lazily, only when there is a
|
|
185
|
+
# `rust/` to read.
|
|
248
186
|
def rust_target?(name, rust_dir)
|
|
249
187
|
return false unless rust_dir
|
|
250
188
|
|
|
@@ -252,12 +190,7 @@ module Hecks
|
|
|
252
190
|
Fuzzing::TargetCapabilities.rust_feature?(name, rust_dir)
|
|
253
191
|
end
|
|
254
192
|
|
|
255
|
-
# The
|
|
256
|
-
# domain directory itself, the same rule `Corpus.bluebook_dir` applies.
|
|
257
|
-
#
|
|
258
|
-
# @param domain_path [String] a domain directory path
|
|
259
|
-
# @return [String, nil] the directory of the first `.bluebook` found, or nil when
|
|
260
|
-
# neither place holds one
|
|
193
|
+
# The same rule `Corpus.bluebook_dir` applies.
|
|
261
194
|
def bluebook_dir(domain_path)
|
|
262
195
|
[File.join(domain_path, "bluebook"), domain_path].each do |dir|
|
|
263
196
|
files = Dir[File.join(dir, "*.bluebook")]
|