rigortype 0.2.7 → 0.2.8
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 +1 -1
- data/docs/manual/04-diagnostics.md +7 -4
- data/docs/manual/06-baseline.md +5 -2
- data/docs/manual/15-type-protection-coverage.md +6 -4
- data/lib/rigor/analysis/baseline.rb +56 -96
- data/lib/rigor/analysis/buffer_binding.rb +13 -20
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +29 -48
- data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +35 -54
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +23 -37
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +16 -23
- data/lib/rigor/analysis/check_rules/rule_walk.rb +48 -71
- data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +19 -28
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +48 -67
- data/lib/rigor/analysis/check_rules.rb +174 -274
- data/lib/rigor/analysis/dependency_recorder.rb +26 -38
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +13 -25
- data/lib/rigor/analysis/dependency_source_inference/builder.rb +17 -30
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +15 -26
- data/lib/rigor/analysis/dependency_source_inference/index.rb +45 -76
- data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +23 -40
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +50 -83
- data/lib/rigor/analysis/dependency_source_inference.rb +6 -10
- data/lib/rigor/analysis/diagnostic.rb +48 -75
- data/lib/rigor/analysis/erb_template_detector.rb +13 -18
- data/lib/rigor/analysis/fact_store.rb +12 -22
- data/lib/rigor/analysis/incremental.rb +47 -63
- data/lib/rigor/analysis/incremental_session.rb +74 -100
- data/lib/rigor/analysis/project_scan.rb +12 -23
- data/lib/rigor/analysis/result.rb +3 -5
- data/lib/rigor/analysis/rule_catalog.rb +67 -95
- data/lib/rigor/analysis/run_stats.rb +38 -61
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +101 -160
- data/lib/rigor/analysis/runner/pool_coordinator.rb +121 -188
- data/lib/rigor/analysis/runner/project_pre_passes.rb +62 -96
- data/lib/rigor/analysis/runner/run_snapshots.rb +12 -18
- data/lib/rigor/analysis/runner.rb +220 -333
- data/lib/rigor/analysis/self_call_resolution_recorder.rb +30 -43
- data/lib/rigor/analysis/worker_session.rb +64 -102
- data/lib/rigor/ast/type_node.rb +6 -8
- data/lib/rigor/ast.rb +6 -10
- data/lib/rigor/bleeding_edge.rb +27 -35
- data/lib/rigor/builtins/hkt_builtins.rb +7 -14
- data/lib/rigor/builtins/imported_refinements.rb +106 -149
- data/lib/rigor/builtins/predefined_constant_refinements.rb +51 -65
- data/lib/rigor/builtins/regex_refinement.rb +32 -43
- data/lib/rigor/builtins/static_return_refinements.rb +57 -81
- data/lib/rigor/cache/descriptor.rb +58 -94
- data/lib/rigor/cache/incremental_snapshot.rb +32 -48
- data/lib/rigor/cache/rbs_cache_producer.rb +10 -15
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +10 -16
- data/lib/rigor/cache/rbs_class_type_param_names.rb +10 -16
- data/lib/rigor/cache/rbs_constant_table.rb +8 -13
- data/lib/rigor/cache/rbs_descriptor.rb +8 -13
- data/lib/rigor/cache/rbs_environment.rb +11 -19
- data/lib/rigor/cache/rbs_environment_marshal_patch.rb +11 -19
- data/lib/rigor/cache/rbs_known_class_names.rb +8 -12
- data/lib/rigor/cache/store.rb +96 -151
- data/lib/rigor/cli/annotate_command.rb +51 -88
- data/lib/rigor/cli/baseline_command.rb +10 -17
- data/lib/rigor/cli/check_command.rb +121 -199
- data/lib/rigor/cli/check_runner_factory.rb +8 -14
- data/lib/rigor/cli/ci_detector.rb +9 -14
- data/lib/rigor/cli/command.rb +8 -14
- data/lib/rigor/cli/coverage_command.rb +19 -26
- data/lib/rigor/cli/coverage_mutation.rb +14 -19
- data/lib/rigor/cli/coverage_report.rb +0 -2
- data/lib/rigor/cli/coverage_scan.rb +7 -11
- data/lib/rigor/cli/diagnostic_formats.rb +43 -62
- data/lib/rigor/cli/diff_command.rb +10 -20
- data/lib/rigor/cli/docs_command.rb +26 -40
- data/lib/rigor/cli/doctor_command.rb +8 -9
- data/lib/rigor/cli/explain_command.rb +4 -7
- data/lib/rigor/cli/fused_protection_renderer.rb +4 -5
- data/lib/rigor/cli/fused_protection_report.rb +6 -8
- data/lib/rigor/cli/lsp_command.rb +11 -19
- data/lib/rigor/cli/mcp_command.rb +4 -6
- data/lib/rigor/cli/mutation_protection_renderer.rb +3 -4
- data/lib/rigor/cli/mutation_protection_report.rb +6 -9
- data/lib/rigor/cli/options.rb +11 -19
- data/lib/rigor/cli/plugin_command.rb +18 -30
- data/lib/rigor/cli/plugins_command.rb +29 -51
- data/lib/rigor/cli/plugins_renderer.rb +12 -20
- data/lib/rigor/cli/prism_colorizer.rb +13 -19
- data/lib/rigor/cli/protection_renderer.rb +5 -7
- data/lib/rigor/cli/protection_report.rb +27 -17
- data/lib/rigor/cli/renderable.rb +4 -6
- data/lib/rigor/cli/show_bleedingedge_command.rb +5 -8
- data/lib/rigor/cli/sig_gen_command.rb +14 -26
- data/lib/rigor/cli/skill_command.rb +30 -47
- data/lib/rigor/cli/skill_describe.rb +40 -64
- data/lib/rigor/cli/trace_command.rb +9 -16
- data/lib/rigor/cli/trace_renderer.rb +35 -51
- data/lib/rigor/cli/triage_command.rb +6 -10
- data/lib/rigor/cli/triage_renderer.rb +1 -2
- data/lib/rigor/cli/type_of_command.rb +14 -23
- data/lib/rigor/cli/type_of_renderer.rb +3 -5
- data/lib/rigor/cli/type_scan_command.rb +6 -10
- data/lib/rigor/cli/type_scan_renderer.rb +3 -5
- data/lib/rigor/cli/type_scan_report.rb +2 -3
- data/lib/rigor/cli/upgrade_command.rb +2 -3
- data/lib/rigor/cli.rb +16 -28
- data/lib/rigor/config_audit.rb +35 -44
- data/lib/rigor/configuration/dependencies.rb +41 -70
- data/lib/rigor/configuration/severity_profile.rb +28 -42
- data/lib/rigor/configuration.rb +150 -241
- data/lib/rigor/environment/bundle_sig_discovery.rb +74 -118
- data/lib/rigor/environment/class_registry.rb +19 -26
- data/lib/rigor/environment/constant_type_cache_holder.rb +14 -21
- data/lib/rigor/environment/hkt_registry_holder.rb +6 -12
- data/lib/rigor/environment/lockfile_resolver.rb +31 -47
- data/lib/rigor/environment/rbs_collection_discovery.rb +39 -63
- data/lib/rigor/environment/rbs_coverage_report.rb +24 -42
- data/lib/rigor/environment/rbs_loader.rb +420 -518
- data/lib/rigor/environment/reflection.rb +28 -53
- data/lib/rigor/environment/reporters.rb +13 -24
- data/lib/rigor/environment.rb +176 -291
- data/lib/rigor/flow_contribution/conflict.rb +16 -27
- data/lib/rigor/flow_contribution/element.rb +7 -12
- data/lib/rigor/flow_contribution/fact.rb +33 -57
- data/lib/rigor/flow_contribution/merge_result.rb +6 -9
- data/lib/rigor/flow_contribution/merger.rb +32 -47
- data/lib/rigor/flow_contribution.rb +37 -55
- data/lib/rigor/inference/acceptance.rb +133 -219
- data/lib/rigor/inference/block_parameter_binder.rb +52 -82
- data/lib/rigor/inference/body_fixpoint.rb +22 -30
- data/lib/rigor/inference/budget_trace.rb +43 -63
- data/lib/rigor/inference/builtins/array_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/comparable_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/complex_catalog.rb +13 -19
- data/lib/rigor/inference/builtins/date_catalog.rb +38 -67
- data/lib/rigor/inference/builtins/encoding_catalog.rb +22 -36
- data/lib/rigor/inference/builtins/enumerable_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/exception_catalog.rb +38 -57
- data/lib/rigor/inference/builtins/hash_catalog.rb +9 -14
- data/lib/rigor/inference/builtins/method_catalog.rb +29 -48
- data/lib/rigor/inference/builtins/numeric_catalog.rb +13 -18
- data/lib/rigor/inference/builtins/pathname_catalog.rb +8 -13
- data/lib/rigor/inference/builtins/proc_catalog.rb +38 -62
- data/lib/rigor/inference/builtins/random_catalog.rb +21 -32
- data/lib/rigor/inference/builtins/range_catalog.rb +12 -21
- data/lib/rigor/inference/builtins/rational_catalog.rb +9 -15
- data/lib/rigor/inference/builtins/re_catalog.rb +29 -48
- data/lib/rigor/inference/builtins/set_catalog.rb +18 -27
- data/lib/rigor/inference/builtins/string_catalog.rb +12 -19
- data/lib/rigor/inference/builtins/struct_catalog.rb +18 -30
- data/lib/rigor/inference/builtins/time_catalog.rb +28 -44
- data/lib/rigor/inference/closure_escape_analyzer.rb +44 -67
- data/lib/rigor/inference/coverage_scanner.rb +13 -18
- data/lib/rigor/inference/def_return_typer.rb +8 -14
- data/lib/rigor/inference/dynamic_origin.rb +23 -20
- data/lib/rigor/inference/expression_typer.rb +774 -1152
- data/lib/rigor/inference/fallback.rb +8 -12
- data/lib/rigor/inference/fallback_tracer.rb +4 -10
- data/lib/rigor/inference/flow_tracer.rb +25 -36
- data/lib/rigor/inference/hkt_body.rb +45 -68
- data/lib/rigor/inference/hkt_body_parser.rb +33 -52
- data/lib/rigor/inference/hkt_reducer.rb +38 -59
- data/lib/rigor/inference/hkt_registry.rb +50 -76
- data/lib/rigor/inference/indexed_narrowing.rb +55 -81
- data/lib/rigor/inference/macro_block_self_type.rb +21 -34
- data/lib/rigor/inference/method_dispatcher/array_to_h_folding.rb +11 -18
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +49 -83
- data/lib/rigor/inference/method_dispatcher/call_context.rb +16 -23
- data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +13 -22
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +307 -454
- data/lib/rigor/inference/method_dispatcher/data_folding.rb +24 -34
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +22 -37
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +52 -81
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +51 -78
- data/lib/rigor/inference/method_dispatcher/literal_string_folding.rb +60 -97
- data/lib/rigor/inference/method_dispatcher/math_folding.rb +23 -34
- data/lib/rigor/inference/method_dispatcher/member_shape_projection.rb +18 -26
- data/lib/rigor/inference/method_dispatcher/method_folding.rb +37 -71
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +114 -182
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +122 -193
- data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +15 -24
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +64 -93
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +31 -45
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +6 -9
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +356 -511
- data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +22 -32
- data/lib/rigor/inference/method_dispatcher/singleton_folding.rb +15 -21
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +66 -82
- data/lib/rigor/inference/method_dispatcher/time_folding.rb +10 -15
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +9 -13
- data/lib/rigor/inference/method_dispatcher.rb +378 -524
- data/lib/rigor/inference/method_parameter_binder.rb +81 -114
- data/lib/rigor/inference/multi_target_binder.rb +51 -68
- data/lib/rigor/inference/mutation_widening.rb +115 -158
- data/lib/rigor/inference/narrowing.rb +509 -727
- data/lib/rigor/inference/origin_lookup.rb +38 -0
- data/lib/rigor/inference/parameter_inference_collector.rb +100 -100
- data/lib/rigor/inference/precision_scanner.rb +26 -35
- data/lib/rigor/inference/project_patched_methods.rb +20 -32
- data/lib/rigor/inference/project_patched_scanner.rb +23 -37
- data/lib/rigor/inference/protection_scanner.rb +16 -18
- data/lib/rigor/inference/rbs_type_translator.rb +49 -66
- data/lib/rigor/inference/scope_indexer.rb +473 -817
- data/lib/rigor/inference/statement_evaluator.rb +706 -1111
- data/lib/rigor/inference/struct_fold_safety.rb +34 -48
- data/lib/rigor/inference/synthetic_method.rb +9 -16
- data/lib/rigor/inference/synthetic_method_index.rb +20 -35
- data/lib/rigor/inference/synthetic_method_scanner.rb +63 -103
- data/lib/rigor/language_server/buffer_resolution.rb +6 -9
- data/lib/rigor/language_server/buffer_table.rb +11 -18
- data/lib/rigor/language_server/completion_provider.rb +69 -116
- data/lib/rigor/language_server/debouncer.rb +16 -25
- data/lib/rigor/language_server/diagnostic_publisher.rb +26 -40
- data/lib/rigor/language_server/document_symbol_provider.rb +14 -19
- data/lib/rigor/language_server/folding_range_provider.rb +11 -19
- data/lib/rigor/language_server/hover_provider.rb +8 -11
- data/lib/rigor/language_server/hover_renderer.rb +56 -93
- data/lib/rigor/language_server/loop.rb +14 -19
- data/lib/rigor/language_server/project_context.rb +46 -74
- data/lib/rigor/language_server/selection_range_provider.rb +9 -12
- data/lib/rigor/language_server/server.rb +55 -83
- data/lib/rigor/language_server/signature_help_provider.rb +29 -46
- data/lib/rigor/language_server/synchronized_writer.rb +4 -7
- data/lib/rigor/language_server/uri.rb +8 -13
- data/lib/rigor/language_server.rb +4 -6
- data/lib/rigor/mcp/loop.rb +2 -3
- data/lib/rigor/mcp/server.rb +4 -7
- data/lib/rigor/mcp.rb +3 -6
- data/lib/rigor/plugin/access_denied_error.rb +5 -8
- data/lib/rigor/plugin/additional_initializer.rb +21 -31
- data/lib/rigor/plugin/base.rb +335 -518
- data/lib/rigor/plugin/blueprint.rb +14 -23
- data/lib/rigor/plugin/box.rb +18 -29
- data/lib/rigor/plugin/fact_store.rb +16 -26
- data/lib/rigor/plugin/inflector.rb +37 -53
- data/lib/rigor/plugin/io_boundary.rb +33 -56
- data/lib/rigor/plugin/isolation.rb +42 -55
- data/lib/rigor/plugin/load_error.rb +10 -15
- data/lib/rigor/plugin/loader.rb +30 -49
- data/lib/rigor/plugin/macro/block_as_method.rb +20 -32
- data/lib/rigor/plugin/macro/heredoc_template.rb +35 -58
- data/lib/rigor/plugin/macro/nested_class_template.rb +22 -36
- data/lib/rigor/plugin/macro/trait_registry.rb +34 -51
- data/lib/rigor/plugin/macro.rb +10 -15
- data/lib/rigor/plugin/manifest.rb +85 -144
- data/lib/rigor/plugin/node_context.rb +14 -22
- data/lib/rigor/plugin/node_rule_walk.rb +49 -74
- data/lib/rigor/plugin/protocol_contract.rb +25 -39
- data/lib/rigor/plugin/registry.rb +132 -205
- data/lib/rigor/plugin/services.rb +21 -33
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +11 -19
- data/lib/rigor/plugin/trust_policy.rb +24 -38
- data/lib/rigor/plugin/type_node_resolver.rb +15 -24
- data/lib/rigor/protection/diagnostic_oracle.rb +11 -13
- data/lib/rigor/protection/mutation_scanner.rb +27 -35
- data/lib/rigor/protection/mutator.rb +50 -70
- data/lib/rigor/protection/test_suite_oracle.rb +20 -27
- data/lib/rigor/rbs_extended/conformance_checker.rb +48 -68
- data/lib/rigor/rbs_extended/hkt_directives.rb +28 -54
- data/lib/rigor/rbs_extended/reporter.rb +24 -40
- data/lib/rigor/rbs_extended.rb +107 -197
- data/lib/rigor/reflection.rb +68 -86
- data/lib/rigor/scope/discovery_index.rb +14 -19
- data/lib/rigor/scope.rb +255 -310
- data/lib/rigor/sig_gen/classification.rb +6 -10
- data/lib/rigor/sig_gen/generator.rb +197 -323
- data/lib/rigor/sig_gen/layout_index.rb +12 -20
- data/lib/rigor/sig_gen/method_candidate.rb +12 -17
- data/lib/rigor/sig_gen/observation_collector.rb +38 -70
- data/lib/rigor/sig_gen/observed_call.rb +13 -23
- data/lib/rigor/sig_gen/path_mapper.rb +17 -29
- data/lib/rigor/sig_gen/renderer.rb +7 -13
- data/lib/rigor/sig_gen/type_elaborator.rb +15 -28
- data/lib/rigor/sig_gen/write_result.rb +8 -16
- data/lib/rigor/sig_gen/writer.rb +95 -174
- data/lib/rigor/sig_gen.rb +3 -6
- data/lib/rigor/signature_path_audit.rb +24 -30
- data/lib/rigor/source/constant_path.rb +10 -14
- data/lib/rigor/source/literals.rb +31 -45
- data/lib/rigor/source/node_locator.rb +9 -11
- data/lib/rigor/source/node_walker.rb +9 -13
- data/lib/rigor/source.rb +3 -4
- data/lib/rigor/testing.rb +16 -20
- data/lib/rigor/triage/catalogue.rb +38 -62
- data/lib/rigor/triage.rb +31 -52
- data/lib/rigor/trinary.rb +9 -13
- data/lib/rigor/type/acceptance_router.rb +4 -6
- data/lib/rigor/type/accepts_result.rb +10 -14
- data/lib/rigor/type/app.rb +19 -27
- data/lib/rigor/type/bot.rb +4 -6
- data/lib/rigor/type/bound_method.rb +10 -15
- data/lib/rigor/type/combinator.rb +165 -257
- data/lib/rigor/type/constant.rb +23 -34
- data/lib/rigor/type/data_class.rb +10 -15
- data/lib/rigor/type/data_instance.rb +14 -20
- data/lib/rigor/type/difference.rb +21 -32
- data/lib/rigor/type/dynamic.rb +3 -5
- data/lib/rigor/type/hash_shape.rb +32 -18
- data/lib/rigor/type/integer_range.rb +11 -16
- data/lib/rigor/type/intersection.rb +27 -42
- data/lib/rigor/type/nominal.rb +10 -15
- data/lib/rigor/type/plain_lattice.rb +9 -13
- data/lib/rigor/type/refined.rb +67 -114
- data/lib/rigor/type/singleton.rb +4 -6
- data/lib/rigor/type/struct_class.rb +11 -16
- data/lib/rigor/type/struct_instance.rb +15 -21
- data/lib/rigor/type/tuple.rb +14 -19
- data/lib/rigor/type/union.rb +30 -42
- data/lib/rigor/type_node/generic.rb +14 -26
- data/lib/rigor/type_node/identifier.rb +12 -19
- data/lib/rigor/type_node.rb +3 -12
- data/lib/rigor/value_semantics.rb +16 -21
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +18 -30
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +16 -29
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +12 -23
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +22 -39
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +26 -46
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +51 -87
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +10 -17
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +26 -39
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +118 -176
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +30 -51
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +57 -92
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +71 -108
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +13 -22
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +15 -25
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +8 -13
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +16 -24
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +30 -47
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +79 -129
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +36 -57
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +27 -41
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +16 -24
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +148 -235
- data/plugins/rigor-activerecord/lib/rigor-activerecord.rb +3 -5
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb +8 -14
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +9 -15
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +4 -7
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +23 -41
- data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +3 -5
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +6 -10
- data/plugins/rigor-activesupport-core-ext/lib/rigor-activesupport-core-ext.rb +8 -11
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +30 -45
- data/plugins/rigor-devise/lib/rigor-devise.rb +3 -5
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +43 -69
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +26 -35
- data/plugins/rigor-dry-schema/lib/rigor-dry-schema.rb +3 -5
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +30 -47
- data/plugins/rigor-dry-struct/lib/rigor-dry-struct.rb +3 -5
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +67 -113
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +29 -46
- data/plugins/rigor-dry-types/lib/rigor-dry-types.rb +3 -5
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -20
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +14 -23
- data/plugins/rigor-dry-validation/lib/rigor-dry-validation.rb +2 -3
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +22 -37
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +28 -46
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +13 -17
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +30 -47
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +52 -80
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +21 -31
- data/plugins/rigor-graphql/lib/rigor-graphql.rb +3 -5
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +11 -17
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +20 -34
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +45 -75
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +22 -36
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +22 -41
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +17 -32
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +6 -12
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +4 -8
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +17 -32
- data/plugins/rigor-rails/lib/rigor-rails.rb +11 -18
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +58 -92
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +20 -34
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +20 -31
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +49 -82
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +55 -92
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +51 -90
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +17 -30
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +38 -70
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +42 -74
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +280 -497
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +54 -89
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +32 -54
- data/plugins/rigor-rbs-inline/lib/rigor-rbs-inline.rb +8 -13
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +9 -16
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +24 -39
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +13 -22
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +34 -56
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/scope_walker.rb +22 -42
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +43 -75
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +27 -39
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/http_status_codes.rb +14 -19
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +20 -34
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +28 -47
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +21 -37
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +13 -22
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +18 -31
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +6 -10
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +14 -29
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +23 -41
- data/plugins/rigor-sinatra/lib/rigor-sinatra.rb +3 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +23 -38
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +57 -96
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +22 -35
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +41 -69
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/method_signature.rb +6 -10
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +24 -41
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +29 -50
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +55 -88
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +159 -262
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +21 -29
- data/plugins/rigor-statesman/lib/rigor-statesman.rb +3 -5
- data/plugins/rigor-typescript-utility-types/lib/rigor/plugin/typescript_utility_types.rb +23 -37
- data/plugins/rigor-typescript-utility-types/lib/rigor-typescript-utility-types.rb +4 -6
- data/sig/rigor/scope.rbs +6 -0
- metadata +2 -1
|
@@ -11,27 +11,21 @@ require_relative "../../rbs_extended/conformance_checker"
|
|
|
11
11
|
module Rigor
|
|
12
12
|
module Analysis
|
|
13
13
|
class Runner
|
|
14
|
-
# Owns the per-file analysis dispatch: the sequential coordinator
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
# {RunSnapshots}, and merges per-worker reporter drains back into
|
|
20
|
-
# the runner's reporter accumulators.
|
|
14
|
+
# Owns the per-file analysis dispatch: the sequential coordinator path (default) and both worker-pool
|
|
15
|
+
# backends — the ADR-15 Phase 4b Ractor pool and the ADR-15 Amendment fork pool, plus the
|
|
16
|
+
# pool-degraded fallback. Builds the coordinator-side Environment, snapshots the end-of-pass RBS
|
|
17
|
+
# tables into the shared {RunSnapshots}, and merges per-worker reporter drains back into the runner's
|
|
18
|
+
# reporter accumulators.
|
|
21
19
|
#
|
|
22
|
-
# Sequential-equivalence contract (docs/internal-spec/
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
# coordinator re-orders worker results by original path order and
|
|
26
|
-
# replays per-worker reporter entries through the dedupe-on-record
|
|
20
|
+
# Sequential-equivalence contract (docs/internal-spec/ worker-session.md): the pool path MUST produce
|
|
21
|
+
# the same diagnostics, in the same order, as the sequential path. The coordinator re-orders worker
|
|
22
|
+
# results by original path order and replays per-worker reporter entries through the dedupe-on-record
|
|
27
23
|
# APIs so reporter state matches a single-session run.
|
|
28
24
|
#
|
|
29
|
-
# Per-run varying prepass state (plugin registry, dependency-source
|
|
30
|
-
#
|
|
31
|
-
# through injected
|
|
32
|
-
#
|
|
33
|
-
# CheckRules / recorder / plugin-emission machinery stays on the
|
|
34
|
-
# {Runner}.
|
|
25
|
+
# Per-run varying prepass state (plugin registry, dependency-source index, synthetic-method /
|
|
26
|
+
# project-patched indexes) is read through injected reader procs; the actual per-file analysis is
|
|
27
|
+
# delegated back through an injected `analyze_file` callable so the CheckRules / recorder /
|
|
28
|
+
# plugin-emission machinery stays on the {Runner}.
|
|
35
29
|
class PoolCoordinator # rubocop:disable Metrics/ClassLength
|
|
36
30
|
# @param configuration [Rigor::Configuration]
|
|
37
31
|
# @param cache_store [Rigor::Cache::Store, nil]
|
|
@@ -41,17 +35,15 @@ module Rigor
|
|
|
41
35
|
# @param buffer [BufferBinding, nil]
|
|
42
36
|
# @param environment_override [Rigor::Environment, nil]
|
|
43
37
|
# @param rbs_extended_reporter [RbsExtended::Reporter]
|
|
44
|
-
# @param boundary_cross_reporter
|
|
45
|
-
#
|
|
46
|
-
# @param source_rbs_synthesis_reporter
|
|
47
|
-
# [Plugin::SourceRbsSynthesisReporter]
|
|
38
|
+
# @param boundary_cross_reporter [DependencySourceInference::BoundaryCrossReporter]
|
|
39
|
+
# @param source_rbs_synthesis_reporter [Plugin::SourceRbsSynthesisReporter]
|
|
48
40
|
# @param snapshots [RunSnapshots] shared end-of-pass snapshot sink.
|
|
49
41
|
# @param plugin_registry [#call] reader for the current registry.
|
|
50
42
|
# @param dependency_source_index [#call] reader.
|
|
51
43
|
# @param synthetic_method_index [#call] reader.
|
|
52
44
|
# @param project_patched_methods [#call] reader.
|
|
53
|
-
# @param project_scope_seed [#call] reader for the cross-file
|
|
54
|
-
#
|
|
45
|
+
# @param project_scope_seed [#call] reader for the cross-file pre-pass seed tables
|
|
46
|
+
# (`Runner#project_scope_seed_tables`).
|
|
55
47
|
# @param analyze_file [#call] `(path, environment) -> diagnostics`.
|
|
56
48
|
def initialize(configuration:, cache_store:, explain:, workers:, collect_stats:, # rubocop:disable Metrics/ParameterLists
|
|
57
49
|
buffer:, environment_override:, rbs_extended_reporter:,
|
|
@@ -78,38 +70,29 @@ module Rigor
|
|
|
78
70
|
@analyze_file = analyze_file
|
|
79
71
|
end
|
|
80
72
|
|
|
81
|
-
# ADR-15 Phase 4b — pool mode is enabled when `@workers > 0`.
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
#
|
|
86
|
-
#
|
|
87
|
-
# because `--workers=N` is a project-scale knob and editor
|
|
88
|
-
# mode is per-buffer; the conflict resolves toward the more
|
|
89
|
-
# specific axis.
|
|
73
|
+
# ADR-15 Phase 4b — pool mode is enabled when `@workers > 0`. Editor mode (`buffer:` non-nil)
|
|
74
|
+
# silently overrides pool mode to sequential: per design § "Ractor pool mode", the pool's warm-up
|
|
75
|
+
# cost dominates one-file wall time, so the pool gains nothing on a per-buffer invocation. The
|
|
76
|
+
# override is part of the contract — not a degradation diagnostic — because `--workers=N` is a
|
|
77
|
+
# project-scale knob and editor mode is per-buffer; the conflict resolves toward the more specific
|
|
78
|
+
# axis.
|
|
90
79
|
def pool_mode?
|
|
91
80
|
return false unless @workers.is_a?(Integer) && @workers.positive?
|
|
92
81
|
|
|
93
82
|
@buffer.nil?
|
|
94
83
|
end
|
|
95
84
|
|
|
96
|
-
# ADR-15 Phase 4b — routes per-file analysis to either the
|
|
97
|
-
#
|
|
98
|
-
#
|
|
99
|
-
#
|
|
100
|
-
#
|
|
101
|
-
# pool path is the substrate exercised by phase 4c when
|
|
102
|
-
# `RIGOR_RACTOR_WORKERS` / `.rigor.yml` `parallel.workers:`
|
|
103
|
-
# is wired.
|
|
85
|
+
# ADR-15 Phase 4b — routes per-file analysis to either the sequential coordinator-side Environment
|
|
86
|
+
# (legacy path, default) or a Ractor worker pool built around {WorkerSession} (opt-in via
|
|
87
|
+
# `workers:`). The sequential path is bit-for-bit unchanged from v0.1.4 / earlier; the pool path is
|
|
88
|
+
# the substrate exercised by phase 4c when `RIGOR_RACTOR_WORKERS` / `.rigor.yml`
|
|
89
|
+
# `parallel.workers:` is wired.
|
|
104
90
|
#
|
|
105
|
-
# Sequential mode also snapshots `class_decl_paths` from the
|
|
106
|
-
#
|
|
107
|
-
#
|
|
108
|
-
#
|
|
109
|
-
#
|
|
110
|
-
# method returns — holding it as long-lived state added
|
|
111
|
-
# memory pressure that surfaced as a Bus Error during the
|
|
112
|
-
# spec suite under Ruby 4.0 + rbs 4.0.2.
|
|
91
|
+
# Sequential mode also snapshots `class_decl_paths` from the local environment after the per-file
|
|
92
|
+
# loop completes so `RunStats` can attribute the RBS class universe between project-sig and bundled
|
|
93
|
+
# sources. The env stays a LOCAL variable (not an ivar) so it goes GC-eligible when the method
|
|
94
|
+
# returns — holding it as long-lived state added memory pressure that surfaced as a Bus Error
|
|
95
|
+
# during the spec suite under Ruby 4.0 + rbs 4.0.2.
|
|
113
96
|
def analyze_files(files, environment: nil)
|
|
114
97
|
return [] if files.empty?
|
|
115
98
|
return dispatch_pool(files) if pool_mode?
|
|
@@ -118,19 +101,15 @@ module Rigor
|
|
|
118
101
|
end
|
|
119
102
|
|
|
120
103
|
def analyze_files_sequentially(files, environment)
|
|
121
|
-
# Snapshot the small synthesized-namespace name list (NOT the
|
|
122
|
-
#
|
|
123
|
-
#
|
|
124
|
-
#
|
|
125
|
-
#
|
|
126
|
-
# `#synthesized_namespaces` forces the (otherwise-lazy) RBS env
|
|
127
|
-
# to build — doing so when there is no project sig set would
|
|
128
|
-
# warm `.rigor/cache` on a bare `--no-stats` run.
|
|
104
|
+
# Snapshot the small synthesized-namespace name list (NOT the env — see the method comment) so
|
|
105
|
+
# #run can surface the malformed-RBS `:info` diagnostic without rebuilding the env. Gated on the
|
|
106
|
+
# project actually declaring `signature_paths:`: synthesis only matters for the project's own
|
|
107
|
+
# RBS, and `#synthesized_namespaces` forces the (otherwise-lazy) RBS env to build — doing so when
|
|
108
|
+
# there is no project sig set would warm `.rigor/cache` on a bare `--no-stats` run.
|
|
129
109
|
@snapshots.synthesized_namespaces =
|
|
130
110
|
project_signature_paths? ? (environment.rbs_loader&.synthesized_namespaces || []) : []
|
|
131
|
-
# `rigor:v1:conforms-to` lives only in the project's own
|
|
132
|
-
#
|
|
133
|
-
# reuse the already-built env (no extra RBS load).
|
|
111
|
+
# `rigor:v1:conforms-to` lives only in the project's own `signature_paths:` RBS, so gate the scan
|
|
112
|
+
# the same way and reuse the already-built env (no extra RBS load).
|
|
134
113
|
@snapshots.conformance_results =
|
|
135
114
|
project_signature_paths? ? RbsExtended::ConformanceChecker.scan(environment.rbs_loader) : []
|
|
136
115
|
result = files.flat_map { |path| @analyze_file.call(path, environment) }
|
|
@@ -142,12 +121,10 @@ module Rigor
|
|
|
142
121
|
result
|
|
143
122
|
end
|
|
144
123
|
|
|
145
|
-
# Sequential-mode environment resolver. Returns the supplied
|
|
146
|
-
#
|
|
147
|
-
#
|
|
148
|
-
#
|
|
149
|
-
# fresh Environment per-call via {#build_runner_environment}
|
|
150
|
-
# — preserving the pre-override behaviour bit-for-bit.
|
|
124
|
+
# Sequential-mode environment resolver. Returns the supplied `environment:` override (with the
|
|
125
|
+
# runner's fresh per-run reporter pair attached so dispatcher events route to THIS runner's
|
|
126
|
+
# diagnostics) when present; otherwise builds a fresh Environment per-call via
|
|
127
|
+
# {#build_runner_environment} — preserving the pre-override behaviour bit-for-bit.
|
|
151
128
|
def resolve_sequential_environment(source_files: [])
|
|
152
129
|
return build_runner_environment(source_files: source_files) unless @environment_override
|
|
153
130
|
|
|
@@ -158,14 +135,11 @@ module Rigor
|
|
|
158
135
|
@environment_override
|
|
159
136
|
end
|
|
160
137
|
|
|
161
|
-
# ADR-15 Amendment (2026-05-20) — worker-pool backend selector.
|
|
162
|
-
#
|
|
163
|
-
# the
|
|
164
|
-
#
|
|
165
|
-
#
|
|
166
|
-
# docs/notes/20260520-ractor-pool-cruby-uaf.md). The Ractor pool
|
|
167
|
-
# is preserved but off the default path — `RIGOR_POOL_BACKEND=ractor`
|
|
168
|
-
# opts back in so it stays testable. Platforms without `fork`
|
|
138
|
+
# ADR-15 Amendment (2026-05-20) — worker-pool backend selector. `fork` is the active backend:
|
|
139
|
+
# separate processes sidestep both the Ruby Bug #22075 use-after-free and the worker-side
|
|
140
|
+
# `Ractor::IsolationError` that make the Ractor pool unusable (see the ADR-15 Amendment +
|
|
141
|
+
# docs/notes/20260520-ractor-pool-cruby-uaf.md). The Ractor pool is preserved but off the default
|
|
142
|
+
# path — `RIGOR_POOL_BACKEND=ractor` opts back in so it stays testable. Platforms without `fork`
|
|
169
143
|
# (Windows) fall back to sequential.
|
|
170
144
|
def pool_backend
|
|
171
145
|
return :ractor if ENV["RIGOR_POOL_BACKEND"] == "ractor"
|
|
@@ -186,15 +160,12 @@ module Rigor
|
|
|
186
160
|
end
|
|
187
161
|
end
|
|
188
162
|
|
|
189
|
-
# Coordinator-side Environment used by the sequential code
|
|
190
|
-
#
|
|
191
|
-
# the worker Ractor's body instead.
|
|
163
|
+
# Coordinator-side Environment used by the sequential code path. Pool mode builds one Environment
|
|
164
|
+
# per worker inside the worker Ractor's body instead.
|
|
192
165
|
#
|
|
193
|
-
# ADR-32 WD4 — `source_files:` is threaded down so that
|
|
194
|
-
# `
|
|
195
|
-
# `
|
|
196
|
-
# at env-build time. Defaults to `[]` for callers that don't
|
|
197
|
-
# have a file list yet (e.g. pre-pass-only build paths); in
|
|
166
|
+
# ADR-32 WD4 — `source_files:` is threaded down so that `Environment.for_project` can invoke each
|
|
167
|
+
# loaded plugin's `source_rbs_synthesizer` callable per project source file at env-build time.
|
|
168
|
+
# Defaults to `[]` for callers that don't have a file list yet (e.g. pre-pass-only build paths); in
|
|
198
169
|
# that case no synthesised RBS is contributed.
|
|
199
170
|
def build_runner_environment(source_files: [])
|
|
200
171
|
Environment.for_project(
|
|
@@ -217,62 +188,44 @@ module Rigor
|
|
|
217
188
|
)
|
|
218
189
|
end
|
|
219
190
|
|
|
220
|
-
# ADR-15 Phase 4b — Ractor pool around {WorkerSession}.
|
|
221
|
-
#
|
|
222
|
-
#
|
|
223
|
-
#
|
|
224
|
-
#
|
|
225
|
-
# round-robin across the pool; each worker writes back to
|
|
226
|
-
# the main Ractor's mailbox via `Ractor.main.send` with
|
|
227
|
-
# one of three message kinds:
|
|
191
|
+
# ADR-15 Phase 4b — Ractor pool around {WorkerSession}. Spawns `@workers` Ractors; each takes the
|
|
192
|
+
# shareable payload (Configuration, cache_root String, plugin Blueprint Array, explain Boolean) and
|
|
193
|
+
# builds its OWN WorkerSession internally. Files are distributed round-robin across the pool; each
|
|
194
|
+
# worker writes back to the main Ractor's mailbox via `Ractor.main.send` with one of three message
|
|
195
|
+
# kinds:
|
|
228
196
|
#
|
|
229
|
-
# - `[:prepare, diagnostics]` — once at startup, the
|
|
230
|
-
#
|
|
231
|
-
#
|
|
232
|
-
#
|
|
233
|
-
# each worker produces the same diagnostic set; surfacing
|
|
234
|
-
# them once avoids N× duplication).
|
|
197
|
+
# - `[:prepare, diagnostics]` — once at startup, the session's `prepare_diagnostics` snapshot. The
|
|
198
|
+
# coordinator keeps the FIRST worker's snapshot only (plugin `#prepare` is deterministic per
|
|
199
|
+
# plugin, so each worker produces the same diagnostic set; surfacing them once avoids N×
|
|
200
|
+
# duplication).
|
|
235
201
|
# - `[:file, path, diagnostics]` — one per analysed file.
|
|
236
|
-
# - `[:done, drained_reporters]` — once at exit, the
|
|
237
|
-
#
|
|
202
|
+
# - `[:done, drained_reporters]` — once at exit, the per-worker reporter snapshots for end-of-pool
|
|
203
|
+
# merge.
|
|
238
204
|
#
|
|
239
|
-
# The Ruby 4.0+ Ractor model uses a single per-Ractor
|
|
240
|
-
# mailbox
|
|
241
|
-
# `
|
|
242
|
-
# via `Ractor.receive` until it has counted exactly
|
|
243
|
-
# `pool.size` `:done` messages.
|
|
205
|
+
# The Ruby 4.0+ Ractor model uses a single per-Ractor mailbox (no `Ractor.yield`); workers push
|
|
206
|
+
# back via `Ractor.main.send`. The coordinator drains its mailbox via `Ractor.receive` until it has
|
|
207
|
+
# counted exactly `pool.size` `:done` messages.
|
|
244
208
|
#
|
|
245
|
-
# Diagnostic order: original path order. Workers may
|
|
246
|
-
#
|
|
247
|
-
# via the `results_by_path` Hash before flattening.
|
|
209
|
+
# Diagnostic order: original path order. Workers may complete files out of order; the coordinator
|
|
210
|
+
# re-orders via the `results_by_path` Hash before flattening.
|
|
248
211
|
#
|
|
249
|
-
# Reporter merge: per-worker `RbsExtended::Reporter` and
|
|
250
|
-
# `
|
|
251
|
-
#
|
|
252
|
-
#
|
|
253
|
-
# would. Net result: reporter state is identical to the
|
|
254
|
-
# sequential path.
|
|
212
|
+
# Reporter merge: per-worker `RbsExtended::Reporter` and `BoundaryCrossReporter` entries are
|
|
213
|
+
# replayed into the runner-side accumulators via their `record_*` APIs, which dedupe on the same
|
|
214
|
+
# keys as a single-session run would. Net result: reporter state is identical to the sequential
|
|
215
|
+
# path.
|
|
255
216
|
def analyze_files_in_pool(files) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
|
256
|
-
# Pre-warm class-level lazy memos on the MAIN Ractor.
|
|
257
|
-
# `Environment
|
|
258
|
-
#
|
|
259
|
-
#
|
|
260
|
-
# from a non-main Ractor would trip
|
|
261
|
-
# `Ractor::IsolationError`. Touching it here forces
|
|
262
|
-
# the (shareable) registry into the class-ivar cache
|
|
263
|
-
# before any worker reads.
|
|
217
|
+
# Pre-warm class-level lazy memos on the MAIN Ractor. `Environment::ClassRegistry.default` is the
|
|
218
|
+
# default kwarg threaded through `Environment.new` inside each worker session; lazy-initialising
|
|
219
|
+
# it from a non-main Ractor would trip `Ractor::IsolationError`. Touching it here forces the
|
|
220
|
+
# (shareable) registry into the class-ivar cache before any worker reads.
|
|
264
221
|
Environment::ClassRegistry.default
|
|
265
222
|
|
|
266
|
-
# ADR-15 Phase 4b.x — pre-warm the RBS cache so
|
|
267
|
-
#
|
|
268
|
-
#
|
|
269
|
-
#
|
|
270
|
-
#
|
|
271
|
-
#
|
|
272
|
-
# constants and raises `Ractor::IsolationError`.
|
|
273
|
-
# Pre-warming requires a `cache_store`; the run aborts
|
|
274
|
-
# to sequential mode otherwise. See ADR-15 Phase 4b.x
|
|
275
|
-
# for the full chain of failing constants.
|
|
223
|
+
# ADR-15 Phase 4b.x — pre-warm the RBS cache so workers serve every reflection query from the
|
|
224
|
+
# Marshal blob on disk. Without this, the first cache MISS inside a worker falls through to
|
|
225
|
+
# `RBS::EnvironmentLoader.new`, which reads a chain of non-`Ractor.shareable?` RubyGems / RBS
|
|
226
|
+
# module constants and raises `Ractor::IsolationError`. Pre-warming requires a `cache_store`; the
|
|
227
|
+
# run aborts to sequential mode otherwise. See ADR-15 Phase 4b.x for the full chain of failing
|
|
228
|
+
# constants.
|
|
276
229
|
if @cache_store.nil?
|
|
277
230
|
return analyze_files_sequentially_fallback(
|
|
278
231
|
files, reason: "pool mode requires a cache_store (--no-cache disables pool)"
|
|
@@ -284,11 +237,9 @@ module Rigor
|
|
|
284
237
|
cache_root = @cache_store&.root
|
|
285
238
|
blueprints = plugin_registry.blueprints
|
|
286
239
|
explain = @explain
|
|
287
|
-
# ADR-32 WD4 — the full project file list travels into
|
|
288
|
-
#
|
|
289
|
-
#
|
|
290
|
-
# env-build time. The list is a frozen Array<String>;
|
|
291
|
-
# cheaply shareable.
|
|
240
|
+
# ADR-32 WD4 — the full project file list travels into every Ractor worker so each worker's
|
|
241
|
+
# WorkerSession can invoke loaded plugins' source_rbs_synthesizers at env-build time. The list is
|
|
242
|
+
# a frozen Array<String>; cheaply shareable.
|
|
292
243
|
shareable_source_files = files.map { |path| path.to_s.dup.freeze }.freeze
|
|
293
244
|
|
|
294
245
|
pool = Array.new(@workers) do
|
|
@@ -340,22 +291,18 @@ module Rigor
|
|
|
340
291
|
Array(prepare_diagnostics) + files.flat_map { |path| results_by_path.fetch(path, []) }
|
|
341
292
|
end
|
|
342
293
|
|
|
343
|
-
# ADR-15 Amendment (2026-05-20) — fork-based worker pool, the
|
|
344
|
-
#
|
|
345
|
-
#
|
|
346
|
-
#
|
|
347
|
-
#
|
|
348
|
-
# temp file; the parent `Process.wait`s every child, merges the
|
|
349
|
-
# payloads, and re-orders diagnostics by original path order.
|
|
294
|
+
# ADR-15 Amendment (2026-05-20) — fork-based worker pool, the active backend for `workers > 0`.
|
|
295
|
+
# Builds ONE {WorkerSession} on the parent, then `fork`s N children that copy-on-write inherit it.
|
|
296
|
+
# Each child analyses a contiguous slice of `files` and writes a Marshal'd `{results:, reporters:}`
|
|
297
|
+
# payload to a temp file; the parent `Process.wait`s every child, merges the payloads, and re-orders
|
|
298
|
+
# diagnostics by original path order.
|
|
350
299
|
#
|
|
351
|
-
# Separate processes have separate GC heaps and `vm->ci_table`
|
|
352
|
-
#
|
|
353
|
-
#
|
|
354
|
-
# Amendment + docs/notes/20260520-ractor-pool-cruby-uaf.md.
|
|
300
|
+
# Separate processes have separate GC heaps and `vm->ci_table` (immune to Ruby Bug #22075) and
|
|
301
|
+
# copy-on-write-inherit every constant (no `Ractor.shareable?` constraint). See the ADR-15 Amendment
|
|
302
|
+
# + docs/notes/20260520-ractor-pool-cruby-uaf.md.
|
|
355
303
|
#
|
|
356
|
-
# A child that exits non-zero (crash / unmarshalable payload) is
|
|
357
|
-
#
|
|
358
|
-
# prepends a `pool-degraded` warning.
|
|
304
|
+
# A child that exits non-zero (crash / unmarshalable payload) is degraded: the parent re-analyses
|
|
305
|
+
# that slice in-process and prepends a `pool-degraded` warning.
|
|
359
306
|
def analyze_files_in_fork_pool(files) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
|
360
307
|
Environment::ClassRegistry.default
|
|
361
308
|
|
|
@@ -369,9 +316,8 @@ module Rigor
|
|
|
369
316
|
project_scope_seed: project_scope_seed,
|
|
370
317
|
source_files: files
|
|
371
318
|
)
|
|
372
|
-
# Force the full RBS load on the parent so children
|
|
373
|
-
#
|
|
374
|
-
# rebuilding it after the fork.
|
|
319
|
+
# Force the full RBS load on the parent so children copy-on-write inherit a warm Environment
|
|
320
|
+
# rather than each rebuilding it after the fork.
|
|
375
321
|
session.environment.rbs_loader&.prewarm
|
|
376
322
|
snapshot_fork_pool_stats(session) if @collect_stats
|
|
377
323
|
|
|
@@ -398,10 +344,9 @@ module Rigor
|
|
|
398
344
|
degraded.empty? ? diagnostics : diagnostics.unshift(fork_degraded_diagnostic(degraded.size))
|
|
399
345
|
end
|
|
400
346
|
|
|
401
|
-
# Child-process body for {#analyze_files_in_fork_pool}. Analyses
|
|
402
|
-
#
|
|
403
|
-
# the
|
|
404
|
-
# stdio flush — the payload is already durable on disk by then.
|
|
347
|
+
# Child-process body for {#analyze_files_in_fork_pool}. Analyses the slice with the
|
|
348
|
+
# copy-on-write-inherited session and writes the Marshal'd payload to `out_path`. `exit!` skips
|
|
349
|
+
# `at_exit` / stdio flush — the payload is already durable on disk by then.
|
|
405
350
|
def run_fork_worker(session, slice, out_path)
|
|
406
351
|
results = slice.to_h { |path| [path, session.analyze(path)] }
|
|
407
352
|
payload = { results: results, reporters: session.drain_reporters }
|
|
@@ -411,17 +356,16 @@ module Rigor
|
|
|
411
356
|
exit!(1)
|
|
412
357
|
end
|
|
413
358
|
|
|
414
|
-
# Snapshots `class_decl_paths` from the parent session's loader
|
|
415
|
-
#
|
|
359
|
+
# Snapshots `class_decl_paths` from the parent session's loader so end-of-run {RunStats} can
|
|
360
|
+
# attribute the RBS class universe.
|
|
416
361
|
def snapshot_fork_pool_stats(session)
|
|
417
362
|
loader = session.environment.rbs_loader
|
|
418
363
|
@snapshots.class_decl_paths = loader&.class_decl_paths || {}.freeze
|
|
419
364
|
@snapshots.signature_paths = loader&.signature_paths || [].freeze
|
|
420
365
|
end
|
|
421
366
|
|
|
422
|
-
# Waits for every forked child, merges each successful payload
|
|
423
|
-
#
|
|
424
|
-
# worker exited abnormally (for in-process degrade).
|
|
367
|
+
# Waits for every forked child, merges each successful payload into `results_by_path`, and returns
|
|
368
|
+
# the file paths whose worker exited abnormally (for in-process degrade).
|
|
425
369
|
def collect_fork_results(children, results_by_path)
|
|
426
370
|
degraded = []
|
|
427
371
|
children.each do |child|
|
|
@@ -437,10 +381,9 @@ module Rigor
|
|
|
437
381
|
degraded
|
|
438
382
|
end
|
|
439
383
|
|
|
440
|
-
# @return [Hash, nil] the child's `{results:, reporters:}`
|
|
441
|
-
#
|
|
442
|
-
#
|
|
443
|
-
# written by our own forked child to a temp file we created.
|
|
384
|
+
# @return [Hash, nil] the child's `{results:, reporters:}` payload, or nil when the child exited
|
|
385
|
+
# abnormally or wrote no readable payload. `Marshal.load` is safe here: the blob was written by
|
|
386
|
+
# our own forked child to a temp file we created.
|
|
444
387
|
def fork_worker_payload(status, out_path)
|
|
445
388
|
return nil unless status.success? && File.exist?(out_path)
|
|
446
389
|
|
|
@@ -458,15 +401,11 @@ module Rigor
|
|
|
458
401
|
)
|
|
459
402
|
end
|
|
460
403
|
|
|
461
|
-
# ADR-15 Phase 4b.x — drives every cached RBS producer
|
|
462
|
-
#
|
|
463
|
-
#
|
|
464
|
-
#
|
|
465
|
-
#
|
|
466
|
-
# after the cache is warm — workers build their own
|
|
467
|
-
# `Environment.for_project` inside the Ractor body,
|
|
468
|
-
# which then routes through `cached_env` instead of
|
|
469
|
-
# `RBS::EnvironmentLoader.new`.
|
|
404
|
+
# ADR-15 Phase 4b.x — drives every cached RBS producer on the main Ractor so each worker can serve
|
|
405
|
+
# all reflection queries from disk (Marshal-load only). Builds a single coordinator-side
|
|
406
|
+
# {Environment} for this purpose; the env object is discarded immediately after the cache is warm
|
|
407
|
+
# — workers build their own `Environment.for_project` inside the Ractor body, which then routes
|
|
408
|
+
# through `cached_env` instead of `RBS::EnvironmentLoader.new`.
|
|
470
409
|
def prewarm_rbs_cache_for_pool
|
|
471
410
|
warm_env = Environment.for_project(
|
|
472
411
|
libraries: @configuration.libraries,
|
|
@@ -481,14 +420,10 @@ module Rigor
|
|
|
481
420
|
warm_env.rbs_loader&.prewarm
|
|
482
421
|
end
|
|
483
422
|
|
|
484
|
-
# ADR-15 Phase 4b.x — pool-mode safety net. When pool
|
|
485
|
-
#
|
|
486
|
-
#
|
|
487
|
-
#
|
|
488
|
-
# analysis with a `:warning` `pool-degraded` diagnostic
|
|
489
|
-
# at run start. The actual per-file analysis runs on
|
|
490
|
-
# the coordinator, identical to the default sequential
|
|
491
|
-
# path.
|
|
423
|
+
# ADR-15 Phase 4b.x — pool-mode safety net. When pool mode is configured but a precondition fails
|
|
424
|
+
# (currently: `--no-cache` would force workers through `EnvironmentLoader.new`), degrade to
|
|
425
|
+
# sequential analysis with a `:warning` `pool-degraded` diagnostic at run start. The actual
|
|
426
|
+
# per-file analysis runs on the coordinator, identical to the default sequential path.
|
|
492
427
|
def analyze_files_sequentially_fallback(files, reason:)
|
|
493
428
|
environment = build_runner_environment
|
|
494
429
|
diagnostics = files.flat_map { |path| @analyze_file.call(path, environment) }
|
|
@@ -524,10 +459,8 @@ module Rigor
|
|
|
524
459
|
rbs_display: entry.rbs_display
|
|
525
460
|
)
|
|
526
461
|
end
|
|
527
|
-
# ADR-32 WD6 — merge per-worker synthesizer failures
|
|
528
|
-
#
|
|
529
|
-
# default empty array so older drains (pre-slice-2)
|
|
530
|
-
# remain compatible.
|
|
462
|
+
# ADR-32 WD6 — merge per-worker synthesizer failures back into the coordinator's reporter. Fetched
|
|
463
|
+
# with a default empty array so older drains (pre-slice-2) remain compatible.
|
|
531
464
|
Array(drained[:source_rbs_synthesis]).each do |entry|
|
|
532
465
|
@source_rbs_synthesis_reporter.record(
|
|
533
466
|
plugin_id: entry.plugin_id, path: entry.path, message: entry.message
|
|
@@ -537,8 +470,8 @@ module Rigor
|
|
|
537
470
|
|
|
538
471
|
private
|
|
539
472
|
|
|
540
|
-
# True when the project declares its own `signature_paths:` (the
|
|
541
|
-
#
|
|
473
|
+
# True when the project declares its own `signature_paths:` (the only place the
|
|
474
|
+
# qualified-name-without-namespace mistake lives).
|
|
542
475
|
def project_signature_paths?
|
|
543
476
|
paths = @configuration.signature_paths
|
|
544
477
|
!(paths.nil? || paths.empty?)
|