rigortype 0.4.6 → 0.4.7
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/README.md +2 -2
- data/data/gem_overlay/activesupport/core_ext.rbs +16 -13
- data/data/vendored_gem_sigs/bundler/bundler.rbs +1 -1
- data/data/vendored_gem_sigs/rubygems/rubygems_extras.rbs +4 -3
- data/docs/handbook/01-getting-started.md +5 -2
- data/docs/handbook/11-sig-gen.md +50 -3
- data/docs/handbook/appendix-phpstan.md +4 -4
- data/docs/manual/02-cli-reference.md +152 -26
- data/docs/manual/03-configuration.md +36 -3
- data/docs/manual/06-baseline.md +6 -4
- data/docs/manual/09-editor-integration.md +13 -2
- data/docs/manual/10-mcp-server.md +38 -2
- data/docs/manual/12-caching.md +4 -3
- data/docs/manual/plugins/rigor-actionpack.md +19 -11
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +20 -1
- data/lib/rigor/analysis/baseline.rb +24 -27
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +5 -6
- data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +4 -4
- data/lib/rigor/analysis/check_rules/duplicate_hash_key_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/inferred_param_guard.rb +85 -13
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +3 -2
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +0 -1
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +5 -8
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +1 -1
- data/lib/rigor/analysis/check_rules/rebinding_block_callees.rb +3 -3
- data/lib/rigor/analysis/check_rules/return_in_ensure_collector.rb +1 -2
- data/lib/rigor/analysis/check_rules/rule_ids.rb +1 -1
- data/lib/rigor/analysis/check_rules/rule_walk.rb +9 -7
- data/lib/rigor/analysis/check_rules/shadowed_rescue_collector.rb +3 -4
- data/lib/rigor/analysis/check_rules/special_global_setters.rb +3 -3
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules.rb +124 -44
- data/lib/rigor/analysis/crash_signature.rb +2 -2
- data/lib/rigor/analysis/dependency_recorder.rb +4 -4
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +14 -3
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +1 -1
- data/lib/rigor/analysis/dependency_source_inference/index.rb +6 -8
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +4 -4
- data/lib/rigor/analysis/edit_replay.rb +93 -6
- data/lib/rigor/analysis/fact_store.rb +3 -3
- data/lib/rigor/analysis/incremental_run_slot/write_guard.rb +2 -2
- data/lib/rigor/analysis/incremental_run_slot.rb +2 -2
- data/lib/rigor/analysis/incremental_session.rb +27 -16
- data/lib/rigor/analysis/rule_catalog.rb +2 -2
- data/lib/rigor/analysis/run_stats.rb +2 -2
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +2 -2
- data/lib/rigor/analysis/runner/declaration_position.rb +1 -1
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +193 -93
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +1 -1
- data/lib/rigor/analysis/runner/pool_coordinator.rb +147 -323
- data/lib/rigor/analysis/runner/project_pre_passes.rb +3 -3
- data/lib/rigor/analysis/runner/run_level_facts.rb +304 -0
- data/lib/rigor/analysis/runner/run_snapshots.rb +44 -54
- data/lib/rigor/analysis/runner/worker_payload.rb +36 -0
- data/lib/rigor/analysis/runner.rb +77 -71
- data/lib/rigor/analysis/self_call_resolution_recorder.rb +1 -1
- data/lib/rigor/analysis/template_unit_positions.rb +2 -3
- data/lib/rigor/analysis/template_units.rb +9 -1
- data/lib/rigor/analysis/worker_session.rb +24 -31
- data/lib/rigor/bleeding_edge.rb +3 -6
- data/lib/rigor/builtins/imported_refinements.rb +6 -8
- data/lib/rigor/builtins/predefined_constant_refinements.rb +1 -1
- data/lib/rigor/builtins/regex_refinement.rb +4 -6
- data/lib/rigor/cache/descriptor.rb +6 -5
- data/lib/rigor/cache/incremental_snapshot.rb +31 -12
- data/lib/rigor/cache/rbs_cache_producer.rb +2 -2
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +1 -1
- data/lib/rigor/cache/rbs_class_type_param_names.rb +2 -2
- data/lib/rigor/cache/rbs_constant_table.rb +1 -1
- data/lib/rigor/cache/rbs_descriptor.rb +54 -3
- data/lib/rigor/cache/rbs_environment.rb +4 -1
- data/lib/rigor/cache/rbs_environment_marshal_patch.rb +2 -2
- data/lib/rigor/cache/rbs_known_class_names.rb +1 -1
- data/lib/rigor/cache/store.rb +11 -10
- data/lib/rigor/ci_detector.rb +1 -1
- data/lib/rigor/cli/annotate_command.rb +24 -19
- data/lib/rigor/cli/baseline_command.rb +145 -55
- data/lib/rigor/cli/catalogue.rb +256 -0
- data/lib/rigor/cli/check_command.rb +108 -102
- data/lib/rigor/cli/check_runner_factory.rb +2 -2
- data/lib/rigor/cli/command.rb +15 -1
- data/lib/rigor/cli/coverage_command.rb +21 -8
- data/lib/rigor/cli/coverage_mutation.rb +5 -7
- data/lib/rigor/cli/coverage_renderer.rb +2 -1
- data/lib/rigor/cli/coverage_scan.rb +3 -5
- data/lib/rigor/cli/diff_command.rb +25 -20
- data/lib/rigor/cli/docs_command.rb +1 -2
- data/lib/rigor/cli/doctor_command.rb +12 -12
- data/lib/rigor/cli/effects_command.rb +50 -40
- data/lib/rigor/cli/effects_diff_renderer.rb +18 -17
- data/lib/rigor/cli/effects_explain_renderer.rb +13 -12
- data/lib/rigor/cli/effects_renderer.rb +2 -1
- data/lib/rigor/cli/effects_snapshot_command.rb +18 -17
- data/lib/rigor/cli/explain_command.rb +18 -8
- data/lib/rigor/cli/fused_protection_renderer.rb +2 -1
- data/lib/rigor/cli/json_document.rb +41 -0
- data/lib/rigor/cli/lens_command.rb +12 -8
- data/lib/rigor/cli/lsp_command.rb +250 -23
- data/lib/rigor/cli/mcp_command.rb +12 -7
- data/lib/rigor/cli/mutation_fork_scan.rb +1 -1
- data/lib/rigor/cli/mutation_protection_renderer.rb +3 -2
- data/lib/rigor/cli/options.rb +40 -1
- data/lib/rigor/cli/plugin_command.rb +93 -46
- data/lib/rigor/cli/plugins_command.rb +17 -18
- data/lib/rigor/cli/plugins_renderer.rb +10 -6
- data/lib/rigor/cli/protection_fork_scan.rb +2 -2
- data/lib/rigor/cli/protection_renderer.rb +2 -1
- data/lib/rigor/cli/show_bleedingedge_command.rb +21 -15
- data/lib/rigor/cli/sig_gen_command.rb +84 -27
- data/lib/rigor/cli/skill_command.rb +32 -3
- data/lib/rigor/cli/skill_deep_probe.rb +1 -1
- data/lib/rigor/cli/skill_describe.rb +1 -1
- data/lib/rigor/cli/trace_command.rb +14 -9
- data/lib/rigor/cli/triage_command.rb +10 -11
- data/lib/rigor/cli/triage_renderer.rb +2 -1
- data/lib/rigor/cli/type_of_command.rb +16 -11
- data/lib/rigor/cli/type_of_project_scope.rb +1 -4
- data/lib/rigor/cli/type_of_renderer.rb +4 -1
- data/lib/rigor/cli/type_scan_command.rb +14 -9
- data/lib/rigor/cli/type_scan_renderer.rb +2 -1
- data/lib/rigor/cli/unused_command.rb +27 -17
- data/lib/rigor/cli/upgrade_command.rb +5 -0
- data/lib/rigor/cli.rb +209 -54
- data/lib/rigor/config_audit.rb +1 -1
- data/lib/rigor/configuration/severity_profile.rb +5 -5
- data/lib/rigor/configuration.rb +72 -30
- data/lib/rigor/effects/definition_context.rb +0 -2
- data/lib/rigor/effects/envelope.rb +1 -1
- data/lib/rigor/effects/framework_units.rb +1 -1
- data/lib/rigor/effects/mutation_classifier.rb +4 -7
- data/lib/rigor/effects/propagator.rb +1 -1
- data/lib/rigor/effects/registry.rb +2 -2
- data/lib/rigor/effects/snapshot.rb +1 -1
- data/lib/rigor/effects/taint_cause.rb +0 -2
- data/lib/rigor/effects/unit_scan.rb +9 -13
- data/lib/rigor/environment/bundle_sig_discovery.rb +5 -9
- data/lib/rigor/environment/class_registry.rb +3 -3
- data/lib/rigor/environment/core_root.rb +77 -0
- data/lib/rigor/environment/default_libraries.rb +1 -1
- data/lib/rigor/environment/deferred_signature_plan.rb +283 -0
- data/lib/rigor/environment/gated_signature_guard.rb +1 -1
- data/lib/rigor/environment/gated_signature_plan.rb +5 -2
- data/lib/rigor/environment/lockfile_resolver.rb +28 -12
- data/lib/rigor/environment/member_consistency/comparator.rb +18 -1
- data/lib/rigor/environment/member_consistency.rb +56 -7
- data/lib/rigor/environment/missing_gem_constant_index.rb +3 -2
- data/lib/rigor/environment/project_path_gems.rb +124 -0
- data/lib/rigor/environment/rbs_hierarchy.rb +6 -15
- data/lib/rigor/environment/rbs_loader.rb +480 -67
- data/lib/rigor/environment/reflection.rb +7 -7
- data/lib/rigor/environment/required_features.rb +0 -3
- data/lib/rigor/environment/ruby_library_roots.rb +1 -1
- data/lib/rigor/environment/vendored_signature_plan.rb +153 -0
- data/lib/rigor/environment.rb +41 -10
- data/lib/rigor/flow_contribution/merger.rb +4 -4
- data/lib/rigor/inference/acceptance.rb +93 -32
- data/lib/rigor/inference/block_parameter_binder.rb +2 -3
- data/lib/rigor/inference/block_run_count.rb +178 -0
- data/lib/rigor/inference/budget_trace.rb +8 -2
- data/lib/rigor/inference/builtins/exception_catalog.rb +2 -2
- data/lib/rigor/inference/builtins/numeric_catalog.rb +2 -5
- data/lib/rigor/inference/builtins/random_catalog.rb +2 -2
- data/lib/rigor/inference/callee_mutation_chain.rb +88 -77
- data/lib/rigor/inference/callee_write_census.rb +815 -0
- data/lib/rigor/inference/construction_escape.rb +217 -0
- data/lib/rigor/inference/declaration_walk/traversal.rb +1 -1
- data/lib/rigor/inference/deep_erasure.rb +39 -7
- data/lib/rigor/inference/def_handle.rb +1 -1
- data/lib/rigor/inference/def_node_resolver.rb +1 -1
- data/lib/rigor/inference/def_return_typer.rb +46 -4
- data/lib/rigor/inference/definer_resolution.rb +4 -2
- data/lib/rigor/inference/definers_index.rb +106 -0
- data/lib/rigor/inference/direct_ivar_writes.rb +300 -0
- data/lib/rigor/inference/element_read_widening.rb +49 -3
- data/lib/rigor/inference/expression_typer.rb +116 -49
- data/lib/rigor/inference/external_ancestor_resolution.rb +3 -4
- data/lib/rigor/inference/global_write_census.rb +76 -2
- data/lib/rigor/inference/global_writer_reach.rb +260 -0
- data/lib/rigor/inference/hkt_body.rb +1 -2
- data/lib/rigor/inference/hkt_body_parser.rb +3 -5
- data/lib/rigor/inference/hkt_reducer.rb +2 -2
- data/lib/rigor/inference/hkt_registry.rb +3 -5
- data/lib/rigor/inference/indexed_narrowing.rb +4 -7
- data/lib/rigor/inference/intervening_ivar_reset.rb +26 -4
- data/lib/rigor/inference/ivar_writer_census.rb +51 -0
- data/lib/rigor/inference/key_presence_guard.rb +2 -1
- data/lib/rigor/inference/loop_value_record.rb +8 -4
- data/lib/rigor/inference/match_rebinding/frame.rb +46 -0
- data/lib/rigor/inference/match_rebinding/yielding_match.rb +45 -0
- data/lib/rigor/inference/match_rebinding.rb +11 -1
- data/lib/rigor/inference/memo_audit.rb +55 -0
- data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/argument_distribution.rb +40 -0
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +3 -3
- data/lib/rigor/inference/method_dispatcher/contested_overloads.rb +89 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/no_match_fallback.rb +54 -0
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +39 -27
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +203 -17
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/self_substitute.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +9 -7
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +83 -20
- data/lib/rigor/inference/method_dispatcher/singleton_folding.rb +0 -1
- data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +50 -17
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +5 -5
- data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +4 -6
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher.rb +64 -14
- data/lib/rigor/inference/module_function_state.rb +11 -1
- data/lib/rigor/inference/multi_target_binder.rb +1 -1
- data/lib/rigor/inference/mutation_rejoin.rb +240 -4
- data/lib/rigor/inference/mutation_widening.rb +157 -27
- data/lib/rigor/inference/narrowing.rb +47 -33
- data/lib/rigor/inference/optimistic_origin.rb +1 -1
- data/lib/rigor/inference/out_buffer_mutation.rb +72 -0
- data/lib/rigor/inference/parameter_inference_collector.rb +5 -6
- data/lib/rigor/inference/pre_eval_constants.rb +1 -1
- data/lib/rigor/inference/project_method_ownership.rb +6 -3
- data/lib/rigor/inference/project_yielder.rb +11 -17
- data/lib/rigor/inference/receiver_alias.rb +20 -0
- data/lib/rigor/inference/refined_dispatch/constructed_class.rb +3 -1
- data/lib/rigor/inference/refined_dispatch/own_method.rb +2 -1
- data/lib/rigor/inference/remover_holder_scan.rb +233 -0
- data/lib/rigor/inference/remover_narrowing.rb +224 -0
- data/lib/rigor/inference/rewrite_mutation.rb +53 -2
- data/lib/rigor/inference/scope_indexer/certainty.rb +0 -1
- data/lib/rigor/inference/scope_indexer/constant_ivar_value.rb +93 -0
- data/lib/rigor/inference/scope_indexer/declared_param_writes.rb +58 -15
- data/lib/rigor/inference/scope_indexer/derived_param_value.rb +112 -0
- data/lib/rigor/inference/scope_indexer/empty_seed.rb +99 -0
- data/lib/rigor/inference/scope_indexer/ivar_contributions.rb +135 -0
- data/lib/rigor/inference/scope_indexer.rb +137 -46
- data/lib/rigor/inference/self_call_ivar_writes.rb +84 -12
- data/lib/rigor/inference/set_mutation.rb +189 -0
- data/lib/rigor/inference/singleton_hook_decline.rb +1 -2
- data/lib/rigor/inference/statement_evaluator.rb +2328 -138
- data/lib/rigor/inference/struct_fold_safety.rb +4 -6
- data/lib/rigor/inference/synthetic_method_scanner.rb +5 -6
- data/lib/rigor/inference/toplevel_def_census.rb +59 -0
- data/lib/rigor/inference/unknown_store_widening.rb +103 -4
- data/lib/rigor/inference/unthreaded_rebinds.rb +2 -3
- data/lib/rigor/inference/void_tail_summary.rb +2 -1
- data/lib/rigor/language_server/buffer_table.rb +3 -3
- data/lib/rigor/language_server/completion_provider.rb +26 -20
- data/lib/rigor/language_server/config_warning_announcer.rb +28 -0
- data/lib/rigor/language_server/diagnostic_publisher.rb +8 -3
- data/lib/rigor/language_server/document_symbol_provider.rb +1 -1
- data/lib/rigor/language_server/folding_range_provider.rb +1 -2
- data/lib/rigor/language_server/hover_provider.rb +1 -7
- data/lib/rigor/language_server/hover_renderer.rb +6 -8
- data/lib/rigor/language_server/project_context.rb +39 -1
- data/lib/rigor/language_server/publish_batcher.rb +3 -4
- data/lib/rigor/language_server/selection_range_provider.rb +2 -4
- data/lib/rigor/language_server/server.rb +7 -3
- data/lib/rigor/language_server/signature_help_provider.rb +4 -4
- data/lib/rigor/lens/plugins.rb +1 -1
- data/lib/rigor/mcp/server.rb +73 -2
- data/lib/rigor/mcp.rb +1 -1
- data/lib/rigor/plugin/access_denied_error.rb +1 -2
- data/lib/rigor/plugin/bundled_catalog.rb +1 -12
- data/lib/rigor/plugin/io_boundary.rb +1 -1
- data/lib/rigor/plugin/loader.rb +25 -8
- data/lib/rigor/plugin/macro/heredoc_template.rb +7 -8
- data/lib/rigor/plugin/macro/trait_registry.rb +6 -9
- data/lib/rigor/plugin/manifest.rb +9 -13
- data/lib/rigor/plugin/registry.rb +3 -3
- data/lib/rigor/plugin/services.rb +2 -3
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +11 -0
- data/lib/rigor/plugin/trust_policy.rb +2 -2
- data/lib/rigor/plugin/type_node_resolver.rb +2 -4
- data/lib/rigor/plugin.rb +6 -8
- data/lib/rigor/plugin_gap_advisory.rb +5 -1
- data/lib/rigor/project_environment.rb +16 -2
- data/lib/rigor/protection/analysis_guard.rb +1 -1
- data/lib/rigor/protection/discovery_seed.rb +44 -5
- data/lib/rigor/protection/mutator.rb +1 -1
- data/lib/rigor/rbs_extended/envelope_scanner.rb +4 -6
- data/lib/rigor/rbs_extended/hkt_directives.rb +6 -10
- data/lib/rigor/rbs_extended/reporter.rb +27 -3
- data/lib/rigor/rbs_extended.rb +2 -3
- data/lib/rigor/reflection/constant_ancestors.rb +5 -3
- data/lib/rigor/rooted_glob.rb +15 -1
- data/lib/rigor/run_scoped_slots.rb +38 -0
- data/lib/rigor/runtime/jit.rb +1 -1
- data/lib/rigor/scope/discovery_index.rb +19 -6
- data/lib/rigor/scope/resolution_chain.rb +3 -1
- data/lib/rigor/scope.rb +365 -31
- data/lib/rigor/sig_gen/classification.rb +4 -0
- data/lib/rigor/sig_gen/effect_annotation.rb +3 -3
- data/lib/rigor/sig_gen/generator.rb +371 -58
- data/lib/rigor/sig_gen/generic_header_scan.rb +189 -0
- data/lib/rigor/sig_gen/inline_declarations.rb +2 -2
- data/lib/rigor/sig_gen/layout_index.rb +3 -3
- data/lib/rigor/sig_gen/method_candidate.rb +23 -4
- data/lib/rigor/sig_gen/observation_collector.rb +3 -5
- data/lib/rigor/sig_gen/observed_call.rb +1 -1
- data/lib/rigor/sig_gen/path_mapper.rb +6 -0
- data/lib/rigor/sig_gen/renderer.rb +15 -9
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +15 -2
- data/lib/rigor/sig_gen/type_name_qualification.rb +69 -0
- data/lib/rigor/sig_gen/write_reporter.rb +63 -14
- data/lib/rigor/sig_gen/write_result.rb +23 -12
- data/lib/rigor/sig_gen/writer.rb +217 -37
- data/lib/rigor/type/acceptance_router.rb +2 -2
- data/lib/rigor/type/accepts_result.rb +1 -1
- data/lib/rigor/type/app.rb +4 -6
- data/lib/rigor/type/combinator.rb +9 -13
- data/lib/rigor/type/constant.rb +4 -5
- data/lib/rigor/type/hash_shape.rb +21 -40
- data/lib/rigor/type/union.rb +1 -1
- data/lib/rigor/type_node/identifier.rb +1 -2
- data/lib/rigor/type_node/resolver_chain.rb +1 -1
- data/lib/rigor/type_node/string_literal.rb +1 -2
- data/lib/rigor/type_node/symbol_literal.rb +1 -2
- data/lib/rigor/type_node/union.rb +3 -6
- data/lib/rigor/value_semantics.rb +1 -10
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +2 -2
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +2 -3
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +1 -1
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +38 -36
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +4 -2
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +6 -4
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +1 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +1 -5
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_scan.rb +0 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/erb_compiler.rb +2 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +1 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +66 -19
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +4 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/association_roots.rb +3 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/effects.rb +2 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +21 -31
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +10 -16
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +2 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +0 -1
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +5 -4
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +3 -4
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +1 -1
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +7 -12
- data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +1 -1
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +1 -1
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/symbolize_keys.rb +102 -0
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +19 -6
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +26 -13
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_index.rb +3 -3
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +1 -3
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +6 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +5 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +1 -1
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/params_shape.rb +2 -3
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +5 -8
- data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +1 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +10 -18
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/analyzer.rb +0 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/discoverer.rb +0 -2
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +4 -5
- data/plugins/rigor-grape/lib/rigor/plugin/grape.rb +0 -2
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +6 -7
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +2 -4
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +2 -5
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +2 -2
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +6 -6
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +2 -1
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +3 -8
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +2 -3
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +5 -8
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +1 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +2 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +1 -1
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +4 -11
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +1 -1
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +2 -1
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +1 -1
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +2 -2
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +3 -4
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +6 -8
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +3 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +4 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +6 -7
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +1 -1
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +2 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +17 -21
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +2 -3
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_discoverer.rb +3 -2
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_index.rb +4 -4
- data/sig/rigor/analysis/baseline.rbs +0 -3
- data/sig/rigor/analysis/fact_store.rbs +1 -0
- data/sig/rigor/analysis/reachability/scan_cache.rbs +1 -1
- data/sig/rigor/cli/diff_command.rbs +1 -1
- data/sig/rigor/cli/explain_command.rbs +1 -1
- data/sig/rigor/effects/registry.rbs +2 -2
- data/sig/rigor/inference.rbs +4 -1
- data/sig/rigor/plugin/additional_initializer.rbs +0 -5
- data/sig/rigor/plugin/base.rbs +1 -0
- data/sig/rigor/plugin/effect_attribution.rbs +3 -3
- data/sig/rigor/plugin/effect_edge.rbs +1 -1
- data/sig/rigor/plugin/effect_entry_points.rbs +3 -3
- data/sig/rigor/plugin/io_boundary.rbs +2 -1
- data/sig/rigor/plugin/manifest.rbs +9 -9
- data/sig/rigor/plugin/protocol_contract.rbs +3 -7
- data/sig/rigor/scope.rbs +23 -3
- data/skills/rigor-plugin-author/SKILL.md +4 -4
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +5 -5
- data/skills/rigor-plugin-review/SKILL.md +3 -3
- data/skills/rigor-project-init/references/03-baseline-and-bugs.md +12 -1
- metadata +36 -3
|
@@ -378,8 +378,8 @@ module Rigor
|
|
|
378
378
|
# Builds the {Rigor::Plugin::TrustPolicy} for this run. Trusted gems are the gem-name half of every
|
|
379
379
|
# entry in `Configuration#plugins`. Allowed read roots default to the project root (CWD), the
|
|
380
380
|
# project's signature_paths, and each trusted gem's `Gem::Specification#full_gem_path`, plus any
|
|
381
|
-
# extras the user listed under `plugins_io.allowed_paths`.
|
|
382
|
-
#
|
|
381
|
+
# extras the user listed under `plugins_io.allowed_paths`. `network_policy` is `plugins_io.network`
|
|
382
|
+
# (`:disabled` or `:allowlist`).
|
|
383
383
|
def build_trust_policy
|
|
384
384
|
trusted_gems = @configuration.plugins.map { |entry| trusted_gem_name(entry) }.uniq
|
|
385
385
|
roots = [Dir.pwd]
|
|
@@ -409,7 +409,7 @@ module Rigor
|
|
|
409
409
|
return nil if gem_name.nil? || gem_name.empty?
|
|
410
410
|
|
|
411
411
|
spec = Gem.loaded_specs[gem_name]
|
|
412
|
-
spec&.full_gem_path
|
|
412
|
+
spec&.full_gem_path
|
|
413
413
|
rescue StandardError
|
|
414
414
|
nil
|
|
415
415
|
end
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rigor
|
|
4
|
+
module Analysis
|
|
5
|
+
class Runner
|
|
6
|
+
# ADR-116 WD3 (#1195) — the run-level fact registry. A run-level fact is a fact about the RUN rather than
|
|
7
|
+
# about one file: the project-signature state, the definition-build failures, the HKT-scan outcome, the
|
|
8
|
+
# `RunStats` RBS tables, the effect-annotation carrier. Each is declared ONCE below, and every path that
|
|
9
|
+
# used to hand-list the slots — the {RunSnapshots} store, the {PoolCoordinator} backends, the
|
|
10
|
+
# {WorkerSession} drain, the {DiagnosticAggregator} rows and the incremental snapshot's
|
|
11
|
+
# `RunLevelRows` — reads the declarations instead.
|
|
12
|
+
#
|
|
13
|
+
# A {Fact} carries:
|
|
14
|
+
#
|
|
15
|
+
# - `name` and `empty` — the store key and its value before anything is recorded;
|
|
16
|
+
# - `merge` — how a recorded value folds into the slot: {Merge.assign}, {Merge.first_wins} (#784) or
|
|
17
|
+
# {Merge.union_by_class} (#696);
|
|
18
|
+
# - `source` — `:environment` (read off a coordinator-side environment before the per-file loop, so a
|
|
19
|
+
# fork child inherits the demand it makes), `:analysis` (read after the loop, and drained out of each
|
|
20
|
+
# pool worker, because the per-file analysis is what demands it) or `:stats` (`RunStats` telemetry,
|
|
21
|
+
# read only when stats are collected);
|
|
22
|
+
# - `gate` — for an `:environment` fact, which environment it is read from; an empty-closure run
|
|
23
|
+
# resolves one per gate, lazily, and every other path hands the same environment to both;
|
|
24
|
+
# - `demand` — for an `:analysis` fact, whether collecting it makes a demand of its own (the HKT
|
|
25
|
+
# registry build, #784) rather than reading what the analysis already demanded. A path that must not
|
|
26
|
+
# pay for a demand (the Ractor prewarm, an empty closure with a replay in hand) drains only the others;
|
|
27
|
+
# - `replay` — whether a narrowed incremental run replays the previous full run's value
|
|
28
|
+
# ({Cache::IncrementalSnapshot::RunLevelRows});
|
|
29
|
+
# - `row` / `position` — the {DiagnosticAggregator} method that turns the slot into diagnostics, and
|
|
30
|
+
# where that row sits in the post-analysis stream (docs/type-specification/diagnostic-policy.md fixes
|
|
31
|
+
# the order). Nil for a fact no diagnostic reads.
|
|
32
|
+
#
|
|
33
|
+
# The declaration ORDER is the collection order: {.harvest} reads the `:environment` facts in it, and
|
|
34
|
+
# that order is load-bearing (the stand-downs are read before the env-forcing reads, the conformance
|
|
35
|
+
# scan — which demands definitions — last). The row order is `position`, independently.
|
|
36
|
+
#
|
|
37
|
+
# Rows whose producer is not a slot here — the reporter streams, which the reporters snapshot and
|
|
38
|
+
# absorb themselves, and the two plugin tables the coordinator collects — are declared as {Row}s so
|
|
39
|
+
# the whole post-analysis order lives in one place.
|
|
40
|
+
#
|
|
41
|
+
# Everything here is frozen data plus module functions, never a closure: {WorkerSession#drain_reporters}
|
|
42
|
+
# reads these declarations inside a Ractor worker, and a drained value has to stay Marshal-clean (#805)
|
|
43
|
+
# for the fork backend.
|
|
44
|
+
module RunLevelFacts
|
|
45
|
+
Fact = Data.define(:name, :empty, :merge, :source, :gate, :demand, :replay, :row, :position)
|
|
46
|
+
Row = Data.define(:builder, :position)
|
|
47
|
+
|
|
48
|
+
# The predicates an `:environment` collector consults, taken by the coordinator when it harvests.
|
|
49
|
+
Context = Data.define(:project_signature_paths, :plugin_signature_paths, :record_effects)
|
|
50
|
+
|
|
51
|
+
# How a recorded value folds into its slot.
|
|
52
|
+
module Merge
|
|
53
|
+
module_function
|
|
54
|
+
|
|
55
|
+
def assign(_current, incoming)
|
|
56
|
+
incoming
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Issue #784 — the HKT scan is one build over the overlay every worker shares, so the first tuple
|
|
60
|
+
# recorded is the run's outcome.
|
|
61
|
+
def first_wins(current, incoming)
|
|
62
|
+
current.nil? ? incoming : current
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Issue #696 / #1902 — each pool worker holds its own loader, so the run's set is the union, one
|
|
66
|
+
# tuple per class chosen by {Environment::RbsLoader.definition_build_detail_order} rather than by
|
|
67
|
+
# arrival.
|
|
68
|
+
def union_by_class(current, incoming)
|
|
69
|
+
return current if incoming.nil? || incoming.empty?
|
|
70
|
+
|
|
71
|
+
(current + incoming)
|
|
72
|
+
.group_by(&:first)
|
|
73
|
+
.map { |_, candidates| candidates.min_by { |c| Environment::RbsLoader.definition_build_detail_order(c) } }
|
|
74
|
+
.freeze
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# One collector per fact, named after it: `(environment, context) -> value`.
|
|
79
|
+
module Collect
|
|
80
|
+
module_function
|
|
81
|
+
|
|
82
|
+
# Issue #610 — gated on a loaded plugin contributing signatures, not on `signature_paths:`: the
|
|
83
|
+
# source a plugin's `sig/` stands down against is typically an `rbs collection install`.
|
|
84
|
+
def signature_standdowns(environment, context)
|
|
85
|
+
return [] unless context.plugin_signature_paths
|
|
86
|
+
|
|
87
|
+
loader = environment&.rbs_loader
|
|
88
|
+
return [] if loader.nil? || !loader.respond_to?(:deferred_signature_paths)
|
|
89
|
+
return [] if loader.deferred_signature_paths.empty?
|
|
90
|
+
|
|
91
|
+
loader.signature_standdowns
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Issue #1713 — not behind the `signature_paths:` gate either; the loader answers without building
|
|
95
|
+
# its env when no gated directory is active.
|
|
96
|
+
def vendored_standdowns(environment, _context)
|
|
97
|
+
loader = environment&.rbs_loader
|
|
98
|
+
loader.respond_to?(:vendored_standdowns) ? loader.vendored_standdowns : []
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# The four below read the project's OWN `signature_paths:` state, and each forces the otherwise-lazy
|
|
102
|
+
# env build, so they are gated on the project declaring `signature_paths:`.
|
|
103
|
+
def synthesized_namespaces(environment, context)
|
|
104
|
+
return [] unless context.project_signature_paths
|
|
105
|
+
|
|
106
|
+
environment&.rbs_loader&.synthesized_namespaces || []
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Read after the env-forcing read above: the collision derivation reads the BUILT env.
|
|
110
|
+
def quarantined_signatures(environment, context)
|
|
111
|
+
return [] unless context.project_signature_paths
|
|
112
|
+
|
|
113
|
+
environment&.rbs_loader&.quarantined_signatures || []
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def env_build_failure(environment, context)
|
|
117
|
+
return nil unless context.project_signature_paths
|
|
118
|
+
|
|
119
|
+
environment&.rbs_loader&.env_build_failure
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Read LAST of the signature state: the scan demands the definition of every `rigor:v1:conforms-to`
|
|
123
|
+
# class, and a resulting definition-build failure has to be in the loader before the `:analysis`
|
|
124
|
+
# read of {.definition_build_failures}.
|
|
125
|
+
def conformance_results(environment, context)
|
|
126
|
+
return [] unless context.project_signature_paths
|
|
127
|
+
|
|
128
|
+
RbsExtended::ConformanceChecker.scan(environment&.rbs_loader)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# #441 — the inline stratum of `effect.annotations-unchecked`. Skipped when effect collection is on:
|
|
132
|
+
# {EffectEnvelopePass} reads the loader directly then.
|
|
133
|
+
def effect_annotation_carrier(environment, context)
|
|
134
|
+
virtual = context.record_effects ? nil : environment&.rbs_loader&.virtual_rbs
|
|
135
|
+
Effects::SignatureSources.annotated_carrier(virtual)
|
|
136
|
+
rescue StandardError
|
|
137
|
+
[].freeze
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Issue #696 — read after the loop: definition builds are lazy, per class, on first demand. NOT
|
|
141
|
+
# gated on `signature_paths:` like the signature state: nothing is forced here (this reads what the
|
|
142
|
+
# analysis already demanded), and two BUNDLED sources can collapse a class with no project sig set
|
|
143
|
+
# in sight (the `bigdecimal` / `BigMath` shape, #299).
|
|
144
|
+
def definition_build_failures(environment, _context)
|
|
145
|
+
environment&.rbs_loader&.definition_build_failures || []
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Issue #784 — the run demands the registry once itself, so the outcome does not depend on which
|
|
149
|
+
# files were analysed. One build, one outcome whoever demands it, so a Rigor-owned demand cannot
|
|
150
|
+
# change what is reported (unlike #696's per-class list).
|
|
151
|
+
def hkt_scan_failure(environment, _context)
|
|
152
|
+
return nil if environment.nil?
|
|
153
|
+
|
|
154
|
+
environment.hkt_registry
|
|
155
|
+
environment.hkt_scan_failure
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def class_decl_paths(environment, _context)
|
|
159
|
+
environment&.rbs_loader&.class_decl_paths || {}.freeze
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def signature_paths(environment, _context)
|
|
163
|
+
environment&.rbs_loader&.signature_paths || [].freeze
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
EMPTY_LIST = [].freeze
|
|
168
|
+
EMPTY_TABLE = {}.freeze
|
|
169
|
+
|
|
170
|
+
FACTS = [
|
|
171
|
+
Fact.new(name: :signature_standdowns, empty: EMPTY_LIST, merge: :assign, source: :environment,
|
|
172
|
+
gate: :signature_state, demand: false, replay: false,
|
|
173
|
+
row: :rbs_plugin_signature_stood_down_diagnostics, position: 60),
|
|
174
|
+
Fact.new(name: :vendored_standdowns, empty: EMPTY_LIST, merge: :assign, source: :environment,
|
|
175
|
+
gate: :signature_state, demand: false, replay: false,
|
|
176
|
+
row: :rbs_vendored_signature_stood_down_diagnostics, position: 70),
|
|
177
|
+
Fact.new(name: :synthesized_namespaces, empty: EMPTY_LIST, merge: :assign, source: :environment,
|
|
178
|
+
gate: :signature_state, demand: false, replay: false,
|
|
179
|
+
row: :rbs_synthesized_namespace_diagnostics, position: 50),
|
|
180
|
+
Fact.new(name: :quarantined_signatures, empty: EMPTY_LIST, merge: :assign, source: :environment,
|
|
181
|
+
gate: :signature_state, demand: false, replay: false,
|
|
182
|
+
row: :rbs_quarantined_signature_diagnostics, position: 10),
|
|
183
|
+
Fact.new(name: :env_build_failure, empty: nil, merge: :assign, source: :environment,
|
|
184
|
+
gate: :signature_state, demand: false, replay: false,
|
|
185
|
+
row: :rbs_environment_build_failed_diagnostics, position: 20),
|
|
186
|
+
Fact.new(name: :conformance_results, empty: EMPTY_LIST, merge: :assign, source: :environment,
|
|
187
|
+
gate: :signature_state, demand: false, replay: false,
|
|
188
|
+
row: :conforms_to_diagnostics, position: 80),
|
|
189
|
+
# Read by {EffectAnnotationResidualPass}, outside this stream.
|
|
190
|
+
Fact.new(name: :effect_annotation_carrier, empty: EMPTY_LIST, merge: :assign, source: :environment,
|
|
191
|
+
gate: :annotation_carrier, demand: false, replay: false, row: nil, position: nil),
|
|
192
|
+
Fact.new(name: :definition_build_failures, empty: EMPTY_LIST, merge: :union_by_class, source: :analysis,
|
|
193
|
+
gate: nil, demand: false, replay: true,
|
|
194
|
+
row: :rbs_definition_build_failed_diagnostics, position: 30),
|
|
195
|
+
Fact.new(name: :hkt_scan_failure, empty: nil, merge: :first_wins, source: :analysis,
|
|
196
|
+
gate: nil, demand: true, replay: true,
|
|
197
|
+
row: :rbs_hkt_scan_failed_diagnostics, position: 40),
|
|
198
|
+
Fact.new(name: :class_decl_paths, empty: EMPTY_TABLE, merge: :assign, source: :stats,
|
|
199
|
+
gate: nil, demand: false, replay: false, row: nil, position: nil),
|
|
200
|
+
Fact.new(name: :signature_paths, empty: EMPTY_LIST, merge: :assign, source: :stats,
|
|
201
|
+
gate: nil, demand: false, replay: false, row: nil, position: nil)
|
|
202
|
+
].freeze
|
|
203
|
+
|
|
204
|
+
# The rows no slot above produces. The reporter streams follow the `rbs.coverage.*` ladder and the
|
|
205
|
+
# conformance rows; the plugin-authored run disclosures (#1051) come before the engine-authored trust
|
|
206
|
+
# refusal envelope (#959), which is read last so every per-file plugin call has recorded its refusals.
|
|
207
|
+
ROWS = [
|
|
208
|
+
Row.new(builder: :unresolved_payload_diagnostics, position: 90),
|
|
209
|
+
Row.new(builder: :lossy_projection_diagnostics, position: 100),
|
|
210
|
+
Row.new(builder: :hkt_directive_diagnostics, position: 110),
|
|
211
|
+
Row.new(builder: :deprecated_form_diagnostics, position: 120),
|
|
212
|
+
Row.new(builder: :boundary_cross_diagnostics, position: 130),
|
|
213
|
+
Row.new(builder: :source_rbs_synthesis_diagnostics, position: 140),
|
|
214
|
+
Row.new(builder: :plugin_run_disclosure_diagnostics, position: 150),
|
|
215
|
+
Row.new(builder: :plugin_trust_refusal_diagnostics, position: 160)
|
|
216
|
+
].freeze
|
|
217
|
+
|
|
218
|
+
# The per-run reporter accumulators, by drain key. Each reporter snapshots and absorbs its own
|
|
219
|
+
# streams (`#snapshot` / `#absorb`), so a new stream inside one touches that reporter and its row.
|
|
220
|
+
REPORTERS = %i[rbs_extended boundary_cross source_rbs_synthesis].freeze
|
|
221
|
+
|
|
222
|
+
BY_NAME = FACTS.to_h { |fact| [fact.name, fact] }.freeze
|
|
223
|
+
|
|
224
|
+
# Read inside a Ractor worker's drain, so every constant here is deeply shareable.
|
|
225
|
+
Ractor.make_shareable(FACTS)
|
|
226
|
+
Ractor.make_shareable(ROWS)
|
|
227
|
+
Ractor.make_shareable(BY_NAME)
|
|
228
|
+
|
|
229
|
+
module_function
|
|
230
|
+
|
|
231
|
+
def facts
|
|
232
|
+
FACTS
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def fact(name)
|
|
236
|
+
BY_NAME.fetch(name)
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def names(source: nil)
|
|
240
|
+
(source ? FACTS.select { |fact| fact.source == source } : FACTS).map(&:name)
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def replayable_names
|
|
244
|
+
FACTS.select(&:replay).map(&:name)
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def empty_values
|
|
248
|
+
FACTS.to_h { |fact| [fact.name, fact.empty] }
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# The post-analysis diagnostic builders, in their contract order.
|
|
252
|
+
def row_builders
|
|
253
|
+
(FACTS.select(&:row).map { |fact| Row.new(builder: fact.row, position: fact.position) } + ROWS)
|
|
254
|
+
.sort_by(&:position)
|
|
255
|
+
.map(&:builder)
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# Collects every fact of `source`, in declaration order, from the environment the block yields for
|
|
259
|
+
# its gate (one call per gate, on first need). `:analysis` and `:stats` facts take the block's
|
|
260
|
+
# environment with a nil gate.
|
|
261
|
+
def harvest(source, context)
|
|
262
|
+
environments = {}
|
|
263
|
+
FACTS.each_with_object({}) do |fact, collected|
|
|
264
|
+
next unless fact.source == source
|
|
265
|
+
|
|
266
|
+
environment = environments.fetch(fact.gate) { environments[fact.gate] = yield(fact.gate) }
|
|
267
|
+
collected[fact.name] = Collect.public_send(fact.name, environment, context)
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
# The `:analysis` facts as an analysing process reports them: the {WorkerSession} drain, and the
|
|
272
|
+
# coordinator's own environment on the paths that analyse on it. Plain tuples — Marshal-clean and
|
|
273
|
+
# shareable.
|
|
274
|
+
#
|
|
275
|
+
# @param demanding — nil drains every `:analysis` fact; false only those that read what was already
|
|
276
|
+
# demanded; true only those that make a demand of their own.
|
|
277
|
+
def drain(environment, demanding: nil)
|
|
278
|
+
FACTS.each_with_object({}) do |fact, drained|
|
|
279
|
+
next unless fact.source == :analysis
|
|
280
|
+
next unless demanding.nil? || fact.demand == demanding
|
|
281
|
+
|
|
282
|
+
drained[fact.name] = Collect.public_send(fact.name, environment, nil)
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
# The `:analysis` facts out of a drained hash, for {RunSnapshots#absorb}.
|
|
287
|
+
def drained_facts(drained)
|
|
288
|
+
names(source: :analysis).each_with_object({}) do |name, facts|
|
|
289
|
+
facts[name] = drained[name] if drained.key?(name)
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def snapshot_reporters(reporters)
|
|
294
|
+
REPORTERS.to_h { |name| [name, reporters.fetch(name).snapshot] }
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
# A drain shape that lacks a reporter's key records nothing for it.
|
|
298
|
+
def absorb_reporters(reporters, drained)
|
|
299
|
+
REPORTERS.each { |name| reporters.fetch(name).absorb(drained[name]) }
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
end
|
|
@@ -1,68 +1,58 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "run_level_facts"
|
|
4
|
+
|
|
3
5
|
module Rigor
|
|
4
6
|
module Analysis
|
|
5
7
|
class Runner
|
|
6
|
-
# Mutable per-run
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
8
|
+
# Mutable per-run store for the run-level facts ({RunLevelFacts}): one slot per declared fact, keyed by
|
|
9
|
+
# its name. The analysis paths write it ({PoolCoordinator} — sequential, fork-pool, Ractor-pool,
|
|
10
|
+
# fallback, empty closure) and the rest of the run reads it back: the {DiagnosticAggregator} rows,
|
|
11
|
+
# {RunStats}, {EffectAnnotationResidualPass} and the incremental snapshot's `RunLevelRows`.
|
|
12
|
+
#
|
|
13
|
+
# A shared mutable holder keeps the write/read timing of the original inline ivars while letting the
|
|
14
|
+
# writer and the readers live in separate objects without a back-reference cycle.
|
|
11
15
|
#
|
|
12
|
-
# The
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
# back-reference cycle.
|
|
16
|
+
# The analysis paths write through {#absorb}, which folds each value in by its fact's declared merge
|
|
17
|
+
# rule. `[]=` and the per-fact `name=` writers (defined from the declarations, like the readers) are a
|
|
18
|
+
# plain assignment that bypasses the merge rule: they exist for specs that seed a slot, and no
|
|
19
|
+
# production path calls them.
|
|
17
20
|
class RunSnapshots
|
|
18
|
-
attr_accessor :class_decl_paths, :signature_paths,
|
|
19
|
-
:synthesized_namespaces, :quarantined_signatures, :signature_standdowns, :vendored_standdowns,
|
|
20
|
-
:conformance_results,
|
|
21
|
-
:env_build_failure, :definition_build_failures, :hkt_scan_failure,
|
|
22
|
-
:effect_annotation_carrier
|
|
23
|
-
|
|
24
|
-
# Constructor defaults match the {Runner} constructor: the pre-seed values `build_run_stats` /
|
|
25
|
-
# `pre_file_diagnostics` read before the first analysis path runs are frozen empties. The
|
|
26
|
-
# `env_build_failure` slot is nil (no failure) rather than an empty collection — it holds a single
|
|
27
|
-
# `[error_class, first_line, buffer_names]` tuple or nothing. Its per-class sibling
|
|
28
|
-
# `definition_build_failures` (#696) holds a LIST, because a collapsed universe fails many classes,
|
|
29
|
-
# and is accumulated ACROSS pool workers rather than assigned once — see
|
|
30
|
-
# {PoolCoordinator#merge_worker_reporters}. `hkt_scan_failure` (#784) is nil-or-tuple like
|
|
31
|
-
# `env_build_failure`, not a list like `definition_build_failures`: the scan is ONE build over the
|
|
32
|
-
# whole `signature_paths:` overlay, not a per-class one, so it has exactly one outcome per run.
|
|
33
|
-
# `signature_standdowns` (#610) is the quarantine slot's twin for the plugin-contributed files that
|
|
34
|
-
# stood down against a colliding generic arity: a list, assigned once from the loader as
|
|
35
|
-
# `quarantined_signatures` is, and derived from the final env so a cache HIT carries it too.
|
|
36
|
-
# `vendored_standdowns` (#1713) is the same shape of slot for what a required-feature-gated vendored
|
|
37
|
-
# directory left out because another signature source declares it.
|
|
38
21
|
def initialize
|
|
39
|
-
@
|
|
40
|
-
@signature_paths = [].freeze
|
|
41
|
-
@synthesized_namespaces = [].freeze
|
|
42
|
-
@quarantined_signatures = [].freeze
|
|
43
|
-
@signature_standdowns = [].freeze
|
|
44
|
-
@vendored_standdowns = [].freeze
|
|
45
|
-
@conformance_results = [].freeze
|
|
46
|
-
@env_build_failure = nil
|
|
47
|
-
@definition_build_failures = [].freeze
|
|
48
|
-
@hkt_scan_failure = nil
|
|
49
|
-
@effect_annotation_carrier = [].freeze
|
|
22
|
+
@values = RunLevelFacts.empty_values
|
|
50
23
|
end
|
|
51
24
|
|
|
52
|
-
# Per-`#run` reset
|
|
53
|
-
# from the frozen constructor defaults) at the top of each run.
|
|
25
|
+
# Per-`#run` reset to every fact's declared empty value.
|
|
54
26
|
def reset_for_run
|
|
55
|
-
@
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
@
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
@
|
|
27
|
+
@values = RunLevelFacts.empty_values
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def [](name)
|
|
31
|
+
RunLevelFacts.fact(name)
|
|
32
|
+
@values[name]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def []=(name, value)
|
|
36
|
+
RunLevelFacts.fact(name)
|
|
37
|
+
@values[name] = value
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Folds `facts` (`{name => value}`) into the store, each by its fact's merge rule.
|
|
41
|
+
def absorb(facts)
|
|
42
|
+
facts.each do |name, value|
|
|
43
|
+
merge = RunLevelFacts.fact(name).merge
|
|
44
|
+
@values[name] = RunLevelFacts::Merge.public_send(merge, @values[name], value)
|
|
45
|
+
end
|
|
46
|
+
self
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def to_h
|
|
50
|
+
@values.dup
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
RunLevelFacts.facts.each do |fact|
|
|
54
|
+
define_method(fact.name) { @values[fact.name] }
|
|
55
|
+
define_method(:"#{fact.name}=") { |value| @values[fact.name] = value }
|
|
66
56
|
end
|
|
67
57
|
end
|
|
68
58
|
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rigor
|
|
4
|
+
module Analysis
|
|
5
|
+
class Runner
|
|
6
|
+
# ADR-116 WD3 (#1195) — what one analysing {WorkerSession} hands back to the {PoolCoordinator}: its
|
|
7
|
+
# per-file results and every drain, taken in one place ({.harvest}) and folded in by one
|
|
8
|
+
# ({PoolCoordinator#absorb_worker_payload}). A fork child marshals it to its payload file, the Ractor
|
|
9
|
+
# backend sends it with `:done`, and the fork backend's degrade path harvests the parent session the
|
|
10
|
+
# same way.
|
|
11
|
+
#
|
|
12
|
+
# Every field is Marshal-clean (#805) and, on the Ractor backend, copyable: the drains are frozen
|
|
13
|
+
# `Data` entries and Hashes of Strings. `effects` is nil unless the run collects effects (ADR-103 WD13).
|
|
14
|
+
#
|
|
15
|
+
# The refusals are carried but not absorbed: their merge order is the file order of the whole run, so
|
|
16
|
+
# each backend merges them itself (#1900).
|
|
17
|
+
WorkerPayload = Data.define(:results, :reporters, :dependencies, :analysis_reads, :analysis_disclosures,
|
|
18
|
+
:disclosures, :refusals, :effects) do
|
|
19
|
+
# Drains `session` in the order the fork child always has: the reporters (which demand the HKT
|
|
20
|
+
# registry) before the refusal delta, so a refusal that demand makes is reported.
|
|
21
|
+
def self.harvest(session, results: {}, record_effects: false)
|
|
22
|
+
new(
|
|
23
|
+
results: results,
|
|
24
|
+
reporters: session.drain_reporters,
|
|
25
|
+
dependencies: session.drain_dependencies,
|
|
26
|
+
analysis_reads: session.drain_analysis_reads,
|
|
27
|
+
analysis_disclosures: session.drain_analysis_disclosures,
|
|
28
|
+
disclosures: session.drain_run_disclosures,
|
|
29
|
+
refusals: session.drain_trust_refusals,
|
|
30
|
+
effects: record_effects ? session.drain_effects : nil
|
|
31
|
+
)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|