hecks 2.8.0 → 3.0.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 +50 -7
- 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 +32 -100
- 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 +10 -32
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +34 -108
- data/lib/hecks/adapters/driven/postgres/shared_connection.rb +180 -0
- data/lib/hecks/adapters/driven/postgres.rb +149 -136
- data/lib/hecks/adapters/driven/postgres_era.adapter +4 -15
- data/lib/hecks/adapters/driven/prism.rb +48 -38
- 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 +76 -62
- 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/bench/cli.rb +62 -0
- data/lib/hecks/bench/environment.rb +71 -0
- data/lib/hecks/bench/postgres_probe.rb +30 -0
- data/lib/hecks/bench/report.rb +76 -0
- data/lib/hecks/bench/ruby_runner.rb +93 -0
- data/lib/hecks/bench/run.rb +55 -0
- data/lib/hecks/bench/rust_runner.rb +101 -0
- data/lib/hecks/bench/stats.rb +46 -0
- data/lib/hecks/bench/suite.rb +98 -0
- data/lib/hecks/bench/workload.rb +89 -0
- data/lib/hecks/bench.rb +17 -0
- 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 +56 -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 +39 -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 +11 -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 +16 -50
- data/lib/hecks/bluebook/command.rb +23 -81
- data/lib/hecks/bluebook/domain_port.rb +49 -67
- 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 +96 -708
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +63 -169
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +3 -1
- 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 +42 -89
- 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 +148 -197
- 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 +38 -43
- 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 +46 -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 +39 -661
- data/lib/hecks/bluebook/hexagon.rb +18 -33
- 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 +25 -176
- data/lib/hecks/bluebook/meta_validator/shapes.rb +53 -267
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +47 -306
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +7 -43
- data/lib/hecks/bluebook/meta_validator/verdict_cache.rb +246 -0
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -18
- data/lib/hecks/bluebook/meta_validator.rb +87 -352
- data/lib/hecks/bluebook/model_check/client_profile.rb +6 -21
- data/lib/hecks/bluebook/model_check.rb +122 -596
- data/lib/hecks/bluebook/pattern_subset.rb +49 -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 +27 -51
- data/lib/hecks/bluebook/read_model.rb +57 -81
- data/lib/hecks/bluebook/reference.rb +7 -41
- data/lib/hecks/bluebook/smoke_test.rb +9 -99
- 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/canonical_json.rb +30 -0
- data/lib/hecks/chapters.rb +102 -0
- data/lib/hecks/cli/behaviors.rb +61 -0
- data/lib/hecks/cli/canonicalise.rb +25 -0
- data/lib/hecks/cli/check_engine_agreement.rb +32 -0
- data/lib/hecks/cli/check_era.rb +88 -0
- data/lib/hecks/cli/console.rb +66 -0
- data/lib/hecks/cli/deploy_template_diff.rb +40 -0
- data/lib/hecks/cli/doc_coverage.rb +32 -0
- data/lib/hecks/cli/document.rb +5 -23
- data/lib/hecks/cli/expression_projection.rb +41 -0
- data/lib/hecks/cli/follow.rb +88 -0
- data/lib/hecks/cli/history.rb +44 -0
- data/lib/hecks/cli/ir.rb +4 -6
- data/lib/hecks/cli/mcp.rb +5 -6
- data/lib/hecks/cli/model_check.rb +24 -88
- data/lib/hecks/cli/pattern_cases.rb +47 -0
- data/lib/hecks/cli/present.rb +39 -0
- data/lib/hecks/cli/project_cli.rb +223 -64
- data/lib/hecks/cli/project_diagrams.rb +4 -10
- data/lib/hecks/cli/project_glossary.rb +44 -0
- data/lib/hecks/cli/reference.rb +46 -0
- data/lib/hecks/cli/refresh_projections.rb +44 -0
- data/lib/hecks/cli/refresh_rspec_runtime_baseline.rb +150 -0
- data/lib/hecks/cli/release.rb +70 -0
- data/lib/hecks/cli/release_gem.rb +59 -0
- data/lib/hecks/cli/rspec_io_parallel_files.rb +137 -0
- data/lib/hecks/cli/rspec_shard_files.rb +66 -0
- data/lib/hecks/cli/run.rb +15 -61
- data/lib/hecks/cli/seed_semantics_corpus.rb +71 -0
- data/lib/hecks/cli/serve_query_ir_mcp.rb +30 -0
- data/lib/hecks/cli/shape.rb +70 -0
- data/lib/hecks/cli/smoke_http.rb +230 -0
- data/lib/hecks/cli/smoke_test.rb +7 -19
- data/lib/hecks/cli/spec_example.rb +27 -0
- data/lib/hecks/cli/statements.rb +32 -0
- data/lib/hecks/cli/stores.rb +4 -6
- data/lib/hecks/cli/stress_concurrency_specs.rb +177 -0
- data/lib/hecks/cli.rb +216 -73
- data/lib/hecks/codemod.rb +324 -0
- data/lib/hecks/construct.rb +8 -34
- data/lib/hecks/corpus.rb +423 -0
- data/lib/hecks/deploy/bluebook/deploy.bluebook +617 -158
- data/lib/hecks/deploy/bluebook/deploy.hecksagon +41 -11
- data/lib/hecks/deploy/oidc.json +82 -2
- data/lib/hecks/doc/reference.rb +351 -0
- data/lib/hecks/doors/cli_door.rb +196 -0
- data/lib/hecks/doors/cli_runner.rb +297 -0
- data/lib/hecks/{facade → doors}/command_request.rb +14 -34
- data/lib/hecks/doors/handle.rb +206 -0
- data/lib/hecks/doors/json_door.rb +132 -0
- data/lib/hecks/doors/launcher_options.rb +129 -0
- data/lib/hecks/{cli → doors}/mcp_door.rb +25 -120
- data/lib/hecks/doors/mcp_door_scope.rb +97 -0
- data/lib/hecks/doors/ruby_door/aggregate_door.rb +162 -0
- data/lib/hecks/doors/ruby_door/chapter.rb +72 -0
- data/lib/hecks/doors/ruby_door.rb +77 -0
- data/lib/hecks/doors.rb +61 -0
- 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 +5 -72
- data/lib/hecks/engine_agreement.rb +156 -0
- data/lib/hecks/facade.rb +23 -51
- data/lib/hecks/forms/app.rb +21 -76
- data/lib/hecks/forms/banking_presentation.rb +50 -0
- 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 +31 -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/fuzzing/bounded_exhaustive_expressions.rb +393 -0
- data/lib/hecks/fuzzing/combination_miner.rb +86 -0
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +214 -0
- data/lib/hecks/fuzzing/coverage_campaign.rb +143 -0
- data/lib/hecks/fuzzing/differential.rb +156 -0
- data/lib/hecks/fuzzing/domain_generator.rb +615 -0
- data/lib/hecks/fuzzing/era_boundary.rb +71 -0
- data/lib/hecks/fuzzing/form_census.rb +136 -0
- data/lib/hecks/fuzzing/generated_domain_check.rb +93 -0
- data/lib/hecks/fuzzing/invalid_value_generator.rb +64 -0
- data/lib/hecks/fuzzing/isolated_boot.rb +301 -0
- data/lib/hecks/fuzzing/nondeterministic.rb +51 -0
- data/lib/hecks/fuzzing/outside_world.rb +45 -0
- data/lib/hecks/fuzzing/persistence_parity.rb +102 -0
- data/lib/hecks/fuzzing/properties/corrections.rb +88 -0
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +314 -0
- data/lib/hecks/fuzzing/properties/guards.rb +190 -0
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +300 -0
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +93 -0
- data/lib/hecks/fuzzing/properties/outbox.rb +89 -0
- data/lib/hecks/fuzzing/properties/querying.rb +175 -0
- data/lib/hecks/fuzzing/properties.rb +162 -0
- data/lib/hecks/fuzzing/qa_settings.rb +123 -0
- data/lib/hecks/fuzzing/replay.rb +505 -0
- data/lib/hecks/fuzzing/rotation_priority.rb +48 -0
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +108 -0
- data/lib/hecks/fuzzing/self_consistency.rb +339 -0
- data/lib/hecks/fuzzing/sequence_generator/adversary.rb +385 -0
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +132 -0
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +95 -0
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +77 -0
- data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +109 -0
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +237 -0
- data/lib/hecks/fuzzing/sequence_generator.rb +189 -0
- data/lib/hecks/fuzzing/shrinker.rb +166 -0
- data/lib/hecks/fuzzing/structural_skips.rb +33 -0
- data/lib/hecks/fuzzing/sweep_depth.rb +43 -0
- data/lib/hecks/fuzzing/target_capabilities.rb +163 -0
- data/lib/hecks/fuzzing/value_generator.rb +216 -0
- data/lib/hecks/fuzzing.rb +23 -0
- data/lib/hecks/grammar/evolve.rb +336 -0
- 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/hecks/adapters/codebase/codemods.rb +45 -0
- data/lib/hecks/hecks/adapters/codebase/conformance.rb +71 -0
- data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +202 -0
- data/lib/hecks/hecks/adapters/codebase/gem_registry.rb +80 -0
- data/lib/hecks/hecks/adapters/codebase/kernel_tables.rb +54 -0
- data/lib/hecks/hecks/adapters/codebase/language.rb +240 -0
- data/lib/hecks/hecks/adapters/codebase/npm_registry.rb +102 -0
- data/lib/hecks/hecks/adapters/codebase/publishing.rb +142 -0
- data/lib/hecks/hecks/adapters/codebase/regeneration.rb +67 -0
- data/lib/hecks/hecks/adapters/codebase/release_facts.rb +90 -0
- data/lib/hecks/hecks/adapters/codebase/ruby_child.rb +83 -0
- data/lib/hecks/hecks/adapters/codebase/secret_vault.rb +36 -0
- data/lib/hecks/hecks/adapters/codebase/source_tree.adapter +7 -0
- data/lib/hecks/hecks/adapters/codebase/source_tree.rb +189 -0
- data/lib/hecks/hecks/adapters/codebase/sqlite_fixture.rb +71 -0
- data/lib/hecks/hecks/adapters/codebase/style.rb +171 -0
- data/lib/hecks/hecks/adapters/codebase/test_runner.rb +55 -0
- data/lib/hecks/hecks/adapters/codebase/test_suite.rb +165 -0
- data/lib/hecks/hecks/adapters/codebase/tree.rb +111 -0
- data/lib/hecks/hecks/adapters/console_capture.rb +79 -0
- data/lib/hecks/hecks/adapters/deploy_toolchain.adapter +7 -0
- data/lib/hecks/hecks/adapters/deploy_toolchain.rb +108 -0
- data/lib/hecks/hecks/adapters/git.adapter +7 -0
- data/lib/hecks/hecks/adapters/git.rb +102 -0
- data/lib/hecks/hecks/adapters/host_http.adapter +7 -0
- data/lib/hecks/hecks/adapters/host_http.rb +65 -0
- data/lib/hecks/hecks/adapters/in_process_boot.adapter +7 -0
- data/lib/hecks/hecks/adapters/in_process_boot.rb +197 -0
- data/lib/hecks/hecks/adapters/in_process_operations.rb +202 -0
- data/lib/hecks/hecks/adapters/journal_store/changes.rb +143 -0
- data/lib/hecks/hecks/adapters/journal_store/compaction.rb +145 -0
- data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +132 -0
- data/lib/hecks/hecks/adapters/journal_store/examination.rb +135 -0
- data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +163 -0
- data/lib/hecks/hecks/adapters/journal_store/readings.rb +187 -0
- data/lib/hecks/hecks/adapters/journal_store.adapter +7 -0
- data/lib/hecks/hecks/adapters/journal_store.rb +64 -0
- data/lib/hecks/hecks/adapters/local_files.adapter +7 -0
- data/lib/hecks/hecks/adapters/local_files.rb +46 -0
- data/lib/hecks/hecks/adapters/pg_admin.adapter +7 -0
- data/lib/hecks/hecks/adapters/pg_admin.rb +245 -0
- data/lib/hecks/hecks/adapters/process_pool.adapter +7 -0
- data/lib/hecks/hecks/adapters/process_pool.rb +119 -0
- data/lib/hecks/hecks/adapters/rust_toolchain.adapter +7 -0
- data/lib/hecks/hecks/adapters/rust_toolchain.rb +179 -0
- data/lib/hecks/hecks/adapters/rust_workspace.rb +150 -0
- data/lib/hecks/hecks/adapters/shell.adapter +7 -0
- data/lib/hecks/hecks/adapters/shell.rb +49 -0
- data/lib/hecks/hecks/adapters/terminal.adapter +7 -0
- data/lib/hecks/hecks/adapters/terminal.rb +74 -0
- data/lib/hecks/hecks/codebase.behaviors +172 -0
- data/lib/hecks/hecks/codebase.bluebook +2453 -0
- data/lib/hecks/hecks/context_map.hecksagon +13 -0
- data/lib/hecks/hecks/custodian.behaviors +179 -0
- data/lib/hecks/hecks/custodian.bluebook +1847 -0
- data/lib/hecks/hecks/deploy.behaviors +74 -0
- data/lib/hecks/hecks/deploy.world +12 -0
- data/lib/hecks/hecks/environments/memory.world +10 -0
- data/lib/hecks/hecks/governance.world +7 -0
- data/lib/hecks/hecks/hecks.behaviors +62 -0
- data/lib/hecks/hecks/hecks.bluebook +124 -0
- data/lib/hecks/hecks/hecks.hecksagon +390 -0
- data/lib/hecks/hecks/hecks.world +42 -0
- data/lib/hecks/ir.rb +14 -83
- data/lib/hecks/kernel_capabilities.rb +194 -0
- 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 +26 -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 +19 -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 +83 -198
- data/lib/hecks/language/hecksagon/adapter_binding.bluebook +3 -10
- data/lib/hecks/language/hecksagon/domain_port.bluebook +14 -19
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +26 -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_stdio_guard.rb +4 -41
- data/lib/hecks/naming.rb +29 -137
- data/lib/hecks/persistence_legacy_fixture/regenerate.rb +161 -0
- data/lib/hecks/persistence_legacy_fixture.rb +113 -0
- 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 +44 -144
- data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +15 -115
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +20 -85
- data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +6 -25
- data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +18 -24
- 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 +19 -76
- 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 +43 -127
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +13 -45
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +131 -555
- data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +13 -63
- data/lib/hecks/ports/persistence/plugins/era/translation/approval_file.rb +227 -0
- 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 +50 -47
- 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/translation.rb +1 -0
- 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 +47 -108
- 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/projection_files.rb +285 -0
- data/lib/hecks/projections/bootstrap_table.rb +12 -44
- 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 +40 -207
- data/lib/hecks/projections/deploy/lambda.rb +191 -708
- 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/preview.sh.erb +1 -1
- 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 +3 -59
- data/lib/hecks/projections/deploy/preview.rb +2 -67
- data/lib/hecks/projections/deploy/scripts/deploy-service.sh.tmpl +1 -1
- data/lib/hecks/projections/deploy/scripts/expected-era.header +1 -1
- data/lib/hecks/projections/deploy/scripts/hosting.mk.tmpl +3 -3
- data/lib/hecks/projections/deploy/scripts/settings.rb +3 -25
- data/lib/hecks/projections/deploy/scripts/smoke-after-deploy.sh.tmpl +1 -1
- data/lib/hecks/projections/deploy/scripts.rb +4 -57
- data/lib/hecks/projections/deploy/shared.rb +48 -147
- 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 +22 -584
- 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 +16 -43
- data/lib/hecks/projections/model.rb +12 -51
- data/lib/hecks/projections/oidc.rb +12 -56
- data/lib/hecks/projections/parser_table.rb +13 -32
- data/lib/hecks/projections/reference.rb +4 -18
- data/lib/hecks/projections/rust_vocabulary.rb +13 -251
- 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 +154 -400
- 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/quality_control/adapters/agent.adapter +7 -0
- data/lib/hecks/quality_control/adapters/agent.rb +58 -0
- data/lib/hecks/quality_control/adapters/angle_tools.adapter +7 -0
- data/lib/hecks/quality_control/adapters/angle_tools.rb +15 -0
- data/lib/hecks/quality_control/adapters/clearance_recorder.rb +36 -0
- data/lib/hecks/quality_control/adapters/clearance_tools.adapter +7 -0
- data/lib/hecks/quality_control/adapters/clearance_tools.rb +17 -0
- data/lib/hecks/quality_control/adapters/git_pr.adapter +7 -0
- data/lib/hecks/quality_control/adapters/git_pr.rb +226 -0
- data/lib/hecks/quality_control/adapters/github_checks.adapter +9 -0
- data/lib/hecks/quality_control/adapters/github_checks.rb +83 -0
- data/lib/hecks/quality_control/adapters/github_ci_webhook.rb +56 -0
- data/lib/hecks/quality_control/adapters/github_issues.adapter +7 -0
- data/lib/hecks/quality_control/adapters/github_issues.rb +49 -0
- data/lib/hecks/quality_control/adapters/qa_tool.rb +59 -0
- data/lib/hecks/quality_control/adapters/sweep_tools.adapter +7 -0
- data/lib/hecks/quality_control/adapters/sweep_tools.rb +51 -0
- data/lib/hecks/quality_control/adapters/target_tools.adapter +7 -0
- data/lib/hecks/quality_control/adapters/target_tools.rb +43 -0
- data/lib/hecks/quality_control/cli/child.rb +45 -0
- data/lib/hecks/quality_control/cli/qa_concurrency_racer.rb +45 -0
- data/lib/hecks/quality_control/cli/qa_discover_external_domains.rb +248 -0
- data/lib/hecks/quality_control/cli/qa_domain_novelty.rb +163 -0
- data/lib/hecks/quality_control/cli/qa_generated_domains.rb +450 -0
- data/lib/hecks/quality_control/cli/qa_log_bug.rb +195 -0
- data/lib/hecks/quality_control/cli/qa_mine_combinations.rb +220 -0
- data/lib/hecks/quality_control/cli/qa_open_pr.rb +305 -0
- data/lib/hecks/quality_control/cli/qa_postgres_migrate.rb +154 -0
- data/lib/hecks/quality_control/cli/qa_postgres_role.rb +159 -0
- data/lib/hecks/quality_control/cli/qa_pr_check.rb +232 -0
- data/lib/hecks/quality_control/cli/qa_seed_angles.rb +142 -0
- data/lib/hecks/quality_control/cli/qa_seed_targets.rb +69 -0
- data/lib/hecks/quality_control/cli/qa_sweep/all_mode.rb +280 -0
- data/lib/hecks/quality_control/cli/qa_sweep/checks.rb +329 -0
- data/lib/hecks/quality_control/cli/qa_sweep/dials.rb +92 -0
- data/lib/hecks/quality_control/cli/qa_sweep/finding_report.rb +117 -0
- data/lib/hecks/quality_control/cli/qa_sweep/parsing.rb +175 -0
- data/lib/hecks/quality_control/cli/qa_sweep/release_mode.rb +60 -0
- data/lib/hecks/quality_control/cli/qa_sweep.rb +611 -0
- data/lib/hecks/quality_control/cli/qa_tick.rb +274 -0
- data/lib/hecks/quality_control/quality_control.bluebook +2224 -0
- data/lib/hecks/quality_control/quality_control.hecksagon +13 -0
- data/lib/hecks/quality_control/quality_control.ports.hecksagon +54 -0
- data/lib/hecks/query_ir.rb +346 -0
- data/lib/hecks/query_ir_mcp.rb +198 -0
- 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 +5 -8
- data/lib/hecks/release/runner/clean_tree.rb +42 -0
- data/lib/hecks/release/runner/commands.rb +2 -4
- data/lib/hecks/release/runner/console.rb +6 -0
- data/lib/hecks/release/runner/gem_publisher.rb +15 -9
- data/lib/hecks/release/runner/npm_publisher.rb +9 -53
- data/lib/hecks/release/runner/preflight.rb +29 -20
- data/lib/hecks/release/runner/published.rb +8 -26
- data/lib/hecks/release/runner/tagger.rb +31 -23
- data/lib/hecks/release/runner.rb +60 -38
- data/lib/hecks/rendering.rb +4 -26
- data/lib/hecks/router/namespace_installer.rb +15 -39
- data/lib/hecks/router.rb +4 -8
- data/lib/hecks/runtime/adapter_lookup.rb +124 -0
- 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 +27 -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 +50 -104
- data/lib/hecks/runtime/dispatcher.rb +134 -243
- 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 +14 -70
- data/lib/hecks/runtime/invocation.rb +28 -164
- data/lib/hecks/runtime/loader.rb +109 -194
- data/lib/hecks/runtime/outbox.rb +39 -262
- data/lib/hecks/runtime/policy_interpreter.rb +43 -202
- data/lib/hecks/runtime/port_operation_interpreter.rb +28 -97
- data/lib/hecks/runtime/query_interpreter.rb +122 -187
- data/lib/hecks/runtime/reaction_invocation.rb +36 -138
- data/lib/hecks/runtime/reaction_outcome.rb +89 -0
- 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 +28 -87
- data/lib/hecks/runtime/registry/saga_persistence.rb +10 -102
- data/lib/hecks/runtime/registry/verification.rb +213 -227
- data/lib/hecks/runtime/registry/world_defaults.rb +4 -53
- data/lib/hecks/runtime/registry.rb +156 -247
- data/lib/hecks/runtime/remote_dispatcher.rb +68 -154
- 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 +162 -760
- data/lib/hecks/runtime/value/entity_list_coercion.rb +26 -219
- data/lib/hecks/runtime/value/field_checks.rb +172 -0
- data/lib/hecks/runtime/value.rb +15 -84
- data/lib/hecks/runtime.rb +35 -69
- data/lib/hecks/rust_build/conformance.rb +158 -0
- data/lib/hecks/rust_build/conformance_fuzz.rb +71 -0
- data/lib/hecks/rust_build/coverage.rb +218 -0
- data/lib/hecks/rust_build/native_build.rb +124 -0
- data/lib/hecks/rust_build/project_rust/root_mod.rb +120 -0
- data/lib/hecks/rust_build/project_rust.rb +332 -0
- data/lib/hecks/rust_build/wasm.rb +105 -0
- data/lib/hecks/rust_build/wasm_browser.rb +113 -0
- data/lib/hecks/rust_build.rb +144 -0
- data/lib/hecks/storehouse.rb +155 -582
- data/lib/hecks/tenancy/bluebook/tenancy.bluebook +10 -34
- data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +6 -23
- data/lib/hecks/three_zero/forms.yml +127 -0
- data/lib/hecks/three_zero.rb +12 -0
- data/lib/hecks/tools/argument_gate_matrix.rb +316 -0
- data/lib/hecks/tools/comment_style.rb +1070 -0
- data/lib/hecks/tools/corpus_report.rb +87 -0
- data/lib/hecks/tools/deploy_recipe.rb +255 -0
- data/lib/hecks/tools/deploy_recipe_lint.rb +282 -0
- data/lib/hecks/tools/drop_implicit_append_fields.rb +95 -0
- data/lib/hecks/tools/era_projection_backfill.rb +94 -0
- data/lib/hecks/tools/era_reattest.rb +146 -0
- data/lib/hecks/tools/evolve_run.rb +189 -0
- data/lib/hecks/tools/fuzz_sweep.rb +373 -0
- data/lib/hecks/tools/heki_compaction.rb +100 -0
- data/lib/hecks/tools/hoist_local_givens.rb +246 -0
- data/lib/hecks/tools/journal_compaction.rb +89 -0
- data/lib/hecks/tools/oidc_manifests.rb +70 -0
- data/lib/hecks/tools/query_ir_run.rb +81 -0
- data/lib/hecks/tools/regeneration_run.rb +166 -0
- data/lib/hecks/tools/rust_comment_style.rb +642 -0
- data/lib/hecks/tools/sequence_script.rb +62 -0
- data/lib/hecks/tools/tail_merge.rb +117 -0
- data/lib/hecks/tools/tenant_provisioning.rb +142 -0
- data/lib/hecks/tools/translation_audit.rb +208 -0
- data/lib/hecks/tools/translation_scaffold.rb +131 -0
- data/lib/hecks/tools.rb +86 -0
- 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 +52 -90
- 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
- data/qa/settings.yml +66 -0
- data/rust/.cargo/config.toml +6 -0
- data/rust/.gitignore +2 -0
- data/rust/Cargo.lock +54 -0
- data/rust/Cargo.toml +61 -0
- data/rust/build/.cargo/config.toml +3 -0
- data/rust/build/.gitignore +1 -0
- data/rust/build/Cargo.lock +7 -0
- data/rust/build/Cargo.toml +19 -0
- data/rust/build/src/build_artifact.rs +47 -0
- data/rust/build/src/cargo_sync.rs +248 -0
- data/rust/build/src/json.rs +421 -0
- data/rust/build/src/lineage_pass.rs +285 -0
- data/rust/build/src/main.rs +51 -0
- data/rust/build/src/optional_pass.rs +150 -0
- data/rust/build/src/pipeline.rs +264 -0
- data/rust/build/src/reserved_names.rs +76 -0
- data/rust/build/src/resolve.rs +124 -0
- data/rust/build/src/root.rs +25 -0
- data/rust/build/src/sidecars.rs +73 -0
- data/rust/build/src/subprocess.rs +51 -0
- data/rust/build/src/tmp.rs +31 -0
- data/rust/codegen/.cargo/config.toml +3 -0
- data/rust/codegen/.gitignore +1 -0
- data/rust/codegen/Cargo.lock +7 -0
- data/rust/codegen/Cargo.toml +20 -0
- data/rust/codegen/src/attr.rs +32 -0
- data/rust/codegen/src/bridging.rs +481 -0
- data/rust/codegen/src/commands.rs +1226 -0
- data/rust/codegen/src/constraints.rs +109 -0
- data/rust/codegen/src/dependency_planning.rs +209 -0
- data/rust/codegen/src/domain_generator.rs +1288 -0
- data/rust/codegen/src/exemplar.rs +230 -0
- data/rust/codegen/src/expr_emitter.rs +87 -0
- data/rust/codegen/src/fielded.rs +192 -0
- data/rust/codegen/src/hecks_naming.rs +33 -0
- data/rust/codegen/src/json.rs +335 -0
- data/rust/codegen/src/json_codec.rs +697 -0
- data/rust/codegen/src/literal.rs +207 -0
- data/rust/codegen/src/main.rs +290 -0
- data/rust/codegen/src/manifest.rs +227 -0
- data/rust/codegen/src/mutations.rs +784 -0
- data/rust/codegen/src/naming.rs +286 -0
- data/rust/codegen/src/ports.rs +208 -0
- data/rust/codegen/src/prelude.rs +116 -0
- data/rust/codegen/src/queries.rs +786 -0
- data/rust/codegen/src/reactions.rs +532 -0
- data/rust/codegen/src/read_models.rs +697 -0
- data/rust/codegen/src/reference_specs.rs +40 -0
- data/rust/codegen/src/registry.rs +966 -0
- data/rust/codegen/src/reserved_names.rs +76 -0
- data/rust/codegen/src/shared.rs +93 -0
- data/rust/codegen/src/skip_reason.rs +25 -0
- data/rust/codegen/src/types.rs +362 -0
- data/rust/host/.cargo/config.toml +3 -0
- data/rust/host/.gitignore +1 -0
- data/rust/host/Cargo.lock +4297 -0
- data/rust/host/Cargo.toml +61 -0
- data/rust/host/HECKS_RELEASE +1 -0
- data/rust/host/rds-ca-bundle.pem +2736 -0
- data/rust/host/src/api.rs +1596 -0
- data/rust/host/src/approval.rs +652 -0
- data/rust/host/src/auth.rs +1287 -0
- data/rust/host/src/bin/expr_harness.rs +46 -0
- data/rust/host/src/bin/lineage_harness.rs +119 -0
- data/rust/host/src/bin/mint_harness.rs +135 -0
- data/rust/host/src/checkout.rs +265 -0
- data/rust/host/src/dispatch.rs +1443 -0
- data/rust/host/src/expr_json.rs +1117 -0
- data/rust/host/src/field_hints.rs +52 -0
- data/rust/host/src/ir.rs +733 -0
- data/rust/host/src/journal.rs +874 -0
- data/rust/host/src/lambda_client.rs +378 -0
- data/rust/host/src/log.rs +147 -0
- data/rust/host/src/main.rs +474 -0
- data/rust/host/src/mint.rs +1865 -0
- data/rust/host/src/payments/keystore.rs +330 -0
- data/rust/host/src/payments/tests.rs +1400 -0
- data/rust/host/src/payments.rs +767 -0
- data/rust/host/src/presentation.rs +698 -0
- data/rust/host/src/presentation_write.rs +1431 -0
- data/rust/host/src/query_step.rs +149 -0
- data/rust/host/src/rate_limit.rs +904 -0
- data/rust/host/src/reference_transform.rs +241 -0
- data/rust/host/src/reference_validate.rs +338 -0
- data/rust/host/src/resend.rs +296 -0
- data/rust/host/src/secrets.rs +106 -0
- data/rust/host/src/server.rs +663 -0
- data/rust/host/src/storage_shape.rs +175 -0
- data/rust/host/src/test_pg.rs +40 -0
- data/rust/host/src/ui_schema.rs +1351 -0
- data/rust/host/src/wasm_runner.rs +191 -0
- data/rust/host/src/web/newsletter/cooldown.rs +126 -0
- data/rust/host/src/web/newsletter/tests.rs +104 -0
- data/rust/host/src/web/newsletter.rs +310 -0
- data/rust/host/src/web/newsletter_send.rs +357 -0
- data/rust/host/src/web/registrations.rs +1505 -0
- data/rust/host/src/web.rs +2937 -0
- data/rust/lsp/.gitignore +1 -0
- data/rust/lsp/Cargo.lock +7 -0
- data/rust/lsp/Cargo.toml +16 -0
- data/rust/lsp/README.md +133 -0
- data/rust/lsp/src/diagnostics.rs +165 -0
- data/rust/lsp/src/json.rs +385 -0
- data/rust/lsp/src/main.rs +399 -0
- data/rust/lsp/src/outline.rs +177 -0
- data/rust/lsp/src/rpc.rs +67 -0
- data/rust/parser/.cargo/config.toml +5 -0
- data/rust/parser/.gitignore +1 -0
- data/rust/parser/Cargo.lock +7 -0
- data/rust/parser/Cargo.toml +21 -0
- data/rust/parser/src/build/closed_sets.rs +27 -0
- data/rust/parser/src/build/identity.rs +276 -0
- data/rust/parser/src/build/mod.rs +12 -0
- data/rust/parser/src/build/naming.rs +141 -0
- data/rust/parser/src/build/pattern_subset.rs +161 -0
- data/rust/parser/src/build/query_derive.rs +72 -0
- data/rust/parser/src/build/query_inference.rs +269 -0
- data/rust/parser/src/build/query_options.rs +100 -0
- data/rust/parser/src/build/read_model.rs +94 -0
- data/rust/parser/src/build/references.rs +32 -0
- data/rust/parser/src/canonical.rs +114 -0
- data/rust/parser/src/diag.rs +55 -0
- data/rust/parser/src/emit.rs +953 -0
- data/rust/parser/src/expr/ast_json.rs +147 -0
- data/rust/parser/src/expr/evaluator.rs +81 -0
- data/rust/parser/src/expr/mod.rs +84 -0
- data/rust/parser/src/expr/resolver.rs +497 -0
- data/rust/parser/src/ir.rs +387 -0
- data/rust/parser/src/keywords.rs +585 -0
- data/rust/parser/src/lex.rs +662 -0
- data/rust/parser/src/main.rs +252 -0
- data/rust/parser/src/parse/aggregate.rs +612 -0
- data/rust/parser/src/parse/chapter.rs +517 -0
- data/rust/parser/src/parse/command.rs +637 -0
- data/rust/parser/src/parse/domain_port.rs +127 -0
- data/rust/parser/src/parse/entity.rs +527 -0
- data/rust/parser/src/parse/file.rs +67 -0
- data/rust/parser/src/parse/hecksagon.rs +231 -0
- data/rust/parser/src/parse/lifecycle.rs +162 -0
- data/rust/parser/src/parse/mod.rs +1262 -0
- data/rust/parser/src/parse/policy.rs +87 -0
- data/rust/parser/src/parse/process_manager.rs +305 -0
- data/rust/parser/src/parse/query.rs +100 -0
- data/rust/parser/src/parse/read_model.rs +214 -0
- data/rust/parser/src/parse/value_object.rs +250 -0
- data/rust/parser/src/ruby_value.rs +422 -0
- data/rust/project/bridging.rb +257 -0
- data/rust/project/commands.rb +877 -0
- data/rust/project/constraints.rb +86 -0
- data/rust/project/dependency_planning.rb +178 -0
- data/rust/project/domain_generator.rb +980 -0
- data/rust/project/exemplar.rb +148 -0
- data/rust/project/expr_emitter.rb +72 -0
- data/rust/project/fielded.rb +141 -0
- data/rust/project/json_codec.rb +641 -0
- data/rust/project/mutations.rb +721 -0
- data/rust/project/naming.rb +205 -0
- data/rust/project/ports.rb +65 -0
- data/rust/project/queries.rb +493 -0
- data/rust/project/reactions.rb +317 -0
- data/rust/project/read_models.rb +690 -0
- data/rust/project/reference_specs.rb +27 -0
- data/rust/project/registry.rb +396 -0
- data/rust/project/skip_reason.rb +29 -0
- data/rust/project/types.rb +225 -0
- data/rust/project/write_if_changed.rb +83 -0
- data/rust/project.rb +30 -0
- data/rust/project_rust_pipeline.rb +383 -0
- data/rust/src/exemplar/commands.rs +279 -0
- data/rust/src/exemplar/constraints.rs +18 -0
- data/rust/src/exemplar/fielded.rs +280 -0
- data/rust/src/exemplar/json.rs +277 -0
- data/rust/src/exemplar/mod.rs +17 -0
- data/rust/src/exemplar/mutations.rs +80 -0
- data/rust/src/exemplar/queries.rs +33 -0
- data/rust/src/exemplar/reactions.rs +88 -0
- data/rust/src/exemplar/read_models.rs +48 -0
- data/rust/src/exemplar/registry.rs +166 -0
- data/rust/src/exemplar/types.rs +44 -0
- data/rust/src/kernel/attribute_shapes/composite.rs +88 -0
- data/rust/src/kernel/attribute_shapes/list.rs +18 -0
- data/rust/src/kernel/attribute_shapes/mod.rs +44 -0
- data/rust/src/kernel/attribute_shapes/optional.rs +9 -0
- data/rust/src/kernel/attribute_shapes/scalar.rs +39 -0
- data/rust/src/kernel/cli.rs +585 -0
- data/rust/src/kernel/dispatch.rs +1090 -0
- data/rust/src/kernel/expr.rs +458 -0
- data/rust/src/kernel/expression_operators/arithmetic.rs +128 -0
- data/rust/src/kernel/expression_operators/comparison.rs +48 -0
- data/rust/src/kernel/expression_operators/enumeration.rs +232 -0
- data/rust/src/kernel/expression_operators/logical.rs +13 -0
- data/rust/src/kernel/expression_operators/membership.rs +18 -0
- data/rust/src/kernel/expression_operators/mod.rs +68 -0
- data/rust/src/kernel/expression_operators/pattern_match.rs +73 -0
- data/rust/src/kernel/expression_operators/positional.rs +126 -0
- data/rust/src/kernel/expression_operators/presence.rs +101 -0
- data/rust/src/kernel/expression_operators/sign_test.rs +16 -0
- data/rust/src/kernel/expression_operators/sized.rs +35 -0
- data/rust/src/kernel/expression_operators/text.rs +79 -0
- data/rust/src/kernel/expression_operators/to_string.rs +18 -0
- data/rust/src/kernel/json.rs +779 -0
- data/rust/src/kernel/mod.rs +133 -0
- data/rust/src/kernel/named_query.rs +219 -0
- data/rust/src/kernel/orchestrate.rs +1810 -0
- data/rust/src/kernel/pattern.rs +307 -0
- data/rust/src/kernel/query_comparators.rs +206 -0
- data/rust/src/kernel/query_ordering.rs +103 -0
- data/rust/src/kernel/read_model.rs +914 -0
- data/rust/src/kernel/reference_lookup.rs +149 -0
- data/rust/src/kernel/repository.rs +468 -0
- data/rust/src/kernel/routing.rs +612 -0
- data/rust/src/kernel/vocab/aggregate_dispatch_order.rs +118 -0
- data/rust/src/kernel/vocab/entity_dispatch_order.rs +114 -0
- data/rust/src/kernel/vocab/field_hint.rs +70 -0
- data/rust/src/kernel/vocab/mod.rs +20 -0
- data/rust/src/kernel/vocab/query_comparator.rs +65 -0
- data/rust/src/kernel/vocab/refusal_template.rs +1592 -0
- data/rust/src/lib.rs +8 -0
- data/rust/src/main.rs +16 -0
- data/rust/web/.gitignore +1 -0
- data/rust/web/Cargo.lock +119 -0
- data/rust/web/Cargo.toml +18 -0
- data/rust/web/src/lib.rs +8 -0
- metadata +478 -12
- data/lib/hecks/facade/cli_door.rb +0 -178
- data/lib/hecks/facade/cli_runner.rb +0 -271
- data/lib/hecks/facade/handle.rb +0 -293
- data/lib/hecks/facade/json_door.rb +0 -247
- data/lib/hecks/facade/surface/aggregate_door.rb +0 -222
- data/lib/hecks/facade/surface/chapter.rb +0 -116
- data/lib/hecks/facade/surface.rb +0 -61
- data/lib/hecks/mcp_door_scope.rb +0 -176
data/lib/hecks/runtime.rb
CHANGED
|
@@ -1,33 +1,7 @@
|
|
|
1
1
|
# Hecks::Runtime
|
|
2
2
|
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
# required each file by hand, and the runtime's own state — the registry a
|
|
6
|
-
# declaration is being collected into — sat on the top-level Hecks module
|
|
7
|
-
# beside the DSL words.
|
|
8
|
-
#
|
|
9
|
-
# What lives here is what runs a domain :
|
|
10
|
-
#
|
|
11
|
-
# Runtime.boot(path) load a directory and return its Dispatcher
|
|
12
|
-
# Runtime.with_registry(r) bind the ambient registry for the duration of a load
|
|
13
|
-
# Runtime.current_registry the registry a declaration is landing in, or nil
|
|
14
|
-
#
|
|
15
|
-
# What does not live here is what declares one — `Hecks.bluebook`,
|
|
16
|
-
# `.hecksagon`, `.port`, `.adapter`, `.world` are loading words and stay on the
|
|
17
|
-
# top-level module, which now reads as a facade over this.
|
|
18
|
-
#
|
|
19
|
-
# runtime = Hecks::Runtime.boot("examples/pizzas/bluebook")
|
|
20
|
-
# runtime.dispatch("Pizzas::Pizza.CreatePizza", name: "Margherita")
|
|
21
|
-
#
|
|
22
|
-
# Note, and it is the reason this file exists : `current_registry` is still
|
|
23
|
-
# process-global. Each boot builds a fresh Registry, and `Loader.bind_runtime`
|
|
24
|
-
# installs a fresh facade door whose modules close over that boot's dispatcher
|
|
25
|
-
# — no class-level runtime binding remains, so two boots in one process no
|
|
26
|
-
# longer share dispatch state, only the top-level name (the last-bound door
|
|
27
|
-
# wins the constant, which is what per-boot install means). Owning the state
|
|
28
|
-
# here was the first move ; the dispatcher reachable per-runtime rather than
|
|
29
|
-
# through a constant was the second, and it is done — the door is the only
|
|
30
|
-
# constant left, and it is a projection, not the runtime.
|
|
3
|
+
# Boots a domain directory and holds the ambient registry and caller state a boot runs under.
|
|
4
|
+
# `current_registry` is process-global; each boot's dispatcher is per-boot.
|
|
31
5
|
|
|
32
6
|
require_relative "runtime/event"
|
|
33
7
|
require_relative "runtime/value"
|
|
@@ -55,45 +29,51 @@ require_relative "runtime/tenant_check"
|
|
|
55
29
|
require_relative "runtime/loader"
|
|
56
30
|
|
|
57
31
|
module Hecks
|
|
58
|
-
#
|
|
59
|
-
# here (rather than documented in place) only because the
|
|
60
|
-
# `require_relative` calls above must run before Ruby reopens the
|
|
61
|
-
# module they populate.
|
|
32
|
+
# The runtime layer: boots a domain directory and holds the ambient registry a boot runs under.
|
|
62
33
|
module Runtime
|
|
63
34
|
class << self
|
|
64
|
-
# The registry declarations are currently landing in, or nil outside a
|
|
65
|
-
# boot. Read by the DSL collectors on the top-level module and by the
|
|
66
|
-
# extraction port.
|
|
35
|
+
# The registry declarations are currently landing in, or nil outside a boot.
|
|
67
36
|
attr_reader :current_registry
|
|
68
37
|
|
|
69
|
-
#
|
|
70
|
-
#
|
|
38
|
+
# Loads a bluebook directory and returns the Dispatcher bound to it. See Loader.boot.
|
|
39
|
+
#
|
|
40
|
+
# Hecks::Runtime.boot("examples/pizzas/bluebook")
|
|
41
|
+
# .dispatch("Pizzas::Pizza.CreatePizza", name: "Margherita")
|
|
71
42
|
#
|
|
72
43
|
# @param path [String] path to a domain directory, or a file inside one
|
|
73
|
-
# @param shared [String, nil] a shared-root override
|
|
74
|
-
# @param
|
|
75
|
-
#
|
|
76
|
-
# @param environment [String, nil] the environment name
|
|
77
|
-
# `Adapters::Folder#load_domain`
|
|
44
|
+
# @param shared [String, nil] a shared-root override
|
|
45
|
+
# @param install_doors [Boolean] whether to install the Ruby facade constants
|
|
46
|
+
# @param install_facade [Boolean, nil] the deprecated spelling of `install_doors`; warns
|
|
47
|
+
# @param environment [String, nil] the environment name for `Adapters::Folder#load_domain`
|
|
78
48
|
# @return [Runtime::Dispatcher, Runtime::RemoteDispatcher] the dispatcher bound
|
|
79
49
|
# to the booted domain
|
|
80
|
-
def boot(path, shared: nil,
|
|
81
|
-
Loader.boot(path, shared: shared,
|
|
50
|
+
def boot(path, shared: nil, install_doors: true, install_facade: nil, environment: Runtime::Loader::FROM_ENV)
|
|
51
|
+
Loader.boot(path, shared: shared, install_doors: install_doors, environment: environment,
|
|
52
|
+
install_facade: install_facade)
|
|
82
53
|
end
|
|
83
54
|
|
|
84
|
-
#
|
|
55
|
+
# Loads a domain's declarations without binding any adapter. See Loader.describe.
|
|
56
|
+
#
|
|
57
|
+
# @param path [String] path to a domain directory, or a file inside one
|
|
58
|
+
# @param shared [String, nil] a shared-root override
|
|
59
|
+
# @param environment [String, nil] the environment overlay; defaults to `HECKS_ENVIRONMENT`
|
|
60
|
+
# @return [Runtime::Loader::Described] the loaded registry, answering `registry`
|
|
61
|
+
def describe(path, shared: nil, environment: Runtime::Loader::FROM_ENV)
|
|
62
|
+
Loader.describe(path, shared: shared, environment: environment)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Loads only the given files of a domain; otherwise like `boot`. See Loader.boot_files.
|
|
85
66
|
#
|
|
86
67
|
# @param paths [String, Array<String>] one or more file paths within the domain
|
|
87
|
-
#
|
|
88
|
-
# @param
|
|
89
|
-
# @param install_facade [Boolean]
|
|
90
|
-
#
|
|
91
|
-
# @param environment [String, nil] the environment name passed through to the
|
|
92
|
-
# selected-file loader
|
|
68
|
+
# @param shared [String, nil] a shared-root override
|
|
69
|
+
# @param install_doors [Boolean] whether to install the Ruby facade constants
|
|
70
|
+
# @param install_facade [Boolean, nil] the deprecated spelling of `install_doors`; warns
|
|
71
|
+
# @param environment [String, nil] the environment name for the selected-file loader
|
|
93
72
|
# @return [Runtime::Dispatcher, Runtime::RemoteDispatcher] the dispatcher bound
|
|
94
73
|
# to the booted domain
|
|
95
|
-
def boot_files(paths, shared: nil,
|
|
96
|
-
Loader.boot_files(paths, shared: shared,
|
|
74
|
+
def boot_files(paths, shared: nil, install_doors: true, install_facade: nil, environment: Runtime::Loader::FROM_ENV)
|
|
75
|
+
Loader.boot_files(paths, shared: shared, install_doors: install_doors, environment: environment,
|
|
76
|
+
install_facade: install_facade)
|
|
97
77
|
end
|
|
98
78
|
|
|
99
79
|
# Bind the ambient registry for the duration of the block, restoring
|
|
@@ -110,23 +90,9 @@ module Hecks
|
|
|
110
90
|
@current_registry = previous
|
|
111
91
|
end
|
|
112
92
|
|
|
113
|
-
#
|
|
114
|
-
#
|
|
115
|
-
# against.
|
|
116
|
-
#
|
|
117
|
-
# `as_of:` is optional, same opt-in shape as `actor_id:` — a caller
|
|
118
|
-
# that wants a Governance `RoleAssignment`'s `starts_at` enforced
|
|
119
|
-
# passes `as_of: Ports::Clock.now(registry)` here, at the door,
|
|
120
|
-
# exactly where `cli_runner.rb` already merges `Clock.now` into a
|
|
121
|
-
# command's own args. Nothing on the dispatch path calls the clock
|
|
122
|
-
# itself — see `Ports::Clock`'s own header for why — so an unbound
|
|
123
|
-
# `as_of` leaves `starts_at` unchecked, exactly as before.
|
|
93
|
+
# Binds the ambient caller (see Runtime::Caller) for the duration of the block.
|
|
94
|
+
# A command's declared `role` is checked against it.
|
|
124
95
|
#
|
|
125
|
-
# `scope:` is optional too — a caller that states which scope it is
|
|
126
|
-
# acting in gets that scope checked against the matching
|
|
127
|
-
# `RoleAssignment`'s own `scope`, not just its `role_name`. See
|
|
128
|
-
# `Runtime::Caller::Current`'s own header for why this lives here
|
|
129
|
-
# rather than as a command-level DSL construct.
|
|
130
96
|
# @param role [String, Symbol] the role to check the caller against
|
|
131
97
|
# @param actor_id [String, nil] who is calling, checked against a real Governance
|
|
132
98
|
# `RoleAssignment` when given; string-equality only against `role` when nil
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "open3"
|
|
5
|
+
require_relative "../rust_build"
|
|
6
|
+
require_relative "native_build"
|
|
7
|
+
|
|
8
|
+
module Hecks
|
|
9
|
+
module RustBuild
|
|
10
|
+
# The differential harness (ADR 0010): replays a corpus script through the Ruby interpreter
|
|
11
|
+
# (`Fuzzing::Replay`) and prints or diffs the JSON surface a Rust artifact must reproduce.
|
|
12
|
+
#
|
|
13
|
+
# With no artifact it prints Ruby's result as JSON, which saved to a file becomes a pinned
|
|
14
|
+
# expectation. The artifact is another artifact's JSON file, `native` (the workspace's
|
|
15
|
+
# `target/{release,debug}/rust`), a `.wasm` path (run under `wasmtime`), an executable path,
|
|
16
|
+
# or `build` (the domain's own Cargo feature, built and run); a live one gets the script on
|
|
17
|
+
# stdin. `HECKS_RUST_DIR` names the workspace and `CARGO_TARGET_DIR` where its output went.
|
|
18
|
+
module Conformance
|
|
19
|
+
USAGE = "usage: hecks check_conformance <domain> <script.json> " \
|
|
20
|
+
"[rust_output.json | native | build | path/to/binary | path/to/module.wasm]"
|
|
21
|
+
|
|
22
|
+
# The refusal kinds are not compared for ad-hoc filter steps: C8.3
|
|
23
|
+
# (docs/semantics/bluebook-semantics.md) is open (RuntimeError in Ruby, TypeMismatch in
|
|
24
|
+
# Rust), and only the message is byte-exact.
|
|
25
|
+
FILTER_VERB = "filter "
|
|
26
|
+
|
|
27
|
+
module_function
|
|
28
|
+
|
|
29
|
+
# @param argv [Array<String>] the domain, the script and optionally the artifact
|
|
30
|
+
# @return [Integer] 0 when the result is printed or matches, 1 on a mismatch
|
|
31
|
+
# @raise [Failure] when the artifact cannot be run
|
|
32
|
+
def call(argv)
|
|
33
|
+
require_relative "../../hecks"
|
|
34
|
+
require_relative "../fuzzing"
|
|
35
|
+
domain, script, other = argv
|
|
36
|
+
raise Failure, USAGE unless domain && script
|
|
37
|
+
|
|
38
|
+
ours = comparable(Hecks::Fuzzing::Replay.call(domain, JSON.parse(File.read(script)).fetch("steps")))
|
|
39
|
+
return print_result(ours) unless other
|
|
40
|
+
|
|
41
|
+
theirs = normalize(JSON.parse(artifact_output(domain, script, other)))
|
|
42
|
+
report(domain, script, ours, theirs)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def print_result(result)
|
|
46
|
+
puts JSON.pretty_generate(result)
|
|
47
|
+
0
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# @param result [Hash] `Fuzzing::Replay`'s answer
|
|
51
|
+
# @return [Hash{String => Object}] the surface a Rust artifact must reproduce
|
|
52
|
+
def comparable(result)
|
|
53
|
+
surface = {
|
|
54
|
+
"instances" => result[:instances].transform_values { |state| JSON.parse(JSON.generate(state)) },
|
|
55
|
+
"events" => result[:events].map { |event| event_surface(event) },
|
|
56
|
+
"refusals" => result[:refusals].map do |refusal|
|
|
57
|
+
{ "verb" => refusal[:verb], "error" => refusal[:error], "kind" => refusal[:kind]&.split("::")&.last }
|
|
58
|
+
end
|
|
59
|
+
}
|
|
60
|
+
# `verb` and `ok` only, as `Hecks::Fuzzing::Differential` compares; omitted when none.
|
|
61
|
+
dry_runs = result[:dry_runs].map { |dry| { "verb" => dry[:verb].to_s, "ok" => dry[:ok] } }
|
|
62
|
+
surface["dry_runs"] = dry_runs unless dry_runs.empty?
|
|
63
|
+
surface
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def event_surface(event)
|
|
67
|
+
{ "name" => event[:name], "aggregate" => event[:aggregate], "id" => event[:id].to_s,
|
|
68
|
+
"payload" => JSON.parse(JSON.generate(event[:payload])) }
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# The artifact's JSON for the script: live from a binary, or read from a file.
|
|
72
|
+
def artifact_output(domain, script, other)
|
|
73
|
+
case other
|
|
74
|
+
when "native" then run_binary(native_binary || missing_native!, script)
|
|
75
|
+
when "build" then run_binary(built_binary(domain), script)
|
|
76
|
+
when /\.wasm\z/
|
|
77
|
+
raise Failure, "#{other}: no such file — run hecks build_wasm #{domain} first" unless File.exist?(other)
|
|
78
|
+
|
|
79
|
+
run_process(["wasmtime", "run", other], File.read(script))
|
|
80
|
+
when ->(path) { !path.end_with?(".json") && File.file?(path) && File.executable?(path) }
|
|
81
|
+
# A pinned per-domain binary, as named by a sweep's `replay:` line.
|
|
82
|
+
run_binary(other, script)
|
|
83
|
+
else File.read(other)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def run_binary(binary, script) = run_process([binary], File.read(script))
|
|
88
|
+
|
|
89
|
+
def run_process(command, stdin_data)
|
|
90
|
+
stdout, status = Open3.capture2(*command, stdin_data: stdin_data)
|
|
91
|
+
raise Failure, "#{command.join(' ')} exited #{status.exitstatus}:\n#{stdout}" unless status.success?
|
|
92
|
+
|
|
93
|
+
stdout
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def target_dir = ENV.fetch("CARGO_TARGET_DIR", File.join(RustBuild.rust_dir, "target"))
|
|
97
|
+
|
|
98
|
+
def native_binary
|
|
99
|
+
%w[release debug].map { |profile| File.join(target_dir, profile, "rust") }.find { |path| File.executable?(path) }
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def missing_native!
|
|
103
|
+
raise Failure, "no native rust binary found under rust/target/{release,debug}/rust — run " \
|
|
104
|
+
"`cd rust && cargo build` first"
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Built on demand because `native` runs whichever domain the crate's default feature names.
|
|
108
|
+
def built_binary(domain)
|
|
109
|
+
feature = File.basename(domain.chomp("/"))
|
|
110
|
+
NativeBuild.build_rust_for(feature, RustBuild.rust_dir) or
|
|
111
|
+
raise Failure, "no `#{feature}` feature in rust/Cargo.toml — run hecks project_rust #{domain} first"
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Strips what a Rust run carries that Ruby has no analog for: `emitted_*` snapshot flags
|
|
115
|
+
# (ADR 0048) and the wall-clock `occurred_at` stamp two runs can never match.
|
|
116
|
+
def normalize(theirs)
|
|
117
|
+
if theirs["instances"].is_a?(Hash)
|
|
118
|
+
theirs["instances"].each_value do |record|
|
|
119
|
+
record.reject! { |key, _| key.start_with?("emitted_") } if record.is_a?(Hash)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
theirs["events"].each { |event| event.delete("occurred_at") if event.is_a?(Hash) } if theirs["events"].is_a?(Array)
|
|
123
|
+
theirs
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def report(domain, script, ours, theirs)
|
|
127
|
+
[ours, theirs].each { |side| drop_filter_kinds(side) }
|
|
128
|
+
mismatches = mismatches(ours, theirs)
|
|
129
|
+
if mismatches.empty?
|
|
130
|
+
puts "#{domain} / #{script}: matches."
|
|
131
|
+
return 0
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
warn "#{domain} / #{script}: #{mismatches.size} mismatch(es)\n\n#{mismatches.join("\n\n")}"
|
|
135
|
+
1
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def drop_filter_kinds(side)
|
|
139
|
+
return unless side["refusals"].is_a?(Array)
|
|
140
|
+
|
|
141
|
+
side["refusals"].each { |r| r.delete("kind") if r.is_a?(Hash) && r["verb"].to_s.start_with?(FILTER_VERB) }
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def mismatches(ours, theirs)
|
|
145
|
+
found = %w[instances events refusals].filter_map do |key|
|
|
146
|
+
next if ours[key] == theirs[key]
|
|
147
|
+
|
|
148
|
+
"#{key}:\n ruby: #{ours[key].inspect}\n other: #{theirs[key].inspect}"
|
|
149
|
+
end
|
|
150
|
+
their_dry_runs = Array(theirs["dry_runs"]).map { |dry| dry.slice("verb", "ok") }
|
|
151
|
+
if (ours["dry_runs"] || []) != their_dry_runs
|
|
152
|
+
found << "dry_runs:\n ruby: #{ours['dry_runs'].inspect}\n other: #{their_dry_runs.inspect}"
|
|
153
|
+
end
|
|
154
|
+
found
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require "json"
|
|
5
|
+
require "tmpdir"
|
|
6
|
+
require_relative "../cache_dir"
|
|
7
|
+
require_relative "../rust_build"
|
|
8
|
+
require_relative "conformance"
|
|
9
|
+
|
|
10
|
+
module Hecks
|
|
11
|
+
module RustBuild
|
|
12
|
+
# Runs generated fuzz sequences through `Conformance` against a native or `.wasm` artifact
|
|
13
|
+
# (ADR 0039), stopping at the first diverging seed with a reproduction command.
|
|
14
|
+
#
|
|
15
|
+
# ConformanceFuzz.call([domain, "native" | "path/to/module.wasm", seeds, steps])
|
|
16
|
+
#
|
|
17
|
+
# `seeds` and `steps` default to `SEEDS` and `STEPS` in the environment, then to 10 and 25.
|
|
18
|
+
module ConformanceFuzz
|
|
19
|
+
USAGE = "usage: hecks fuzz_conformance <domain> <native|path/to/module.wasm> [seeds] [steps]"
|
|
20
|
+
|
|
21
|
+
# What a domain directory's basename may be: a plain identifier, never `.` or `..`.
|
|
22
|
+
DOMAIN_NAME = /\A[A-Za-z0-9][A-Za-z0-9_-]*\z/
|
|
23
|
+
|
|
24
|
+
module_function
|
|
25
|
+
|
|
26
|
+
# @param argv [Array<String>] the domain, the artifact, and optionally seeds and steps
|
|
27
|
+
# @return [Integer] 0 when every sequence matched
|
|
28
|
+
# @raise [Failure] at the first seed that diverges, naming how to reproduce it
|
|
29
|
+
def call(argv)
|
|
30
|
+
require_relative "../../hecks"
|
|
31
|
+
require_relative "../fuzzing"
|
|
32
|
+
domain, artifact, seeds, steps = argv
|
|
33
|
+
raise Failure, USAGE unless domain && artifact
|
|
34
|
+
|
|
35
|
+
seeds = Integer(seeds || ENV["SEEDS"] || 10)
|
|
36
|
+
steps = Integer(steps || ENV["STEPS"] || 25)
|
|
37
|
+
scratch = scratch_dir(domain)
|
|
38
|
+
(1..seeds).each { |seed| replay(domain, artifact, seed, seeds, steps, scratch) }
|
|
39
|
+
FileUtils.rm_rf(scratch)
|
|
40
|
+
puts "#{domain}: #{seeds} generated sequence(s) x #{steps} step(s) each, all matched #{artifact}."
|
|
41
|
+
0
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# A fresh directory per run, under the cache root outside the gem, so concurrent runs never
|
|
45
|
+
# share one; it is kept when a seed diverges, so the failing script outlives the run.
|
|
46
|
+
#
|
|
47
|
+
# @param domain [String] the domain's directory; its basename names the scratch directory
|
|
48
|
+
# @return [String] the new directory
|
|
49
|
+
# @raise [Failure] when the basename cannot safely name a directory
|
|
50
|
+
def scratch_dir(domain)
|
|
51
|
+
name = File.basename(domain.to_s.chomp("/"))
|
|
52
|
+
raise Failure, "#{USAGE}\n`#{domain}` is not a domain directory name" unless name.match?(DOMAIN_NAME)
|
|
53
|
+
|
|
54
|
+
parent = Hecks::CacheDir.path("rust_conformance_fuzz")
|
|
55
|
+
FileUtils.mkdir_p(parent)
|
|
56
|
+
Dir.mktmpdir("#{name}-", parent)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def replay(domain, artifact, seed, seeds, steps, scratch)
|
|
60
|
+
sequence = Hecks::Fuzzing::SequenceGenerator.generate(domain, seed: seed, steps: steps)
|
|
61
|
+
path = File.join(scratch, "seed-#{seed}.json")
|
|
62
|
+
File.write(path, JSON.generate({ "steps" => sequence }))
|
|
63
|
+
return if Conformance.call([domain, path, artifact]).zero?
|
|
64
|
+
|
|
65
|
+
raise Failure, "hecks fuzz_conformance: seed #{seed}/#{seeds} diverged against #{artifact} " \
|
|
66
|
+
"(see the conformance output above) — " \
|
|
67
|
+
"reproduce with: hecks check_conformance #{domain} #{path} #{artifact}"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require "json"
|
|
5
|
+
require "open3"
|
|
6
|
+
require "tmpdir"
|
|
7
|
+
require_relative "../rust_build"
|
|
8
|
+
|
|
9
|
+
module Hecks
|
|
10
|
+
module RustBuild
|
|
11
|
+
# Reports whether each construct in a domain's IR has a real, routed implementation under
|
|
12
|
+
# `<workspace>/src/generated/<domain>` (ADR 0054a).
|
|
13
|
+
#
|
|
14
|
+
# Coverage.call([domain, "--codegen=ruby|rust"])
|
|
15
|
+
# Coverage.call(["--check-allowlist"])
|
|
16
|
+
#
|
|
17
|
+
# Ground truth is the generated module's `ir.json` and its `manifest.json`; a construct in the
|
|
18
|
+
# IR that the manifest omits is a synthetic `unaccounted` finding. The exit status is 1 when a
|
|
19
|
+
# gap remains that the allowlist does not excuse.
|
|
20
|
+
module Coverage
|
|
21
|
+
USAGE = "usage: hecks rust_coverage <generated-module-name> [--codegen=ruby|rust] " \
|
|
22
|
+
"(e.g. pizzas, banking, governance, identity)\n hecks rust_coverage --check-allowlist"
|
|
23
|
+
|
|
24
|
+
# Deliberate, documented gaps only, matched by kind, gap class and construct (never a regex
|
|
25
|
+
# over `reason` prose). The list only shrinks: `--check-allowlist` fails once a rule excuses
|
|
26
|
+
# no gap anywhere.
|
|
27
|
+
ALLOWLIST = [].freeze
|
|
28
|
+
|
|
29
|
+
module_function
|
|
30
|
+
|
|
31
|
+
# @param argv [Array<String>] the generated module's name and optional `--codegen=` flag,
|
|
32
|
+
# or `--check-allowlist`
|
|
33
|
+
# @return [Integer] 0 when nothing is a gap, 1 otherwise
|
|
34
|
+
# @raise [Failure] when the module, its `ir.json` or its manifest is missing
|
|
35
|
+
def call(argv)
|
|
36
|
+
flags, positional = argv.partition { |arg| arg.start_with?("--codegen") }
|
|
37
|
+
codegen = flags.empty? ? "ruby" : flags.last.delete_prefix("--codegen=")
|
|
38
|
+
raise Failure, "--codegen must be `ruby` or `rust` (got #{flags.last.inspect})" unless %w[ruby rust].include?(codegen)
|
|
39
|
+
|
|
40
|
+
target = positional.first or raise Failure, USAGE
|
|
41
|
+
return check_allowlist if target == "--check-allowlist"
|
|
42
|
+
|
|
43
|
+
report(target, codegen)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def rust_dir = RustBuild.rust_dir
|
|
47
|
+
|
|
48
|
+
def generated_root = File.join(rust_dir, "src/generated")
|
|
49
|
+
|
|
50
|
+
# Entity-scoped query ids at any depth (`Domain::Aggregate.Entity.Query`); mirrors the
|
|
51
|
+
# generator's own entity query entries.
|
|
52
|
+
def entity_query_ids(owner_id, entities)
|
|
53
|
+
entities.flat_map do |entity|
|
|
54
|
+
entity_id = "#{owner_id}.#{entity.fetch(:name)}"
|
|
55
|
+
entity.fetch(:queries, []).map { |q| "#{entity_id}.#{q.fetch(:name)}" } +
|
|
56
|
+
entity_query_ids(entity_id, entity.fetch(:entities, []))
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# The [kind, id] pairs the IR implies, independent of the manifest.
|
|
61
|
+
def expected_from_ir(payload)
|
|
62
|
+
domain_name = payload.fetch(:name)
|
|
63
|
+
expected = payload.fetch(:aggregates).flat_map { |aggregate| aggregate_constructs(domain_name, aggregate) }
|
|
64
|
+
payload.fetch(:read_models).each { |rm| expected << [:read_model, "#{domain_name}::#{rm.fetch(:name)}"] }
|
|
65
|
+
payload.fetch(:policies).each { |p| expected << [:policy, "#{domain_name}::#{p.fetch(:name)}"] }
|
|
66
|
+
payload.fetch(:process_managers).each { |pm| expected << [:process_manager, "#{domain_name}::#{pm.fetch(:name)}"] }
|
|
67
|
+
# An `ir.json` from before the `lineage` key existed has none: nothing to expect.
|
|
68
|
+
payload.fetch(:lineage, {}).fetch(:capable_aggregates, []).each do |aggregate|
|
|
69
|
+
expected << [:lineage_aggregate, "#{domain_name}::#{aggregate.fetch(:name)}"]
|
|
70
|
+
end
|
|
71
|
+
expected
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def aggregate_constructs(domain_name, aggregate)
|
|
75
|
+
id = "#{domain_name}::#{aggregate.fetch(:name)}"
|
|
76
|
+
found = [[:aggregate, id]]
|
|
77
|
+
aggregate.fetch(:commands).each { |c| found << [:command, "#{id}.#{c.fetch(:name)}"] }
|
|
78
|
+
aggregate.fetch(:queries).each { |q| found << [:query, "#{id}.#{q.fetch(:name)}"] }
|
|
79
|
+
entity_query_ids(id, aggregate.fetch(:entities)).each { |query_id| found << [:query, query_id] }
|
|
80
|
+
aggregate.fetch(:entities).each do |entity|
|
|
81
|
+
entity_id = "#{id}.#{entity.fetch(:name)}"
|
|
82
|
+
found << [:entity, entity_id]
|
|
83
|
+
entity.fetch(:commands).each { |c| found << [:entity_command, "#{entity_id}.#{c.fetch(:name)}"] }
|
|
84
|
+
end
|
|
85
|
+
aggregate.fetch(:ports).each do |port|
|
|
86
|
+
port.fetch(:operations).each { |op| found << [:port_operation, "#{id}.#{port.fetch(:name)}.#{op.fetch(:name)}"] }
|
|
87
|
+
end
|
|
88
|
+
found
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Parses a generated module's `ir.json` and `manifest.json`, adding a synthetic `unaccounted`
|
|
92
|
+
# finding for any IR construct the manifest omits.
|
|
93
|
+
def coverage_findings(mod_dir)
|
|
94
|
+
ir_path = File.join(mod_dir, "ir.json")
|
|
95
|
+
File.exist?(ir_path) or raise Failure, "#{ir_path}: missing — this generated tree predates ir.json " \
|
|
96
|
+
"(hecks project_rust writes it now); re-run hecks project_rust for this domain"
|
|
97
|
+
ir = JSON.parse(File.read(ir_path), symbolize_names: true)
|
|
98
|
+
manifest_path = File.join(mod_dir, "manifest.json")
|
|
99
|
+
File.exist?(manifest_path) or raise Failure, "#{manifest_path}: missing — re-run hecks project_rust for this " \
|
|
100
|
+
"domain to write it"
|
|
101
|
+
manifest = JSON.parse(File.read(manifest_path), symbolize_names: true)
|
|
102
|
+
[ir, manifest + unaccounted_findings(ir, manifest)]
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def allowlist_rule_matches?(rule, finding)
|
|
106
|
+
rule[:kind] == finding[:kind].to_s &&
|
|
107
|
+
rule[:gap_class] == finding[:gap_class].to_s &&
|
|
108
|
+
rule[:construct] == finding[:construct].to_s
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def allowlisted(finding) = ALLOWLIST.find { |rule| allowlist_rule_matches?(rule, finding) }
|
|
112
|
+
|
|
113
|
+
# A synthetic finding for each expected construct with no manifest entry at all: a gap in
|
|
114
|
+
# the manifest writer itself.
|
|
115
|
+
def unaccounted_findings(payload, manifest)
|
|
116
|
+
ids = Hash.new { |hash, kind| hash[kind] = Set.new }
|
|
117
|
+
manifest.each { |entry| ids[entry[:kind].to_sym] << entry[:id] }
|
|
118
|
+
expected_from_ir(payload).reject { |kind, id| ids[kind].include?(id) }.map do |kind, id|
|
|
119
|
+
{ kind: kind.to_s, id: id, generated: false, gap_class: "unaccounted", construct: "unaccounted",
|
|
120
|
+
reason: "expected per ir.json, but manifest.json has NO entry for it at all — not even a " \
|
|
121
|
+
"recorded skip; the generator's own accounting missed this construct entirely" }
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# A real functional gap: not generated, or generated but unrouted.
|
|
126
|
+
def functional_gap?(finding) = finding[:generated] == false || finding[:routed] == false
|
|
127
|
+
|
|
128
|
+
# Every rule must still excuse a real gap somewhere under `src/generated/`.
|
|
129
|
+
def check_allowlist
|
|
130
|
+
gaps = Dir.glob(File.join(generated_root, "*/ir.json")).flat_map do |ir_path|
|
|
131
|
+
coverage_findings(File.dirname(ir_path))[1].select { |finding| functional_gap?(finding) }
|
|
132
|
+
end
|
|
133
|
+
stale = ALLOWLIST.reject { |rule| gaps.any? { |finding| allowlist_rule_matches?(rule, finding) } }
|
|
134
|
+
if stale.empty?
|
|
135
|
+
puts "hecks rust_coverage --check-allowlist: all #{ALLOWLIST.size} rules still excuse a real gap"
|
|
136
|
+
return 0
|
|
137
|
+
end
|
|
138
|
+
stale.each do |rule|
|
|
139
|
+
warn "STALE ALLOWLIST RULE: #{rule.slice(:kind, :gap_class, :construct)} matches no gap in any generated " \
|
|
140
|
+
"module — the gap it excused is gone; delete the rule"
|
|
141
|
+
end
|
|
142
|
+
1
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def report(domain, codegen)
|
|
146
|
+
mod_dir = File.join(generated_root, domain)
|
|
147
|
+
Dir.exist?(mod_dir) or raise Failure, "#{mod_dir}: no such generated module — run hecks project_rust first, " \
|
|
148
|
+
"or check rust/src/generated/ for the actual directory name"
|
|
149
|
+
return print_report(domain, mod_dir) unless codegen == "rust"
|
|
150
|
+
|
|
151
|
+
Dir.mktmpdir("rust-coverage-codegen-") do |scratch|
|
|
152
|
+
print_report(domain, regenerated(mod_dir, domain, scratch))
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Regenerates the domain's manifest through `hecks-codegen` into a scratch directory. `cargo
|
|
157
|
+
# run` rather than a fixed target path, so `CARGO_TARGET_DIR` and rust-toolchain.toml apply.
|
|
158
|
+
def regenerated(mod_dir, domain, scratch)
|
|
159
|
+
ir_path = File.join(mod_dir, "ir.json")
|
|
160
|
+
File.exist?(File.join(mod_dir, "manifest.json")) or raise Failure, "#{mod_dir}: no committed manifest.json — " \
|
|
161
|
+
"re-run hecks project_rust for this domain to write it"
|
|
162
|
+
out_dir = File.join(scratch, domain)
|
|
163
|
+
output, status = Open3.capture2e("cargo", "run", "--quiet", "--", "domain", ir_path, domain, domain, out_dir,
|
|
164
|
+
chdir: File.join(rust_dir, "codegen"))
|
|
165
|
+
status.success? or raise Failure, "hecks-codegen domain failed for #{domain}:\n#{output}"
|
|
166
|
+
# `hecks-codegen domain` writes no ir.json sidecar; the cross-check reads the committed IR
|
|
167
|
+
# the generator was just handed.
|
|
168
|
+
FileUtils.cp(ir_path, File.join(out_dir, "ir.json"))
|
|
169
|
+
out_dir
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def print_report(domain, mod_dir)
|
|
173
|
+
ir, findings = coverage_findings(mod_dir)
|
|
174
|
+
# A construct is implemented only when generated and routed (where routing applies): a
|
|
175
|
+
# `dispatch_*` that compiles but nothing can call is not working.
|
|
176
|
+
implemented, remainder = findings.partition { |f| f[:generated] && f[:routed] != false }
|
|
177
|
+
deferred, gap = remainder.partition { |f| allowlisted(f) }
|
|
178
|
+
puts "=" * 72
|
|
179
|
+
puts "hecks rust_coverage #{domain} (source: manifest.json)"
|
|
180
|
+
puts "=" * 72
|
|
181
|
+
puts "#{ir.fetch(:name)} — #{findings.size} constructs accounted for " \
|
|
182
|
+
"(#{implemented.size} implemented, #{deferred.size} deferred, #{gap.size} GAP)"
|
|
183
|
+
print_bucket("IMPLEMENTED", implemented) unless implemented.empty?
|
|
184
|
+
print_deferred(deferred)
|
|
185
|
+
print_gaps(gap)
|
|
186
|
+
puts
|
|
187
|
+
gap.empty? ? 0 : 1
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def print_bucket(label, entries)
|
|
191
|
+
puts "\n#{label} (#{entries.size})"
|
|
192
|
+
sorted(entries).each { |entry| print_entry(entry) }
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def print_deferred(deferred)
|
|
196
|
+
puts "\nDEFERRED (#{deferred.size}) — on the allowlist, with its cited reason"
|
|
197
|
+
sorted(deferred).each do |entry|
|
|
198
|
+
puts " [#{entry[:kind]}] #{entry[:id]}"
|
|
199
|
+
puts " allowlist: #{allowlisted(entry)[:doc]}"
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def print_gaps(gap)
|
|
204
|
+
puts "\nGAP (#{gap.size}) — missing, and NOT on the allowlist: a real, actionable finding"
|
|
205
|
+
sorted(gap).each { |entry| print_entry(entry) }
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def print_entry(entry)
|
|
209
|
+
line = " [#{entry[:kind]}] #{entry[:id]}"
|
|
210
|
+
line += " (#{entry[:gap_class]})" if entry[:gap_class]
|
|
211
|
+
puts line
|
|
212
|
+
puts " #{entry[:reason]}" if entry[:reason]
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def sorted(entries) = entries.sort_by { |entry| [entry[:kind].to_s, entry[:id]] }
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|