rigortype 0.3.8 → 0.4.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/README.md +2 -2
- data/data/capability_roles/capability_roles.rbs +36 -0
- data/data/core_overlay/enumerable.rbs +51 -0
- data/data/core_overlay/enumerator.rbs +84 -0
- data/data/core_overlay/hash_rbs3.rbs +41 -0
- data/data/core_overlay/process.rbs +40 -0
- data/data/core_overlay/string_io.rbs +33 -0
- data/data/effects/core.yml +3 -3
- data/data/gem_overlay/activesupport/core_ext.rbs +236 -17
- data/docs/handbook/02-everyday-types.md +17 -14
- data/docs/handbook/03-narrowing.md +132 -14
- data/docs/handbook/04-tuples-and-shapes.md +8 -6
- data/docs/handbook/05-methods-and-blocks.md +1 -1
- data/docs/handbook/06-classes.md +2 -2
- data/docs/handbook/07-rbs-and-extended.md +19 -1
- data/docs/handbook/10-sorbet.md +9 -10
- data/docs/handbook/11-sig-gen.md +525 -13
- data/docs/handbook/README.md +1 -1
- data/docs/handbook/appendix-elixir.md +2 -2
- data/docs/handbook/appendix-go.md +2 -2
- data/docs/handbook/appendix-java-csharp.md +2 -2
- data/docs/handbook/appendix-mypy.md +2 -2
- data/docs/handbook/appendix-phpstan.md +1 -1
- data/docs/handbook/appendix-rust.md +1 -1
- data/docs/handbook/appendix-type-theory.md +4 -4
- data/docs/handbook/appendix-typescript.md +1 -1
- data/docs/llms.txt +2 -0
- data/docs/manual/02-cli-reference.md +95 -6
- data/docs/manual/03-configuration.md +18 -0
- data/docs/manual/04-diagnostics.md +15 -0
- data/docs/manual/07-plugins.md +15 -5
- data/docs/manual/08-skills.md +23 -2
- data/docs/manual/10-mcp-server.md +3 -2
- data/docs/manual/11-ci.md +9 -0
- data/docs/manual/15-type-protection-coverage.md +8 -0
- data/docs/manual/16-rbs-extended-annotations.md +46 -8
- data/docs/manual/18-removing-dead-code.md +10 -8
- data/docs/manual/19-effect-labels.md +10 -0
- data/docs/manual/plugins/README.md +7 -0
- data/docs/manual/plugins/rigor-actioncable.md +8 -1
- data/docs/manual/plugins/rigor-actionmailer.md +7 -0
- data/docs/manual/plugins/rigor-actionpack.md +261 -0
- data/docs/manual/plugins/rigor-active-model-serializers.md +153 -0
- data/docs/manual/plugins/rigor-activejob.md +7 -0
- data/docs/manual/plugins/rigor-activerecord.md +138 -4
- data/docs/manual/plugins/rigor-activestorage.md +8 -1
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +43 -7
- data/docs/manual/plugins/rigor-grape.md +106 -0
- data/docs/manual/plugins/rigor-graphql.md +23 -2
- data/docs/manual/plugins/rigor-pundit.md +8 -1
- data/docs/manual/plugins/rigor-rails-i18n.md +10 -5
- data/docs/manual/plugins/rigor-rails-routes.md +7 -0
- data/docs/manual/plugins/rigor-rbs-inline.md +229 -1
- data/docs/manual/plugins/rigor-sidekiq.md +8 -1
- data/docs/manual/plugins/rigor-sorbet.md +21 -5
- data/exe/rigor +19 -4
- data/lib/rigor/analysis/baseline.rb +3 -3
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/dead_version_guard_arms.rb +1 -5
- data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +167 -2
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +10 -2
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +189 -0
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +6 -4
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +15 -6
- data/lib/rigor/analysis/check_rules/rule_ids.rb +21 -6
- data/lib/rigor/analysis/check_rules/rule_walk.rb +41 -5
- data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +1 -1
- data/lib/rigor/analysis/check_rules/shadowed_rescue_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/source_arity.rb +323 -0
- data/lib/rigor/analysis/check_rules/special_global_setters.rb +146 -0
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +38 -4
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +0 -1
- data/lib/rigor/analysis/check_rules.rb +718 -79
- data/lib/rigor/analysis/crash_signature.rb +8 -24
- data/lib/rigor/analysis/dependency_recorder.rb +23 -0
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +1 -1
- data/lib/rigor/analysis/dependency_source_inference/builder.rb +0 -2
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +0 -2
- data/lib/rigor/analysis/dependency_source_inference/index.rb +5 -5
- data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +1 -2
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +4 -4
- data/lib/rigor/analysis/effects_cache_probe.rb +3 -4
- data/lib/rigor/analysis/erb_template_detector.rb +1 -2
- data/lib/rigor/analysis/fact_store.rb +15 -1
- data/lib/rigor/analysis/incremental.rb +42 -0
- data/lib/rigor/analysis/incremental_session.rb +117 -26
- data/lib/rigor/analysis/plugin_fact_fingerprint.rb +0 -1
- data/lib/rigor/analysis/project_scan.rb +11 -1
- data/lib/rigor/analysis/reachability/graph.rb +3 -5
- data/lib/rigor/analysis/reachability/plugin_roots.rb +5 -5
- data/lib/rigor/analysis/reachability/project_files.rb +2 -2
- data/lib/rigor/analysis/reachability/scan.rb +5 -5
- data/lib/rigor/analysis/reachability/scan_cache.rb +3 -2
- data/lib/rigor/analysis/reachability/signature_scan.rb +2 -2
- data/lib/rigor/analysis/result.rb +1 -3
- data/lib/rigor/analysis/rule_catalog.rb +131 -1
- data/lib/rigor/analysis/run_cache_key.rb +21 -12
- data/lib/rigor/analysis/run_cache_probe.rb +3 -5
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +6 -8
- data/lib/rigor/analysis/runner/declaration_position.rb +1 -2
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +340 -33
- data/lib/rigor/analysis/runner/effect_annotation_residual_pass.rb +2 -3
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +18 -14
- data/lib/rigor/analysis/runner/pool_coordinator.rb +357 -97
- data/lib/rigor/analysis/runner/project_pre_passes.rb +38 -13
- data/lib/rigor/analysis/runner/run_snapshots.rb +6 -1
- data/lib/rigor/analysis/runner.rb +407 -51
- data/lib/rigor/analysis/template_unit_collector.rb +303 -0
- data/lib/rigor/analysis/template_unit_paths.rb +91 -0
- data/lib/rigor/analysis/template_unit_positions.rb +293 -0
- data/lib/rigor/analysis/template_units.rb +399 -0
- data/lib/rigor/analysis/worker_session.rb +62 -20
- data/lib/rigor/bleeding_edge.rb +10 -24
- data/lib/rigor/builtins/hkt_builtins.rb +3 -2
- data/lib/rigor/builtins/imported_refinements.rb +159 -21
- data/lib/rigor/builtins/predefined_constant_refinements.rb +5 -7
- data/lib/rigor/builtins/regex_refinement.rb +21 -13
- data/lib/rigor/builtins/static_return_refinements.rb +7 -6
- data/lib/rigor/cache/annotation_location.rb +2 -4
- data/lib/rigor/cache/descriptor.rb +63 -20
- data/lib/rigor/cache/engine_source.rb +33 -5
- data/lib/rigor/cache/file_digest.rb +9 -1
- data/lib/rigor/cache/incremental_snapshot.rb +72 -6
- data/lib/rigor/cache/rbs_cache_producer.rb +4 -0
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +0 -3
- data/lib/rigor/cache/rbs_class_type_param_names.rb +0 -3
- data/lib/rigor/cache/rbs_constant_table.rb +0 -3
- data/lib/rigor/cache/rbs_descriptor.rb +112 -14
- data/lib/rigor/cache/rbs_environment.rb +8 -4
- data/lib/rigor/cache/rbs_known_class_names.rb +0 -3
- data/lib/rigor/cache/store.rb +76 -32
- data/lib/rigor/ci_detector.rb +1 -0
- data/lib/rigor/cli/annotate_command.rb +5 -6
- data/lib/rigor/cli/check_command.rb +57 -10
- data/lib/rigor/cli/check_invocation.rb +6 -11
- data/lib/rigor/cli/check_runner_factory.rb +1 -5
- data/lib/rigor/cli/coverage_command.rb +1 -1
- data/lib/rigor/cli/coverage_mutation.rb +12 -3
- data/lib/rigor/cli/coverage_scan.rb +1 -5
- data/lib/rigor/cli/diff_command.rb +1 -1
- data/lib/rigor/cli/doc_links.rb +4 -4
- data/lib/rigor/cli/docs_command.rb +6 -6
- data/lib/rigor/cli/doctor_command.rb +85 -38
- data/lib/rigor/cli/effects_command.rb +2 -2
- data/lib/rigor/cli/effects_diff_renderer.rb +3 -3
- data/lib/rigor/cli/effects_snapshot_command.rb +1 -1
- data/lib/rigor/cli/explain_command.rb +34 -1
- data/lib/rigor/cli/fused_protection_report.rb +7 -1
- data/lib/rigor/cli/lsp_command.rb +1 -1
- data/lib/rigor/cli/mcp_command.rb +1 -1
- data/lib/rigor/cli/measurement_integrity_warning.rb +4 -5
- data/lib/rigor/cli/mutation_fork_scan.rb +6 -6
- data/lib/rigor/cli/mutation_protection_report.rb +7 -1
- data/lib/rigor/cli/plugin_command.rb +4 -4
- data/lib/rigor/cli/plugins_command.rb +2 -1
- data/lib/rigor/cli/prism_colorizer.rb +1 -2
- data/lib/rigor/cli/protection_fork_scan.rb +6 -6
- data/lib/rigor/cli/show_bleedingedge_command.rb +1 -1
- data/lib/rigor/cli/sig_gen_command.rb +212 -31
- data/lib/rigor/cli/skill_command.rb +2 -2
- data/lib/rigor/cli/skill_deep_probe.rb +4 -4
- data/lib/rigor/cli/skill_describe.rb +35 -35
- data/lib/rigor/cli/trace_command.rb +4 -4
- data/lib/rigor/cli/trace_renderer.rb +5 -6
- data/lib/rigor/cli/triage_command.rb +1 -1
- data/lib/rigor/cli/type_of_command.rb +29 -11
- data/lib/rigor/cli/type_of_renderer.rb +20 -9
- data/lib/rigor/cli/type_of_template_probe.rb +189 -0
- data/lib/rigor/cli/type_scan_command.rb +4 -4
- data/lib/rigor/cli/unused_command.rb +11 -3
- data/lib/rigor/cli/upgrade_command.rb +1 -1
- data/lib/rigor/cli.rb +89 -9
- data/lib/rigor/config_audit.rb +30 -5
- data/lib/rigor/configuration/severity_profile.rb +25 -9
- data/lib/rigor/configuration.rb +109 -7
- data/lib/rigor/effects/ancestry_recorder.rb +191 -0
- data/lib/rigor/effects/attribution.rb +12 -5
- data/lib/rigor/effects/callee_rule.rb +368 -0
- data/lib/rigor/effects/catalog.rb +7 -4
- data/lib/rigor/effects/collector.rb +11 -5
- data/lib/rigor/effects/config_envelopes.rb +15 -10
- data/lib/rigor/effects/definition_context.rb +179 -0
- data/lib/rigor/effects/definition_lines.rb +25 -6
- data/lib/rigor/effects/effect_table.rb +11 -4
- data/lib/rigor/effects/entry_points.rb +0 -2
- data/lib/rigor/effects/envelope_check.rb +9 -9
- data/lib/rigor/effects/envelope_index.rb +20 -8
- data/lib/rigor/effects/file_collection.rb +59 -5
- data/lib/rigor/effects/framework_units.rb +5 -7
- data/lib/rigor/effects/identity.rb +20 -6
- data/lib/rigor/effects/inline_anchor.rb +7 -7
- data/lib/rigor/effects/label_intent.rb +3 -4
- data/lib/rigor/effects/liskov_check.rb +8 -8
- data/lib/rigor/effects/local_ownership.rb +38 -12
- data/lib/rigor/effects/method_key.rb +22 -1
- data/lib/rigor/effects/mutation_classifier.rb +23 -12
- data/lib/rigor/effects/plugin_facts.rb +47 -37
- data/lib/rigor/effects/propagator.rb +297 -19
- data/lib/rigor/effects/registry.rb +1 -1
- data/lib/rigor/effects/scanner.rb +122 -73
- data/lib/rigor/effects/signature_sources.rb +4 -6
- data/lib/rigor/effects/snapshot.rb +12 -11
- data/lib/rigor/effects/snapshot_diff.rb +1 -1
- data/lib/rigor/effects/summary.rb +27 -4
- data/lib/rigor/effects/unit_scan.rb +393 -38
- data/lib/rigor/effects/unknown_label_check.rb +3 -8
- data/lib/rigor/effects/unknown_label_report.rb +3 -4
- data/lib/rigor/effects/visibility.rb +101 -0
- data/lib/rigor/environment/bundle_sig_discovery.rb +6 -6
- data/lib/rigor/environment/class_registry.rb +3 -1
- data/lib/rigor/environment/failure_slot.rb +2 -2
- data/lib/rigor/environment/installed_gem_set.rb +85 -0
- data/lib/rigor/environment/lockfile_resolver.rb +68 -4
- data/lib/rigor/environment/member_consistency/comparator.rb +708 -0
- data/lib/rigor/environment/member_consistency.rb +298 -0
- data/lib/rigor/environment/missing_gem_constant_index.rb +4 -4
- data/lib/rigor/environment/rbs_collection_discovery.rb +5 -5
- data/lib/rigor/environment/rbs_coverage_report.rb +5 -5
- data/lib/rigor/environment/rbs_hierarchy.rb +3 -1
- data/lib/rigor/environment/rbs_loader.rb +674 -79
- data/lib/rigor/environment.rb +174 -24
- data/lib/rigor/flow_contribution/merger.rb +0 -2
- data/lib/rigor/flow_contribution.rb +11 -13
- data/lib/rigor/hashing/xxh3.rb +264 -0
- data/lib/rigor/inference/acceptance.rb +292 -17
- data/lib/rigor/inference/block_auto_splat.rb +216 -0
- data/lib/rigor/inference/block_call_timing.rb +338 -0
- data/lib/rigor/inference/block_parameter_binder.rb +75 -30
- data/lib/rigor/inference/block_repetition.rb +71 -0
- data/lib/rigor/inference/body_fixpoint.rb +7 -6
- data/lib/rigor/inference/budget_trace.rb +3 -6
- data/lib/rigor/inference/builtins/method_catalog.rb +2 -1
- data/lib/rigor/inference/builtins/string_catalog.rb +1 -1
- data/lib/rigor/inference/captured_locals.rb +389 -18
- data/lib/rigor/inference/closure_escape_analyzer.rb +159 -17
- data/lib/rigor/inference/content_join.rb +200 -27
- data/lib/rigor/inference/coverage_scanner.rb +4 -6
- data/lib/rigor/inference/def_return_typer.rb +11 -7
- data/lib/rigor/inference/define_method_block_self.rb +64 -0
- data/lib/rigor/inference/dynamic_origin.rb +1 -1
- data/lib/rigor/inference/element_read_widening.rb +180 -0
- data/lib/rigor/inference/error_info.rb +196 -0
- data/lib/rigor/inference/expression_typer.rb +2124 -468
- data/lib/rigor/inference/external_ancestor_resolution.rb +267 -0
- data/lib/rigor/inference/fork_map.rb +5 -7
- data/lib/rigor/inference/fresh_frame_blocks.rb +127 -0
- data/lib/rigor/inference/global_write_census.rb +239 -0
- data/lib/rigor/inference/guard_rebinding.rb +447 -0
- data/lib/rigor/inference/hash_lookup_mutation.rb +88 -0
- data/lib/rigor/inference/hkt_reducer.rb +2 -3
- data/lib/rigor/inference/hkt_registry.rb +4 -7
- data/lib/rigor/inference/index_write_widening.rb +16 -7
- data/lib/rigor/inference/indexed_narrowing.rb +61 -9
- data/lib/rigor/inference/jump_targets.rb +82 -0
- data/lib/rigor/inference/last_line/implicit_self.rb +210 -0
- data/lib/rigor/inference/last_line/self_evidence.rb +329 -0
- data/lib/rigor/inference/last_line.rb +340 -0
- data/lib/rigor/inference/last_status.rb +144 -0
- data/lib/rigor/inference/macro_block_self_type.rb +168 -21
- data/lib/rigor/inference/match_rebinding/calls.rb +281 -0
- data/lib/rigor/inference/match_rebinding/frame.rb +148 -0
- data/lib/rigor/inference/match_rebinding/operands.rb +236 -0
- data/lib/rigor/inference/match_rebinding/self_calls.rb +83 -0
- data/lib/rigor/inference/match_rebinding.rb +392 -0
- data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +36 -0
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +87 -33
- data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +305 -19
- data/lib/rigor/inference/method_dispatcher/data_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/facet_distribution.rb +147 -0
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/hash_transform_keys_folding.rb +191 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +6 -2
- data/lib/rigor/inference/method_dispatcher/json_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +7 -1
- data/lib/rigor/inference/method_dispatcher/match_data_folding.rb +159 -0
- data/lib/rigor/inference/method_dispatcher/math_folding.rb +41 -3
- data/lib/rigor/inference/method_dispatcher/method_folding.rb +2 -5
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +165 -111
- data/lib/rigor/inference/method_dispatcher/process_folding.rb +56 -0
- data/lib/rigor/inference/method_dispatcher/proven_overload.rb +72 -0
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +82 -0
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +1046 -69
- data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +25 -4
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +2 -8
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/self_substitute.rb +142 -0
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +129 -54
- data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +1 -2
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +5 -6
- data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +85 -4
- data/lib/rigor/inference/method_dispatcher/time_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/universal_object_dispatch.rb +1 -2
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher.rb +225 -25
- data/lib/rigor/inference/method_parameter_binder.rb +12 -9
- data/lib/rigor/inference/multi_target_binder.rb +341 -55
- data/lib/rigor/inference/mutation_rejoin.rb +171 -0
- data/lib/rigor/inference/mutation_widening.rb +156 -85
- data/lib/rigor/inference/narrowing.rb +835 -162
- data/lib/rigor/inference/operand_effects.rb +167 -0
- data/lib/rigor/inference/operand_walk.rb +88 -0
- data/lib/rigor/inference/optimistic_origin.rb +153 -16
- data/lib/rigor/inference/origin_lookup.rb +2 -3
- data/lib/rigor/inference/parameter_inference_collector.rb +7 -7
- data/lib/rigor/inference/pre_eval_constants.rb +6 -5
- data/lib/rigor/inference/precision_scanner.rb +3 -4
- data/lib/rigor/inference/project_method_ownership.rb +136 -0
- data/lib/rigor/inference/project_patched_methods.rb +9 -4
- data/lib/rigor/inference/project_patched_scanner.rb +10 -6
- data/lib/rigor/inference/protection_scanner.rb +1 -2
- data/lib/rigor/inference/range_constant.rb +57 -0
- data/lib/rigor/inference/rbs_type_translator.rb +49 -11
- data/lib/rigor/inference/receiver_alias.rb +93 -4
- data/lib/rigor/inference/receiver_blind_block.rb +219 -0
- data/lib/rigor/inference/refinement_mutation.rb +76 -0
- data/lib/rigor/inference/repeated_or_writes.rb +463 -0
- data/lib/rigor/inference/return_barrier.rb +54 -0
- data/lib/rigor/inference/rewrite_mutation.rb +120 -0
- data/lib/rigor/inference/scope_indexer.rb +5228 -627
- data/lib/rigor/inference/statement_evaluator.rb +3452 -595
- data/lib/rigor/inference/stored_block_call.rb +54 -0
- data/lib/rigor/inference/string_mutation.rb +97 -0
- data/lib/rigor/inference/struct_fold_safety.rb +6 -7
- data/lib/rigor/inference/synthetic_method_index.rb +1 -2
- data/lib/rigor/inference/synthetic_method_scanner.rb +4 -6
- data/lib/rigor/inference/unknown_store_widening.rb +200 -0
- data/lib/rigor/inference/unthreaded_rebinds.rb +282 -0
- data/lib/rigor/inference/version_guard.rb +28 -21
- data/lib/rigor/inference/void_origin.rb +3 -3
- data/lib/rigor/inference/void_tail_summary.rb +2 -4
- data/lib/rigor/language_server/buffer_table.rb +4 -4
- data/lib/rigor/language_server/completion_provider.rb +1 -1
- data/lib/rigor/language_server/debouncer.rb +0 -1
- data/lib/rigor/language_server/diagnostic_publisher.rb +7 -6
- data/lib/rigor/language_server/document_symbol_provider.rb +1 -1
- data/lib/rigor/language_server/folding_range_provider.rb +1 -1
- data/lib/rigor/language_server/hover_provider.rb +1 -1
- data/lib/rigor/language_server/hover_renderer.rb +4 -4
- data/lib/rigor/language_server/incremental_sync.rb +6 -6
- data/lib/rigor/language_server/project_context.rb +7 -8
- data/lib/rigor/language_server/publish_batcher.rb +2 -2
- data/lib/rigor/language_server/selection_range_provider.rb +2 -2
- data/lib/rigor/language_server/server.rb +9 -9
- data/lib/rigor/language_server/signature_help_provider.rb +1 -1
- data/lib/rigor/language_server/uri.rb +1 -1
- data/lib/rigor/mcp/server.rb +2 -1
- data/lib/rigor/plugin/base.rb +258 -26
- data/lib/rigor/plugin/box_probe.rb +91 -0
- data/lib/rigor/plugin/bundled_catalog.rb +167 -0
- data/lib/rigor/plugin/effect_attribution.rb +65 -11
- data/lib/rigor/plugin/effect_entry_points.rb +3 -3
- data/lib/rigor/plugin/fact_store.rb +6 -6
- data/lib/rigor/plugin/io_boundary.rb +93 -8
- data/lib/rigor/plugin/isolation.rb +29 -6
- data/lib/rigor/plugin/loader.rb +33 -13
- data/lib/rigor/plugin/macro/block_as_method.rb +45 -6
- data/lib/rigor/plugin/macro/heredoc_template.rb +1 -1
- data/lib/rigor/plugin/macro/trait_registry.rb +1 -1
- data/lib/rigor/plugin/manifest.rb +94 -11
- data/lib/rigor/plugin/registry.rb +76 -12
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +21 -4
- data/lib/rigor/plugin/template_unit.rb +196 -0
- data/lib/rigor/plugin/trust_policy.rb +2 -4
- data/lib/rigor/plugin/type_node_resolver.rb +3 -3
- data/lib/rigor/plugin.rb +1 -0
- data/lib/rigor/plugin_gap_advisory.rb +96 -0
- data/lib/rigor/project_environment.rb +138 -0
- data/lib/rigor/protection/analysis_guard.rb +93 -14
- data/lib/rigor/protection/closure_kill_oracle.rb +67 -23
- data/lib/rigor/protection/dependency_closure.rb +5 -8
- data/lib/rigor/protection/diagnostic_oracle.rb +2 -2
- data/lib/rigor/protection/discovery_seed.rb +14 -12
- data/lib/rigor/protection/kill_signature.rb +1 -4
- data/lib/rigor/protection/measurement_integrity.rb +1 -3
- data/lib/rigor/protection/mutation_cache.rb +7 -11
- data/lib/rigor/protection/mutation_scanner.rb +12 -15
- data/lib/rigor/protection/mutator.rb +2 -1
- data/lib/rigor/protection/test_suite_oracle.rb +5 -5
- data/lib/rigor/rbs_extended/conformance_checker.rb +4 -3
- data/lib/rigor/rbs_extended/envelope_scanner.rb +4 -6
- data/lib/rigor/rbs_extended/reporter.rb +36 -10
- data/lib/rigor/rbs_extended.rb +88 -21
- data/lib/rigor/reflection/constant_ancestors.rb +97 -0
- data/lib/rigor/reflection/constant_path.rb +139 -0
- data/lib/rigor/reflection.rb +93 -110
- data/lib/rigor/runtime/jit.rb +6 -8
- data/lib/rigor/scope/discovery_index.rb +165 -2
- data/lib/rigor/scope.rb +1041 -32
- data/lib/rigor/sig_gen/alias_index.rb +289 -0
- data/lib/rigor/sig_gen/classification.rb +22 -5
- data/lib/rigor/sig_gen/declaration_equivalence.rb +127 -0
- data/lib/rigor/sig_gen/effect_annotation.rb +202 -0
- data/lib/rigor/sig_gen/generator.rb +673 -53
- data/lib/rigor/sig_gen/inline_declarations.rb +184 -0
- data/lib/rigor/sig_gen/layout_index.rb +3 -4
- data/lib/rigor/sig_gen/meta_class_shape.rb +3 -5
- data/lib/rigor/sig_gen/method_candidate.rb +47 -3
- data/lib/rigor/sig_gen/observation_collector.rb +18 -16
- data/lib/rigor/sig_gen/path_mapper.rb +4 -6
- data/lib/rigor/sig_gen/rbs_validity.rb +4 -4
- data/lib/rigor/sig_gen/renderer.rb +128 -14
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +154 -0
- data/lib/rigor/sig_gen/superclass_spelling.rb +27 -0
- data/lib/rigor/sig_gen/type_elaborator.rb +1 -3
- data/lib/rigor/sig_gen/write_result.rb +19 -3
- data/lib/rigor/sig_gen/writer.rb +189 -41
- data/lib/rigor/sig_gen.rb +3 -0
- data/lib/rigor/signature_path_audit.rb +153 -6
- data/lib/rigor/source/literals.rb +0 -23
- data/lib/rigor/source/node_children.rb +0 -2
- data/lib/rigor/source/node_locator.rb +5 -11
- data/lib/rigor/source/node_walker.rb +0 -6
- data/lib/rigor/source/parameter_envelope.rb +72 -0
- data/lib/rigor/source.rb +1 -0
- data/lib/rigor/triage/catalogue.rb +1 -3
- data/lib/rigor/triage.rb +3 -5
- data/lib/rigor/type/accepts_result.rb +24 -6
- data/lib/rigor/type/combinator.rb +144 -5
- data/lib/rigor/type/data_class.rb +2 -2
- data/lib/rigor/type/data_instance.rb +4 -4
- data/lib/rigor/type/difference.rb +1 -0
- data/lib/rigor/type/float_range.rb +128 -0
- data/lib/rigor/type/hash_shape.rb +6 -6
- data/lib/rigor/type/integer_range.rb +13 -8
- data/lib/rigor/type/nominal.rb +8 -2
- data/lib/rigor/type/refined.rb +4 -3
- data/lib/rigor/type/struct_class.rb +3 -3
- data/lib/rigor/type/struct_instance.rb +4 -4
- data/lib/rigor/type.rb +1 -0
- data/lib/rigor/type_node/generic.rb +1 -1
- data/lib/rigor/type_node/range_literal.rb +25 -0
- data/lib/rigor/type_node/resolver_chain.rb +1 -1
- data/lib/rigor/type_node.rb +1 -0
- data/lib/rigor/version.rb +1 -1
- data/lib/rigor.rb +1 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +0 -4
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +0 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +0 -2
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/effects.rb +1 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +10 -5
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +0 -4
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +3 -5
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +1 -4
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +14 -4
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +32 -30
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +0 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +1 -3
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_scan.rb +96 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/effects.rb +65 -8
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/erb_compiler.rb +270 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/render_locals.rb +402 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +370 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_units.rb +132 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +264 -3
- data/plugins/rigor-actionpack/sig/action_controller.rbs +71 -0
- data/plugins/rigor-actionpack/sig/action_view.rbs +43 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_discoverer.rb +220 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_index.rb +56 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers.rb +263 -0
- data/plugins/rigor-active-model-serializers/lib/rigor-active-model-serializers.rb +7 -0
- data/plugins/rigor-active-model-serializers/sig/active_model_serializers.rbs +45 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +0 -4
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +2 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +0 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +0 -2
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/recurring_scan.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +10 -5
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +35 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/effects.rb +72 -12
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +383 -7
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +14 -6
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +1 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +1 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +322 -41
- data/plugins/rigor-activerecord/sig/active_record/framework.rbs +123 -0
- data/plugins/rigor-activerecord/sig/active_record/relation.rbs +206 -31
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +26 -14
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +9 -2
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +9 -2
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +290 -19
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +1 -0
- data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +3 -0
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +9 -7
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +7 -3
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +1 -0
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +8 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +11 -7
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -11
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +9 -4
- data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +2 -0
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +0 -5
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +8 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/types.rb +1 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +36 -4
- data/plugins/rigor-ffi-rzmq/lib/rigor/plugin/ffi_rzmq.rb +1 -0
- data/plugins/rigor-grape/lib/rigor/plugin/grape.rb +141 -0
- data/plugins/rigor-grape/lib/rigor-grape.rb +6 -0
- data/plugins/rigor-grape/sig/grape.rbs +263 -0
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +8 -6
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +78 -5
- data/plugins/rigor-graphql/sig/graphql.rbs +485 -0
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +1 -0
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +2 -1
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +2 -3
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +1 -0
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +0 -5
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/authorization_scan.rb +2 -2
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +0 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +0 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +12 -7
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +0 -12
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +1 -3
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +0 -1
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +36 -37
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/acronyms.rb +5 -5
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +0 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +5 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +3 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/grape_api_discoverer.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +9 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +2 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +10 -17
- data/plugins/rigor-railties/lib/rigor/plugin/railties.rb +1 -0
- data/plugins/rigor-rbnacl/lib/rigor/plugin/rbnacl.rb +13 -1
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline/same_line_annotations.rb +149 -0
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +324 -18
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +0 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +0 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +1 -5
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +2 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +1 -0
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +0 -3
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +1 -0
- data/plugins/rigor-sassc/lib/rigor/plugin/sassc.rb +1 -0
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +1 -9
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +1 -0
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +0 -4
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/effects.rb +1 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/schedule_scan.rb +2 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +0 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +0 -2
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +10 -5
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +1 -0
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +2 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +1 -4
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +3 -9
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +4 -4
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +1 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +3 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +7 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +51 -6
- data/plugins/rigor-sorbet/sig/sorbet.rbs +277 -0
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +1 -0
- data/sig/rigor/analysis/baseline.rbs +69 -7
- data/sig/rigor/analysis/fact_store.rbs +1 -1
- data/sig/rigor/analysis/project_scan.rbs +74 -0
- data/sig/rigor/analysis/reachability/scan_cache.rbs +12 -0
- data/sig/rigor/cache.rbs +2 -3
- data/sig/rigor/effects/config_envelopes.rbs +100 -0
- data/sig/rigor/effects/effect_table.rbs +60 -0
- data/sig/rigor/effects/envelope.rbs +97 -0
- data/sig/rigor/effects/envelope_index.rbs +33 -0
- data/sig/rigor/effects/file_collection.rbs +81 -0
- data/sig/rigor/effects/label.rbs +26 -0
- data/sig/rigor/effects/label_set.rbs +46 -0
- data/sig/rigor/effects/method_key.rbs +24 -0
- data/sig/rigor/effects/origin.rbs +50 -0
- data/sig/rigor/effects/plugin_facts.rbs +141 -0
- data/sig/rigor/effects/registry.rbs +68 -0
- data/sig/rigor/effects/summary.rbs +50 -0
- data/sig/rigor/effects/taint_cause.rbs +12 -0
- data/sig/rigor/environment.rbs +17 -10
- data/sig/rigor/inference/optimistic_origin.rbs +10 -0
- data/sig/rigor/inference.rbs +9 -14
- data/sig/rigor/plugin/additional_initializer.rbs +36 -0
- data/sig/rigor/plugin/base.rbs +30 -7
- data/sig/rigor/plugin/effect_ancestry.rbs +27 -0
- data/sig/rigor/plugin/effect_attribution.rbs +66 -0
- data/sig/rigor/plugin/effect_edge.rbs +33 -0
- data/sig/rigor/plugin/effect_entry_points.rbs +25 -0
- data/sig/rigor/plugin/io_boundary.rbs +4 -0
- data/sig/rigor/plugin/loader.rbs +3 -3
- data/sig/rigor/plugin/manifest.rbs +51 -11
- data/sig/rigor/plugin/protocol_contract.rbs +68 -0
- data/sig/rigor/plugin/registry.rbs +62 -1
- data/sig/rigor/plugin.rbs +1 -1
- data/sig/rigor/rbs_extended.rbs +1 -1
- data/sig/rigor/reflection.rbs +9 -6
- data/sig/rigor/scope.rbs +148 -12
- data/sig/rigor/sig_gen/skip_reason_catalog.rbs +21 -0
- data/sig/rigor/source.rbs +4 -4
- data/sig/rigor/testing.rbs +10 -4
- data/sig/rigor/type.rbs +33 -1
- data/sig/rigor.rbs +39 -20
- data/skills/rigor-ask/SKILL.md +16 -11
- data/skills/rigor-baseline-reduce/SKILL.md +4 -6
- data/skills/rigor-ci-setup/SKILL.md +17 -21
- data/skills/rigor-doctor/SKILL.md +24 -22
- data/skills/rigor-doctor/references/01-checks.md +97 -33
- data/skills/rigor-editor-setup/SKILL.md +6 -4
- data/skills/rigor-mcp-setup/SKILL.md +5 -4
- data/skills/rigor-monkeypatch-resolve/SKILL.md +5 -3
- data/skills/rigor-next-steps/SKILL.md +4 -2
- data/skills/rigor-plugin-author/SKILL.md +19 -23
- data/skills/rigor-plugin-author/references/01-plan-and-scaffold.md +9 -8
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +25 -27
- data/skills/rigor-plugin-author/references/03-test-and-ship.md +6 -8
- data/skills/rigor-plugin-review/SKILL.md +6 -4
- data/skills/rigor-plugin-review/references/01-best-practices-checklist.md +2 -1
- data/skills/rigor-plugin-tune/SKILL.md +4 -2
- data/skills/rigor-project-init/SKILL.md +15 -10
- data/skills/rigor-project-init/references/01-detect.md +13 -9
- data/skills/rigor-project-init/references/02-configure.md +43 -14
- data/skills/rigor-project-init/references/03-baseline-and-bugs.md +14 -14
- data/skills/rigor-project-init/references/04-sig-uplift.md +27 -14
- data/skills/rigor-project-init/references/06-agent-contract.md +67 -0
- data/skills/rigor-protection-uplift/SKILL.md +4 -6
- data/skills/rigor-rbs-setup/SKILL.md +4 -2
- data/skills/rigor-type-oracle/SKILL.md +226 -0
- data/skills/rigor-type-oracle/references/01-oracle-commands.md +265 -0
- data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +52 -0
- data/skills/rigor-type-oracle/references/03-gap-protocol.md +125 -0
- data/skills/rigor-unused-adjudicate/SKILL.md +12 -7
- data/skills/rigor-upgrade/SKILL.md +13 -8
- metadata +133 -3
- data/lib/rigor/cli/probe_environment.rb +0 -85
- data/sig/rigor/inference/builtins/numeric_catalog.rbs +0 -3
|
@@ -87,12 +87,13 @@ module Rigor
|
|
|
87
87
|
# user — every rule fired — but NOT a valid measurement of Rigor itself, so a harness that scores
|
|
88
88
|
# Rigor's behaviour should treat one of these as a crash finding the way it treats `:check_rule`, or
|
|
89
89
|
# a mutant that re-breaks the HKT scan (#776 was one) scores as a measurement over a silently degraded
|
|
90
|
-
# universe.
|
|
91
|
-
#
|
|
92
|
-
#
|
|
93
|
-
#
|
|
94
|
-
# the
|
|
95
|
-
# and
|
|
90
|
+
# universe. Both Rigor-measuring harnesses consult it (#790): `tool/mutation`'s fuzz crash detector
|
|
91
|
+
# and {Protection::AnalysisGuard}, the ADR-69 kill oracles' refusal. Neither reads it alone — the row
|
|
92
|
+
# is severity-stamped like any other, so `severity_overrides:` can drop it from a run's diagnostics
|
|
93
|
+
# entirely, and each harness also reads {Rigor::Environment#hkt_scan_failure}, the pre-severity record
|
|
94
|
+
# the row is derived from. Both also replace their Environment after a defect: the registry build is
|
|
95
|
+
# memoised and the failure slot is first-write-wins, so an Environment that degraded once stays
|
|
96
|
+
# degraded for every later mutant.
|
|
96
97
|
ANALYZER_DEFECT_RULES = %w[
|
|
97
98
|
rbs.coverage.hkt-scan-failed
|
|
98
99
|
].freeze
|
|
@@ -103,9 +104,6 @@ module Rigor
|
|
|
103
104
|
# into. Built here, not at either rescue site, so the two twins cannot drift (issue #665) — and so
|
|
104
105
|
# the appended crash frame is derived identically on the sequential and pooled paths. Keeps the
|
|
105
106
|
# {CHECK_RULE_MESSAGE_PREFIX} prefix every consumer matches on; the frame is a trailing hint.
|
|
106
|
-
#
|
|
107
|
-
# @param error [StandardError]
|
|
108
|
-
# @return [String]
|
|
109
107
|
def check_rule_message(error)
|
|
110
108
|
base = "#{CHECK_RULE_MESSAGE_PREFIX}: #{error.class}: #{error.message}"
|
|
111
109
|
frame = crash_frame(error)
|
|
@@ -117,9 +115,6 @@ module Rigor
|
|
|
117
115
|
# bundled or third-party plugin also lives under `lib/rigor/<plugin>/`, so a frame here says where
|
|
118
116
|
# the raise was, never whose defect it is. Falls back to the raw top frame when the crash is entirely
|
|
119
117
|
# inside a dependency, and to nil when there is no backtrace at all.
|
|
120
|
-
#
|
|
121
|
-
# @param error [Exception]
|
|
122
|
-
# @return [String, nil]
|
|
123
118
|
def crash_frame(error)
|
|
124
119
|
frames = error.backtrace
|
|
125
120
|
return nil if frames.nil? || frames.empty?
|
|
@@ -132,15 +127,11 @@ module Rigor
|
|
|
132
127
|
# (the fork pool) rather than deriving it fresh from a live `Exception` — can relativize the frame it
|
|
133
128
|
# already has without re-deriving `.crash_frame`'s "which frame" choice. Nil-safe, and a no-op (`sub`
|
|
134
129
|
# never matches) on a frame with no `lib/rigor/` segment at all.
|
|
135
|
-
#
|
|
136
|
-
# @param frame [String, nil]
|
|
137
|
-
# @return [String, nil]
|
|
138
130
|
def relativize_frame(frame)
|
|
139
131
|
frame&.sub(%r{\A.*/(lib/rigor/)}, '\1')
|
|
140
132
|
end
|
|
141
133
|
|
|
142
|
-
# @
|
|
143
|
-
# @return [Symbol, nil] `:check_rule`, `:plugin`, `:rbs_build`, or nil for an ordinary diagnostic.
|
|
134
|
+
# @return `:check_rule`, `:plugin`, `:rbs_build`, or nil for an ordinary diagnostic.
|
|
144
135
|
def reason(diagnostic)
|
|
145
136
|
return :check_rule if diagnostic.message.to_s.start_with?(CHECK_RULE_MESSAGE_PREFIX)
|
|
146
137
|
return :plugin if plugin_isolation_row?(diagnostic)
|
|
@@ -152,8 +143,6 @@ module Rigor
|
|
|
152
143
|
# True when `diagnostic` is the rescue row that REPLACED a file's analysis — the only shape after which
|
|
153
144
|
# the run's diagnostics say nothing about the code. NOT a general "something went wrong" predicate; see
|
|
154
145
|
# the class doc for why `:plugin` and `:rbs_build` are excluded.
|
|
155
|
-
#
|
|
156
|
-
# @param diagnostic [Rigor::Analysis::Diagnostic]
|
|
157
146
|
def discards_file_analysis?(diagnostic)
|
|
158
147
|
reason(diagnostic) == DISCARDS_FILE_ANALYSIS_REASON
|
|
159
148
|
end
|
|
@@ -162,17 +151,12 @@ module Rigor
|
|
|
162
151
|
# measurement of Rigor — see {ANALYZER_DEFECT_RULES}. Orthogonal to {.discards_file_analysis?}: the
|
|
163
152
|
# user-facing tier reads the run; the Rigor-measuring tier should refuse it (the mutation fuzz does,
|
|
164
153
|
# the ADR-69 kill oracle does not yet — #790).
|
|
165
|
-
#
|
|
166
|
-
# @param diagnostic [Rigor::Analysis::Diagnostic]
|
|
167
154
|
def analyzer_defect?(diagnostic)
|
|
168
155
|
ANALYZER_DEFECT_RULES.include?(diagnostic.rule)
|
|
169
156
|
end
|
|
170
157
|
|
|
171
158
|
# A one-line "<reason> at <path>:<line>: <message>" for a failure message, so whoever reads the raise
|
|
172
159
|
# sees which shape fired and where without re-deriving it.
|
|
173
|
-
#
|
|
174
|
-
# @param diagnostic [Rigor::Analysis::Diagnostic]
|
|
175
|
-
# @return [String]
|
|
176
160
|
def describe(diagnostic)
|
|
177
161
|
"#{reason(diagnostic) || :unknown} at #{diagnostic.path}:#{diagnostic.line}: #{diagnostic.message}"
|
|
178
162
|
end
|
|
@@ -126,6 +126,29 @@ module Rigor
|
|
|
126
126
|
[result, capture.snapshot]
|
|
127
127
|
end
|
|
128
128
|
|
|
129
|
+
# Issue #992 — runs the block with its reads DETACHED from the current consumer (and from any enclosing
|
|
130
|
+
# capture) and returns `[block_result, read_set]`, so a caller that learns only afterwards whether its
|
|
131
|
+
# answer depended on those reads can {replay} them or drop them. `call.wrong-arity` reads a class's whole
|
|
132
|
+
# envelope bucket to decide a call that turns out to fit, and recording that as a file-level ancestry
|
|
133
|
+
# edge would make every correct call on a project class re-check on any edit to the class's files.
|
|
134
|
+
# Returns a nil read set when no recording is active.
|
|
135
|
+
def withhold
|
|
136
|
+
previous = Thread.current[KEY]
|
|
137
|
+
return [yield, nil] if previous.nil?
|
|
138
|
+
|
|
139
|
+
previous_captures = Thread.current[CAPTURE_KEY]
|
|
140
|
+
capture = Capture.new
|
|
141
|
+
Thread.current[KEY] = Accumulator.new(previous.consumer)
|
|
142
|
+
Thread.current[CAPTURE_KEY] = [capture]
|
|
143
|
+
begin
|
|
144
|
+
result = yield
|
|
145
|
+
ensure
|
|
146
|
+
Thread.current[KEY] = previous
|
|
147
|
+
Thread.current[CAPTURE_KEY] = previous_captures
|
|
148
|
+
end
|
|
149
|
+
[result, capture.snapshot]
|
|
150
|
+
end
|
|
151
|
+
|
|
129
152
|
# ADR-84 WD2 — replays a {ReadSet} into the current consumer's accumulator as if each read happened
|
|
130
153
|
# here, applying the same per-consumer self-read filter as {read_site}, and tees into every active
|
|
131
154
|
# capture so an enclosing capture window stays transitive when a memo hit substitutes for a body walk.
|
|
@@ -25,7 +25,7 @@ module Rigor
|
|
|
25
25
|
@mutex = Mutex.new
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
# @return
|
|
28
|
+
# @return frozen snapshot of the recorded boundary-cross events. Each entry is a Data
|
|
29
29
|
# with `class_name` (String), `method_name` (Symbol), `gem_name` (String), and `rbs_display` (String
|
|
30
30
|
# — the authoritative-side type's human-facing form, embedded into the diagnostic message).
|
|
31
31
|
def entries
|
|
@@ -30,8 +30,6 @@ module Rigor
|
|
|
30
30
|
|
|
31
31
|
module_function
|
|
32
32
|
|
|
33
|
-
# @param entry [Rigor::Configuration::Dependencies::Entry]
|
|
34
|
-
# @return [Resolved, Unresolvable]
|
|
35
33
|
def resolve(entry)
|
|
36
34
|
spec = locate_gem_spec(entry.gem)
|
|
37
35
|
return Unresolvable.new(gem_name: entry.gem, reason: :not_in_bundle) if spec.nil?
|
|
@@ -13,19 +13,19 @@ module Rigor
|
|
|
13
13
|
attr_reader :resolved_gems, :unresolvable, :method_catalog, :budget_exceeded,
|
|
14
14
|
:class_to_gem, :budget_overrun_strategy, :gem_modes
|
|
15
15
|
|
|
16
|
-
# @param method_catalog
|
|
16
|
+
# @param method_catalog — => Symbol}] the flat
|
|
17
17
|
# `(class_name, method_name) → :instance | :singleton` table produced by {Walker.walk}, aggregated
|
|
18
18
|
# across every resolved gem in the run. The Index itself stays gem-agnostic — the per-gem
|
|
19
19
|
# attribution that slice 3's cache descriptor needs lives on `Resolved`, not here.
|
|
20
|
-
# @param budget_exceeded
|
|
20
|
+
# @param budget_exceeded — gem names whose {Walker} run hit the per-gem catalog cap
|
|
21
21
|
# (slice 4). The Runner consumes this list to emit one `dynamic.dependency-source.budget-exceeded`
|
|
22
22
|
# warning per gem.
|
|
23
|
-
# @param class_to_gem
|
|
23
|
+
# @param class_to_gem — reverse lookup `class_name → gem_name` (slice 5b). Built
|
|
24
24
|
# first-write-wins: when two opt-in gems re-open the same class, the first gem owns it. The
|
|
25
25
|
# dispatcher consults this map under the `:dependency_silence` budget overrun strategy so call
|
|
26
26
|
# sites on a budget-exceeded gem's classes degrade to `Dynamic[top]` instead of falling through to
|
|
27
27
|
# the user-class fallback.
|
|
28
|
-
# @param gem_modes
|
|
28
|
+
# @param gem_modes — per-gem mode table (`gem_name → :disabled | :when_missing |
|
|
29
29
|
# :full`). ADR-10 slice 5c consults this through {#mode_for} to identify call sites where
|
|
30
30
|
# gem-source and RBS both contribute under `mode: :full`. The map is keyed on `gem_name` (not
|
|
31
31
|
# class) because re-opened classes belong to the first gem they appeared in per `class_to_gem`;
|
|
@@ -56,7 +56,7 @@ module Rigor
|
|
|
56
56
|
end
|
|
57
57
|
private :normalize_catalog
|
|
58
58
|
|
|
59
|
-
# @return
|
|
59
|
+
# @return the gem that owns `class_name` (first-write-wins); `nil` when the class isn't
|
|
60
60
|
# in any opt-in gem's catalog.
|
|
61
61
|
def gem_for(class_name)
|
|
62
62
|
@class_to_gem[class_name]
|
|
@@ -28,8 +28,7 @@ module Rigor
|
|
|
28
28
|
module ReturnTypeHeuristic
|
|
29
29
|
module_function
|
|
30
30
|
|
|
31
|
-
# @
|
|
32
|
-
# @return [Rigor::Type, nil] heuristic return type, or `nil` when the body's tail expression doesn't
|
|
31
|
+
# @return heuristic return type, or `nil` when the body's tail expression doesn't
|
|
33
32
|
# match any of the recognised shapes.
|
|
34
33
|
def extract(def_node)
|
|
35
34
|
body = def_node.body
|
|
@@ -55,12 +55,12 @@ module Rigor
|
|
|
55
55
|
|
|
56
56
|
module_function
|
|
57
57
|
|
|
58
|
-
# @param gem_dir
|
|
59
|
-
# @param roots
|
|
58
|
+
# @param gem_dir — absolute path to the gem's installation directory.
|
|
59
|
+
# @param roots — subdirectory names within the gem to walk (defaults to `["lib"]` per
|
|
60
60
|
# `Configuration::Dependencies::Entry`).
|
|
61
|
-
# @param budget
|
|
61
|
+
# @param budget — per-gem catalog cap (method-definition count). When unset, defaults
|
|
62
62
|
# to `UNBOUNDED` for backwards-compatible test paths.
|
|
63
|
-
# @return
|
|
63
|
+
# @return frozen wrapper carrying the catalog (`Hash{[class_name, method_name] =>
|
|
64
64
|
# :instance | :singleton}`) and a `truncated?` flag set when the walker stopped harvesting because
|
|
65
65
|
# the budget was reached. Methods of identical name on the same class with different kinds (rare;
|
|
66
66
|
# private API mostly) carry the kind that wins the per-class first walk.
|
|
@@ -52,17 +52,16 @@ module Rigor
|
|
|
52
52
|
# otherwise rebuild (the probe loaded the plugins to key the entry, so it already knows it).
|
|
53
53
|
Served = Data.define(:table, :sources, :registry, :plugin_facts)
|
|
54
54
|
|
|
55
|
-
# @param configuration
|
|
56
|
-
# @param cache_root [String, nil]
|
|
55
|
+
# @param configuration — with effects already enabled by the caller.
|
|
57
56
|
def initialize(configuration:, cache_root:)
|
|
58
57
|
@configuration = configuration
|
|
59
58
|
@cache_root = cache_root
|
|
60
59
|
end
|
|
61
60
|
|
|
62
|
-
# @param paths
|
|
61
|
+
# @param paths — the analysed set — `configuration.paths` unioned with any path
|
|
63
62
|
# arguments, exactly what {CLI::EffectsCommand#analyze} hands the runner, because the analysed
|
|
64
63
|
# set is part of the diagnostics key.
|
|
65
|
-
# @return
|
|
64
|
+
# @return nil to decline, on any failure whatsoever.
|
|
66
65
|
def serve(paths)
|
|
67
66
|
return nil if @cache_root.nil? || !@configuration.effects_check?
|
|
68
67
|
|
|
@@ -19,8 +19,7 @@ module Rigor
|
|
|
19
19
|
|
|
20
20
|
module_function
|
|
21
21
|
|
|
22
|
-
# @
|
|
23
|
-
# @return [Boolean] true when the parsed source looks like an ERB template (parse errors expected;
|
|
22
|
+
# @return true when the parsed source looks like an ERB template (parse errors expected;
|
|
24
23
|
# analysis should skip).
|
|
25
24
|
def template?(parse_result)
|
|
26
25
|
source = parse_result.source.source
|
|
@@ -18,9 +18,23 @@ module Rigor
|
|
|
18
18
|
].freeze
|
|
19
19
|
|
|
20
20
|
class Target < Data.define(:kind, :name)
|
|
21
|
+
# #775 — a target is an immutable value keyed by its name, and the local target is built on every
|
|
22
|
+
# binding (`Scope#with_local` invalidates through it) and every local-fact read: ~350k times on
|
|
23
|
+
# the lib self-check for a few thousand distinct names. One shared instance per name.
|
|
24
|
+
#
|
|
25
|
+
# #1055 — the table is a class ivar holding an unshareable Hash, and a non-main Ractor may neither
|
|
26
|
+
# write one nor read one. A pool worker therefore pays the allocation instead of sharing the
|
|
27
|
+
# instance: the interning is a per-process ALLOCATION saving, never an identity contract (`Target`
|
|
28
|
+
# is a `Data` value and compares by value), so declining it changes nothing a caller can observe.
|
|
29
|
+
# The guard is a C-level predicate on the hot path, which is what keeps the sequential run's
|
|
30
|
+
# saving intact.
|
|
21
31
|
def self.local(name)
|
|
22
|
-
|
|
32
|
+
name = name.to_sym
|
|
33
|
+
return new(kind: :local, name: name) unless Ractor.main?
|
|
34
|
+
|
|
35
|
+
@local_targets[name] ||= new(kind: :local, name: name)
|
|
23
36
|
end
|
|
37
|
+
@local_targets = {}
|
|
24
38
|
|
|
25
39
|
def initialize(kind:, name:)
|
|
26
40
|
super(kind: kind.to_sym, name: name)
|
|
@@ -120,6 +120,48 @@ module Rigor
|
|
|
120
120
|
appeared.freeze
|
|
121
121
|
end
|
|
122
122
|
|
|
123
|
+
# Issue #1120 — the method names whose refinements moved in this edit: a `[refined class, method, refining
|
|
124
|
+
# module]` entry that appeared in, or vanished from, any file in `paths`. A consumer whose
|
|
125
|
+
# `call.undefined-method` answer consulted the refinement table recorded a `refinement:<method>` edge
|
|
126
|
+
# whichever way it answered, because the answer is a function of the whole project's refinements of that
|
|
127
|
+
# name. `paths` MUST include removed files, whose whole before-table vanished. `before` / `after` map a
|
|
128
|
+
# path to that file's `{refined class => {method => [modules]}}` table (nil when it refines nothing).
|
|
129
|
+
def changed_refinement_names(paths, before, after)
|
|
130
|
+
moved = Set.new
|
|
131
|
+
paths.each do |path|
|
|
132
|
+
entries_before = refinement_entries(before[path])
|
|
133
|
+
entries_after = refinement_entries(after[path])
|
|
134
|
+
(entries_before ^ entries_after).each { |(_refined, method_name, _module)| moved << method_name }
|
|
135
|
+
end
|
|
136
|
+
moved.freeze
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def refinement_entries(table)
|
|
140
|
+
entries = Set.new
|
|
141
|
+
table&.each do |refined, methods|
|
|
142
|
+
methods.each do |method_name, modules|
|
|
143
|
+
modules.each { |refining| entries << [refined, method_name, refining] }
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
entries
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Issue #639 — the SYMMETRIC reading of {appeared_classes}: the names whose declaration in a file
|
|
150
|
+
# appeared OR VANISHED. Appearance alone answered the miss side, which was the only side recording a
|
|
151
|
+
# `class:` edge; a bare reference that RESOLVED now records one too, and what invalidates it is the
|
|
152
|
+
# declaration going away. `paths` MUST therefore include REMOVED files — a removed file has no
|
|
153
|
+
# after-state, so its whole before-set vanished — which is the same reason
|
|
154
|
+
# {changed_constant_publications} diffs over `changed + removed`.
|
|
155
|
+
def changed_class_declarations(paths, decls_before, decls_after)
|
|
156
|
+
moved = Set.new
|
|
157
|
+
paths.each do |path|
|
|
158
|
+
before = decls_before[path] || Set.new
|
|
159
|
+
after = decls_after[path] || Set.new
|
|
160
|
+
moved.merge(after ^ before)
|
|
161
|
+
end
|
|
162
|
+
moved.freeze
|
|
163
|
+
end
|
|
164
|
+
|
|
123
165
|
# Issue #644 — the qualified constant names whose PUBLICATION could have moved in this edit: the names
|
|
124
166
|
# whose per-file census descriptor differs between the before- and after-state of any file in `paths`.
|
|
125
167
|
# The value-constant twin of {appeared_classes}, and deliberately NOT its analogue — a class either
|
|
@@ -42,22 +42,22 @@ module Rigor
|
|
|
42
42
|
end
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
-
# @param paths
|
|
45
|
+
# @param paths — explicit analysis roots; nil (the default) uses the configuration's
|
|
46
46
|
# `paths:`.
|
|
47
|
-
# @param environment
|
|
47
|
+
# @param environment — optional shared environment to thread into each internal
|
|
48
48
|
# Runner. Long-lived callers and specs can use this to avoid rebuilding the same RBS universe for
|
|
49
49
|
# every baseline / recheck / oracle run.
|
|
50
|
-
# @param cache_store
|
|
50
|
+
# @param cache_store — ADR-85 WD1 — the persistent cache each internal Runner
|
|
51
51
|
# exposes to the RBS-env and plugin-producer tiers. A cross-process `--incremental` recheck otherwise
|
|
52
52
|
# rebuilt a fresh runner with no store, so every plugin `#prepare` producer (the ADR-9/#74/ADR-60 WD3
|
|
53
53
|
# record-and-validate caches) recomputed per invocation — 86% of a Rails warm incremental. Threading
|
|
54
54
|
# the store lets those producers serve from disk. `nil` (the default) preserves the pre-#85 behaviour
|
|
55
55
|
# the specs assert; the whole-run ADR-45 result cache stays disabled on these runs
|
|
56
56
|
# (`Runner#run_result_cacheable?` excludes `record_dependencies` / `analyze_only`).
|
|
57
|
-
# @param plugin_requirer
|
|
57
|
+
# @param plugin_requirer — optional gem-require hook threaded into each internal Runner
|
|
58
58
|
# (mirrors {Runner}'s parameter). nil (the default, and what the CLI passes) uses `Kernel.require`;
|
|
59
59
|
# embedders and specs inject a fake so a test plugin registers without touching the real load path.
|
|
60
|
-
# @param workers
|
|
60
|
+
# @param workers — ADR-46 — the resolved fork-pool worker count threaded into every internal
|
|
61
61
|
# analyzer, so a `--incremental` recheck's closure re-analysis parallelises exactly like the standard
|
|
62
62
|
# `check` path (the recon's audit: `--workers` / `RIGOR_RACTOR_WORKERS` / `parallel.workers:` were
|
|
63
63
|
# silently ignored because `build_runner` passed no `workers:`). 0 (the default, and what the specs and
|
|
@@ -112,7 +112,7 @@ module Rigor
|
|
|
112
112
|
# and a missing invalidation edge is impossible by construction — the reason this is a table diff
|
|
113
113
|
# and not the caller→callee edge recording #204 first sketched.
|
|
114
114
|
@param_table = {}
|
|
115
|
-
|
|
115
|
+
reset_carried_state
|
|
116
116
|
# ADR-88 WD1 — the plugin fact-surface digest computed for THIS invocation (nil until a
|
|
117
117
|
# `#run_incremental` pass runs / a plugin-free project) and the reporting flags a caller (the CLI
|
|
118
118
|
# banner + `--cache-stats`) reads after `#run_incremental`. `@last_runner` is the analysis runner the
|
|
@@ -162,7 +162,11 @@ module Rigor
|
|
|
162
162
|
runner = build_runner(record_dependencies: true)
|
|
163
163
|
diagnostics = run_runner(runner).diagnostics
|
|
164
164
|
@last_runner = runner # ADR-88 WD1 — the post-hoc fact-surface fingerprint reads this prepared registry.
|
|
165
|
-
|
|
165
|
+
# #392 — the template units are deliberately NOT in the analysed set. `Runner#target_files`
|
|
166
|
+
# re-analyses every unit on every run, so a unit must never be reused from the per-file cache and
|
|
167
|
+
# must never read as a file that VANISHED from the project on the next recheck (which is what
|
|
168
|
+
# `previous - current` would say, `current_files` being a `.rb` expansion).
|
|
169
|
+
@analyzed = runner.analyzed_files - runner.template_unit_paths
|
|
166
170
|
@seed_bundles = runner.seed_bundles # ADR-85 WD2 — the freshly built bundle set for the next run.
|
|
167
171
|
absorb_dependency_graph(runner)
|
|
168
172
|
@return_summaries = runner.return_summaries # ADR-89 WD2 — the full-run behavioural surface.
|
|
@@ -174,6 +178,7 @@ module Rigor
|
|
|
174
178
|
@effects_identity = current_effects_identity
|
|
175
179
|
@cache = per_file(runner.per_file_diagnostics)
|
|
176
180
|
@digests = @analyzed.to_h { |path| [path, pack_digest(path)] }
|
|
181
|
+
@run_level_rows = runner.run_level_rows
|
|
177
182
|
diagnostics
|
|
178
183
|
end
|
|
179
184
|
|
|
@@ -197,7 +202,8 @@ module Rigor
|
|
|
197
202
|
# The freshly collected table is handed to the runner so the run seeds from the SAME table the diff
|
|
198
203
|
# was decided on (and the collector runs once per recheck, not twice).
|
|
199
204
|
runner = build_runner(analyze_only: analyze_set, record_dependencies: true,
|
|
200
|
-
param_inferred_types: fresh_params
|
|
205
|
+
param_inferred_types: fresh_params,
|
|
206
|
+
restored_run_level_rows: @run_level_rows)
|
|
201
207
|
fresh = run_runner(runner).diagnostics
|
|
202
208
|
@last_runner = runner # ADR-88 WD1 — the post-hoc fact-surface fingerprint reads this prepared registry.
|
|
203
209
|
reused = (current & previous) - affected.to_a
|
|
@@ -281,12 +287,24 @@ module Rigor
|
|
|
281
287
|
symbol_pairs = behaviourally_unstable_pairs(changed_pairs, unstable, scan_index) | param_pairs
|
|
282
288
|
base = dependents_base(unstable, symbol_pairs)
|
|
283
289
|
closure = base | changed.to_set | added.to_set |
|
|
284
|
-
negative_affected(scan, removed, new_fps, new_class_decls, new_constant_decls)
|
|
290
|
+
negative_affected(scan, removed, new_fps, new_class_decls, new_constant_decls, summary)
|
|
285
291
|
closure = param_seed_closure(closure, param_files)
|
|
286
292
|
removed.each { |path| closure |= @dependents[path] || Set.new }
|
|
287
293
|
closure.freeze
|
|
288
294
|
end
|
|
289
295
|
|
|
296
|
+
# Issue #1367 — every file whose last result holds a `global.*` diagnostic re-checks on any recheck. What
|
|
297
|
+
# exempts such a write is a fact of the whole program — an alias, or a `write` / `to_str` / `to_int` / hatch
|
|
298
|
+
# defined in any spelling on any receiver, a rewritten ancestor, a mixin — which no name-keyed edge can
|
|
299
|
+
# follow, so a stale report would outlive the edit that exempts it. Such files are rare, so this costs little.
|
|
300
|
+
# A file the census silenced is not re-checked when the exemption goes away: that stale answer misses a
|
|
301
|
+
# report, it never makes one.
|
|
302
|
+
def global_write_reporters
|
|
303
|
+
@cache.each_with_object(Set.new) do |(path, diagnostics), reporters|
|
|
304
|
+
reporters << path if diagnostics.any? { |diagnostic| diagnostic.rule.to_s.start_with?("global.") }
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
|
|
290
308
|
# ADR-67 WD6c lift — the seed-invalidated callees' own contribution to the closure: the files
|
|
291
309
|
# themselves, plus — on a pre-slice-4 snapshot with no symbol edges, where the pairs' symbol fan-out
|
|
292
310
|
# found nothing — their file-level dependents (wider, always sound).
|
|
@@ -407,10 +425,13 @@ module Rigor
|
|
|
407
425
|
end
|
|
408
426
|
|
|
409
427
|
# The current project file set (cheap directory expansion, no analysis), used to detect files added /
|
|
410
|
-
# removed since the last run.
|
|
428
|
+
# removed since the last run. Also where an editor buffer's binding is re-spelled onto the set, since
|
|
429
|
+
# this is where the run first learns how it spells its own members.
|
|
411
430
|
def current_files
|
|
412
431
|
runner = build_runner
|
|
413
|
-
@paths ? runner.analysis_file_set(@paths) : runner.analysis_file_set
|
|
432
|
+
files = @paths ? runner.analysis_file_set(@paths) : runner.analysis_file_set
|
|
433
|
+
rebind_buffer(files)
|
|
434
|
+
files
|
|
414
435
|
end
|
|
415
436
|
|
|
416
437
|
# Verification engine (the `--verify-incremental` gate): with NO source edit, re-analyze `subset` fresh
|
|
@@ -422,7 +443,8 @@ module Rigor
|
|
|
422
443
|
affected = subset.to_set
|
|
423
444
|
# ADR-67 WD6c lift — seed the subset run from the baseline's own table so the verification engine
|
|
424
445
|
# exercises the exact seeds the served cache entries were computed under (and skips a re-collect).
|
|
425
|
-
runner = build_runner(analyze_only: affected, param_inferred_types: @param_table
|
|
446
|
+
runner = build_runner(analyze_only: affected, param_inferred_types: @param_table,
|
|
447
|
+
restored_run_level_rows: @run_level_rows)
|
|
426
448
|
fresh = run_runner(runner).diagnostics
|
|
427
449
|
reused = @analyzed - affected.to_a
|
|
428
450
|
fresh + reused.flat_map { |path| @cache[path] || [] }
|
|
@@ -559,6 +581,9 @@ module Rigor
|
|
|
559
581
|
restore_structural_declarations(payload)
|
|
560
582
|
@return_summaries = payload.return_summaries || {}
|
|
561
583
|
@param_table = payload.param_table || {} # ADR-67 WD6c lift — the seeds the cache was built under.
|
|
584
|
+
# Issues #796 / #794 — absent (nil) in a snapshot written before schema 22 is impossible (the SCHEMA
|
|
585
|
+
# gate rejects one), so nil here means the writing run genuinely had nothing to say.
|
|
586
|
+
@run_level_rows = payload.run_level_rows
|
|
562
587
|
# ADR-103 WD13 / #382 — the effects sidecar rides its own identity, so a snapshot whose summaries
|
|
563
588
|
# were collected under a different vocabulary / catalogue / `effects:` block restores as EMPTY
|
|
564
589
|
# rather than as stale rows. {#run_incremental} turns that emptiness into a full baseline, because
|
|
@@ -592,7 +617,8 @@ module Rigor
|
|
|
592
617
|
return_summaries: marshal_safe_return_summaries,
|
|
593
618
|
param_table: marshal_safe_param_table,
|
|
594
619
|
effect_collections: marshal_safe_effect_collections,
|
|
595
|
-
effects_identity: @effects_identity
|
|
620
|
+
effects_identity: @effects_identity,
|
|
621
|
+
run_level_rows: @run_level_rows
|
|
596
622
|
)
|
|
597
623
|
end
|
|
598
624
|
|
|
@@ -606,6 +632,15 @@ module Rigor
|
|
|
606
632
|
@effects_identity = nil
|
|
607
633
|
end
|
|
608
634
|
|
|
635
|
+
# The state this session carries ACROSS processes in the snapshot rather than deriving each run: the
|
|
636
|
+
# effects sidecar above, and (issues #796 / #794) the run-level rows the last FULL run answered — the
|
|
637
|
+
# `definition-build-failed` set and the HKT-scan outcome, nil until a full run has produced them, and
|
|
638
|
+
# handed to every narrowed run this session builds, none of which can derive them from its own files.
|
|
639
|
+
def reset_carried_state
|
|
640
|
+
reset_effect_state
|
|
641
|
+
@run_level_rows = nil
|
|
642
|
+
end
|
|
643
|
+
|
|
609
644
|
# Whether the effects half of a restored snapshot permits reuse. Collection off is vacuously true —
|
|
610
645
|
# the session keeps no collections, writes none, and the pre-#382 reuse decision stands unchanged.
|
|
611
646
|
def effects_reuse_permitted?(payload)
|
|
@@ -696,6 +731,9 @@ module Rigor
|
|
|
696
731
|
@digests[path] = pack_digest(path)
|
|
697
732
|
end
|
|
698
733
|
absorb_dependency_graph(runner)
|
|
734
|
+
# Issues #796 / #794 — the recheck's own snapshots already carry the replayed rows folded together
|
|
735
|
+
# with anything its closure demanded for itself, so this is the same union the next run replays.
|
|
736
|
+
@run_level_rows = runner.run_level_rows
|
|
699
737
|
refresh_return_summaries(runner, analyze_set)
|
|
700
738
|
refresh_effect_collections(runner, analyze_set)
|
|
701
739
|
end
|
|
@@ -803,22 +841,42 @@ module Rigor
|
|
|
803
841
|
end
|
|
804
842
|
|
|
805
843
|
# ADR-46 slice 3 — the consumers to re-check because a symbol that appeared in a changed file resolves
|
|
806
|
-
# a prior missed lookup
|
|
807
|
-
# would satisfy (`toplevel:foo` for a
|
|
808
|
-
# negative-dependents of those keys.
|
|
809
|
-
|
|
844
|
+
# a prior missed lookup, and (issue #639) because a class DECLARATION appeared or vanished. Maps each
|
|
845
|
+
# appeared `"ClassName#method"` to the negative-dependency key it would satisfy (`toplevel:foo` for a
|
|
846
|
+
# top-level def, `method:C#m` otherwise), then unions the recorded negative-dependents of those keys.
|
|
847
|
+
# Issue #1120 — plus the consumers of any refinement name the edit moved ({#refinement_affected}). Issue #1367 —
|
|
848
|
+
# and every file whose last result holds a `global.*` diagnostic ({#global_write_reporters}).
|
|
849
|
+
def negative_affected(changed, removed, new_fingerprints, new_class_decls, new_constant_decls, summary = nil)
|
|
810
850
|
appeared_methods = Incremental.appeared_symbols(changed, @symbol_fingerprints, new_fingerprints)
|
|
811
|
-
|
|
851
|
+
# Issue #639 — a class DISAPPEARING satisfies the `class:` kind too, now that a resolved bare
|
|
852
|
+
# reference records the edge and not only a failed one; removed files join the diff for it.
|
|
853
|
+
moved_classes = Incremental.changed_class_declarations(
|
|
854
|
+
changed + removed, @class_decls, new_class_decls
|
|
855
|
+
)
|
|
812
856
|
# Issue #644 — a constant whose PUBLICATION moved satisfies the `constant:` kind, keyed on the same
|
|
813
|
-
# last segment the consumer recorded.
|
|
814
|
-
# second declarer restores the precise answer, and no other producer input can see that.
|
|
857
|
+
# last segment the consumer recorded. Removed files join this diff (as they do the class one above):
|
|
858
|
+
# deleting a second declarer restores the precise answer, and no other producer input can see that.
|
|
815
859
|
moved_constants = Incremental.changed_constant_publications(
|
|
816
860
|
changed + removed, @constant_decls, new_constant_decls
|
|
817
861
|
)
|
|
818
862
|
keys = appeared_methods.map { |symbol| negative_key_for(symbol) }
|
|
819
|
-
keys.concat(
|
|
863
|
+
keys.concat(moved_classes.map { |klass| "class:#{klass.split('::').last}" })
|
|
820
864
|
keys.concat(moved_constants.map { |name| "constant:#{name.split('::').last}" })
|
|
821
|
-
Incremental.negative_closure(keys, @negative_dependents)
|
|
865
|
+
Incremental.negative_closure(keys, @negative_dependents) | refinement_affected(changed + removed, summary) |
|
|
866
|
+
global_write_reporters
|
|
867
|
+
end
|
|
868
|
+
|
|
869
|
+
# Issue #1120 — the consumers whose `call.undefined-method` answer read the refinement table for a method
|
|
870
|
+
# name whose refinements moved in this edit. The before-state is each file's seed bundle (the per-file
|
|
871
|
+
# table the last run recorded), the after-state the scan's per-file tables. A refine body is not a class's
|
|
872
|
+
# method, so neither the symbol fingerprints nor the appeared-symbol diff above sees it.
|
|
873
|
+
def refinement_affected(paths, summary)
|
|
874
|
+
after = (summary && summary[:refinements]) || {}
|
|
875
|
+
before = paths.to_h { |path| [path, @seed_bundles.dig(path, :refinements)] }
|
|
876
|
+
names = Incremental.changed_refinement_names(paths, before, after)
|
|
877
|
+
return Set.new if names.empty?
|
|
878
|
+
|
|
879
|
+
Incremental.negative_closure(names.map { |name| "refinement:#{name}" }, @negative_dependents)
|
|
822
880
|
end
|
|
823
881
|
|
|
824
882
|
# The qualified class/module names declared in the pre-parsed `index` (shared with
|
|
@@ -1013,18 +1071,51 @@ module Rigor
|
|
|
1013
1071
|
candidates.reject { |path| stat_fresh?(path) }
|
|
1014
1072
|
end
|
|
1015
1073
|
|
|
1016
|
-
# A bound buffer's logical path is never fresh: the bytes to analyse live in the editor's temp file, and
|
|
1017
|
-
# the recorded entry describes the file on disk. Re-analysing it when the two happen to agree costs one
|
|
1018
|
-
# file; trusting the stat tuple would serve the editor its own stale diagnostics.
|
|
1019
1074
|
def buffer_path?(path)
|
|
1020
1075
|
!@buffer.nil? && path == @buffer.logical_path
|
|
1021
1076
|
end
|
|
1022
1077
|
|
|
1078
|
+
# Editor mode (#146) — the bound buffer's logical path is fresh exactly when the EDITOR's bytes still
|
|
1079
|
+
# hash to the digest the snapshot recorded for the file they stand in for. The recorded stat tuple
|
|
1080
|
+
# describes the file on disk, which an edit in the editor never moves, so validating through it serves
|
|
1081
|
+
# the editor its own pre-buffer answers (#960); hashing the buffer makes the substituted file changed
|
|
1082
|
+
# whenever it differs, and keeps an untouched buffer out of the closure. Anything unreadable or
|
|
1083
|
+
# unrecorded reads as changed, the conservative direction the rest of this tier takes.
|
|
1084
|
+
def buffer_fresh?(path)
|
|
1085
|
+
recorded = Cache::FileDigest.content_digest(@digests[path])
|
|
1086
|
+
return false if recorded.nil?
|
|
1087
|
+
|
|
1088
|
+
Cache::FileDigest.hexdigest(@buffer.resolve(path)) == recorded
|
|
1089
|
+
rescue StandardError
|
|
1090
|
+
false
|
|
1091
|
+
end
|
|
1092
|
+
|
|
1093
|
+
# Editor mode (#146 / #960) — `--instead-of` is spelled the way the editor spells it (absolute, or
|
|
1094
|
+
# `./`-prefixed), while the analysed set is spelled the way the run's path arguments produce. A binding
|
|
1095
|
+
# whose logical path matches no member of that set substitutes nothing at all: every reader keeps
|
|
1096
|
+
# reading the file on disk and the run answers as if no buffer had been passed. Re-spell the binding
|
|
1097
|
+
# onto the set's own member, identified by real path, once the set is known.
|
|
1098
|
+
def rebind_buffer(files)
|
|
1099
|
+
return if @buffer.nil? || files.include?(@buffer.logical_path)
|
|
1100
|
+
|
|
1101
|
+
target = real_path(@buffer.logical_path)
|
|
1102
|
+
return if target.nil?
|
|
1103
|
+
|
|
1104
|
+
match = files.find { |path| real_path(path) == target }
|
|
1105
|
+
@buffer = BufferBinding.new(logical_path: match, physical_path: @buffer.physical_path) if match
|
|
1106
|
+
end
|
|
1107
|
+
|
|
1108
|
+
def real_path(path)
|
|
1109
|
+
File.realpath(path)
|
|
1110
|
+
rescue StandardError
|
|
1111
|
+
nil
|
|
1112
|
+
end
|
|
1113
|
+
|
|
1023
1114
|
# True when `path`'s recorded stat entry proves it unchanged since the last analysis. Any stat / parse
|
|
1024
1115
|
# failure (missing entry, unreadable / vanished file) reads as NOT fresh (→ re-analyse), preserving the
|
|
1025
1116
|
# prior `digest(path) != recorded` "changed" semantics for a file that cannot be validated.
|
|
1026
1117
|
def stat_fresh?(path)
|
|
1027
|
-
return
|
|
1118
|
+
return buffer_fresh?(path) if buffer_path?(path)
|
|
1028
1119
|
|
|
1029
1120
|
entry = @digests[path]
|
|
1030
1121
|
return false if entry.nil?
|
|
@@ -79,7 +79,6 @@ module Rigor
|
|
|
79
79
|
#
|
|
80
80
|
# Keeping the opaque decision here, rather than at each cache's call site, means a new consumer cannot
|
|
81
81
|
# key on `digest` while forgetting that an opaque surface makes it meaningless.
|
|
82
|
-
# @return [String, nil]
|
|
83
82
|
def self.key_digest(registry)
|
|
84
83
|
result = from_registry(registry)
|
|
85
84
|
result.opaque? ? nil : result.digest.to_s
|
|
@@ -16,13 +16,23 @@ module Rigor
|
|
|
16
16
|
# are NOT visible until the owner invalidates the scan — typically via `workspace/didChangeWatchedFiles`.
|
|
17
17
|
# This is the same trade-off the LSP made when slice 7 cached only the `Environment`; extending the cache
|
|
18
18
|
# to the pre-pass outputs preserves the contract.
|
|
19
|
+
#
|
|
20
|
+
# `template_units` (#1038) is the one slot a consumer does not adopt verbatim. The rest of the snapshot
|
|
21
|
+
# is reused as it stands until the owner invalidates it; the template index is handed to
|
|
22
|
+
# `TemplateUnits.collect(previous:)`, which re-expands the claimed globs and revalidates each template
|
|
23
|
+
# against the filesystem, so a template edited, added or deleted on disk is seen on the next publish
|
|
24
|
+
# even though the snapshot itself did not move. What the carry saves is the plugin transform — for ERB
|
|
25
|
+
# (#393) an Erubi compile of every view in the project, otherwise paid per keystroke. The index is
|
|
26
|
+
# always built WITHOUT a buffer binding, so the shared snapshot never holds a unit compiled from an
|
|
27
|
+
# editor's in-flight bytes.
|
|
19
28
|
ProjectScan = Data.define(
|
|
20
29
|
:plugin_registry,
|
|
21
30
|
:dependency_source_index,
|
|
22
31
|
:synthetic_method_index,
|
|
23
32
|
:project_patched_methods,
|
|
24
33
|
:plugin_prepare_diagnostics,
|
|
25
|
-
:pre_eval_diagnostics
|
|
34
|
+
:pre_eval_diagnostics,
|
|
35
|
+
:template_units
|
|
26
36
|
)
|
|
27
37
|
end
|
|
28
38
|
end
|