rigortype 0.4.6 → 0.4.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (417) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/data/gem_overlay/activesupport/core_ext.rbs +16 -13
  4. data/data/vendored_gem_sigs/bundler/bundler.rbs +1 -1
  5. data/data/vendored_gem_sigs/rubygems/rubygems_extras.rbs +4 -3
  6. data/docs/handbook/01-getting-started.md +5 -2
  7. data/docs/handbook/11-sig-gen.md +50 -3
  8. data/docs/handbook/appendix-phpstan.md +4 -4
  9. data/docs/manual/02-cli-reference.md +152 -26
  10. data/docs/manual/03-configuration.md +36 -3
  11. data/docs/manual/06-baseline.md +6 -4
  12. data/docs/manual/09-editor-integration.md +13 -2
  13. data/docs/manual/10-mcp-server.md +38 -2
  14. data/docs/manual/12-caching.md +4 -3
  15. data/docs/manual/plugins/rigor-actionpack.md +19 -11
  16. data/docs/manual/plugins/rigor-activesupport-core-ext.md +20 -1
  17. data/lib/rigor/analysis/baseline.rb +24 -27
  18. data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +5 -6
  19. data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +2 -2
  20. data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +4 -4
  21. data/lib/rigor/analysis/check_rules/duplicate_hash_key_collector.rb +2 -2
  22. data/lib/rigor/analysis/check_rules/inferred_param_guard.rb +85 -13
  23. data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +3 -2
  24. data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +0 -1
  25. data/lib/rigor/analysis/check_rules/main_pass_collector.rb +5 -8
  26. data/lib/rigor/analysis/check_rules/published_constant_guard.rb +1 -1
  27. data/lib/rigor/analysis/check_rules/rebinding_block_callees.rb +3 -3
  28. data/lib/rigor/analysis/check_rules/return_in_ensure_collector.rb +1 -2
  29. data/lib/rigor/analysis/check_rules/rule_ids.rb +1 -1
  30. data/lib/rigor/analysis/check_rules/rule_walk.rb +9 -7
  31. data/lib/rigor/analysis/check_rules/shadowed_rescue_collector.rb +3 -4
  32. data/lib/rigor/analysis/check_rules/special_global_setters.rb +3 -3
  33. data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +2 -2
  34. data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +1 -1
  35. data/lib/rigor/analysis/check_rules.rb +124 -44
  36. data/lib/rigor/analysis/crash_signature.rb +2 -2
  37. data/lib/rigor/analysis/dependency_recorder.rb +4 -4
  38. data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +14 -3
  39. data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +1 -1
  40. data/lib/rigor/analysis/dependency_source_inference/index.rb +6 -8
  41. data/lib/rigor/analysis/dependency_source_inference/walker.rb +4 -4
  42. data/lib/rigor/analysis/edit_replay.rb +93 -6
  43. data/lib/rigor/analysis/fact_store.rb +3 -3
  44. data/lib/rigor/analysis/incremental_run_slot/write_guard.rb +2 -2
  45. data/lib/rigor/analysis/incremental_run_slot.rb +2 -2
  46. data/lib/rigor/analysis/incremental_session.rb +27 -16
  47. data/lib/rigor/analysis/rule_catalog.rb +2 -2
  48. data/lib/rigor/analysis/run_stats.rb +2 -2
  49. data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +2 -2
  50. data/lib/rigor/analysis/runner/declaration_position.rb +1 -1
  51. data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +193 -93
  52. data/lib/rigor/analysis/runner/effect_envelope_pass.rb +1 -1
  53. data/lib/rigor/analysis/runner/pool_coordinator.rb +147 -323
  54. data/lib/rigor/analysis/runner/project_pre_passes.rb +3 -3
  55. data/lib/rigor/analysis/runner/run_level_facts.rb +304 -0
  56. data/lib/rigor/analysis/runner/run_snapshots.rb +44 -54
  57. data/lib/rigor/analysis/runner/worker_payload.rb +36 -0
  58. data/lib/rigor/analysis/runner.rb +77 -71
  59. data/lib/rigor/analysis/self_call_resolution_recorder.rb +1 -1
  60. data/lib/rigor/analysis/template_unit_positions.rb +2 -3
  61. data/lib/rigor/analysis/template_units.rb +9 -1
  62. data/lib/rigor/analysis/worker_session.rb +24 -31
  63. data/lib/rigor/bleeding_edge.rb +3 -6
  64. data/lib/rigor/builtins/imported_refinements.rb +6 -8
  65. data/lib/rigor/builtins/predefined_constant_refinements.rb +1 -1
  66. data/lib/rigor/builtins/regex_refinement.rb +4 -6
  67. data/lib/rigor/cache/descriptor.rb +6 -5
  68. data/lib/rigor/cache/incremental_snapshot.rb +31 -12
  69. data/lib/rigor/cache/rbs_cache_producer.rb +2 -2
  70. data/lib/rigor/cache/rbs_class_ancestor_table.rb +1 -1
  71. data/lib/rigor/cache/rbs_class_type_param_names.rb +2 -2
  72. data/lib/rigor/cache/rbs_constant_table.rb +1 -1
  73. data/lib/rigor/cache/rbs_descriptor.rb +54 -3
  74. data/lib/rigor/cache/rbs_environment.rb +4 -1
  75. data/lib/rigor/cache/rbs_environment_marshal_patch.rb +2 -2
  76. data/lib/rigor/cache/rbs_known_class_names.rb +1 -1
  77. data/lib/rigor/cache/store.rb +11 -10
  78. data/lib/rigor/ci_detector.rb +1 -1
  79. data/lib/rigor/cli/annotate_command.rb +24 -19
  80. data/lib/rigor/cli/baseline_command.rb +145 -55
  81. data/lib/rigor/cli/catalogue.rb +256 -0
  82. data/lib/rigor/cli/check_command.rb +108 -102
  83. data/lib/rigor/cli/check_runner_factory.rb +2 -2
  84. data/lib/rigor/cli/command.rb +15 -1
  85. data/lib/rigor/cli/coverage_command.rb +21 -8
  86. data/lib/rigor/cli/coverage_mutation.rb +5 -7
  87. data/lib/rigor/cli/coverage_renderer.rb +2 -1
  88. data/lib/rigor/cli/coverage_scan.rb +3 -5
  89. data/lib/rigor/cli/diff_command.rb +25 -20
  90. data/lib/rigor/cli/docs_command.rb +1 -2
  91. data/lib/rigor/cli/doctor_command.rb +12 -12
  92. data/lib/rigor/cli/effects_command.rb +50 -40
  93. data/lib/rigor/cli/effects_diff_renderer.rb +18 -17
  94. data/lib/rigor/cli/effects_explain_renderer.rb +13 -12
  95. data/lib/rigor/cli/effects_renderer.rb +2 -1
  96. data/lib/rigor/cli/effects_snapshot_command.rb +18 -17
  97. data/lib/rigor/cli/explain_command.rb +18 -8
  98. data/lib/rigor/cli/fused_protection_renderer.rb +2 -1
  99. data/lib/rigor/cli/json_document.rb +41 -0
  100. data/lib/rigor/cli/lens_command.rb +12 -8
  101. data/lib/rigor/cli/lsp_command.rb +250 -23
  102. data/lib/rigor/cli/mcp_command.rb +12 -7
  103. data/lib/rigor/cli/mutation_fork_scan.rb +1 -1
  104. data/lib/rigor/cli/mutation_protection_renderer.rb +3 -2
  105. data/lib/rigor/cli/options.rb +40 -1
  106. data/lib/rigor/cli/plugin_command.rb +93 -46
  107. data/lib/rigor/cli/plugins_command.rb +17 -18
  108. data/lib/rigor/cli/plugins_renderer.rb +10 -6
  109. data/lib/rigor/cli/protection_fork_scan.rb +2 -2
  110. data/lib/rigor/cli/protection_renderer.rb +2 -1
  111. data/lib/rigor/cli/show_bleedingedge_command.rb +21 -15
  112. data/lib/rigor/cli/sig_gen_command.rb +84 -27
  113. data/lib/rigor/cli/skill_command.rb +32 -3
  114. data/lib/rigor/cli/skill_deep_probe.rb +1 -1
  115. data/lib/rigor/cli/skill_describe.rb +1 -1
  116. data/lib/rigor/cli/trace_command.rb +14 -9
  117. data/lib/rigor/cli/triage_command.rb +10 -11
  118. data/lib/rigor/cli/triage_renderer.rb +2 -1
  119. data/lib/rigor/cli/type_of_command.rb +16 -11
  120. data/lib/rigor/cli/type_of_project_scope.rb +1 -4
  121. data/lib/rigor/cli/type_of_renderer.rb +4 -1
  122. data/lib/rigor/cli/type_scan_command.rb +14 -9
  123. data/lib/rigor/cli/type_scan_renderer.rb +2 -1
  124. data/lib/rigor/cli/unused_command.rb +27 -17
  125. data/lib/rigor/cli/upgrade_command.rb +5 -0
  126. data/lib/rigor/cli.rb +209 -54
  127. data/lib/rigor/config_audit.rb +1 -1
  128. data/lib/rigor/configuration/severity_profile.rb +5 -5
  129. data/lib/rigor/configuration.rb +72 -30
  130. data/lib/rigor/effects/definition_context.rb +0 -2
  131. data/lib/rigor/effects/envelope.rb +1 -1
  132. data/lib/rigor/effects/framework_units.rb +1 -1
  133. data/lib/rigor/effects/mutation_classifier.rb +4 -7
  134. data/lib/rigor/effects/propagator.rb +1 -1
  135. data/lib/rigor/effects/registry.rb +2 -2
  136. data/lib/rigor/effects/snapshot.rb +1 -1
  137. data/lib/rigor/effects/taint_cause.rb +0 -2
  138. data/lib/rigor/effects/unit_scan.rb +9 -13
  139. data/lib/rigor/environment/bundle_sig_discovery.rb +5 -9
  140. data/lib/rigor/environment/class_registry.rb +3 -3
  141. data/lib/rigor/environment/core_root.rb +77 -0
  142. data/lib/rigor/environment/default_libraries.rb +1 -1
  143. data/lib/rigor/environment/deferred_signature_plan.rb +283 -0
  144. data/lib/rigor/environment/gated_signature_guard.rb +1 -1
  145. data/lib/rigor/environment/gated_signature_plan.rb +5 -2
  146. data/lib/rigor/environment/lockfile_resolver.rb +28 -12
  147. data/lib/rigor/environment/member_consistency/comparator.rb +18 -1
  148. data/lib/rigor/environment/member_consistency.rb +56 -7
  149. data/lib/rigor/environment/missing_gem_constant_index.rb +3 -2
  150. data/lib/rigor/environment/project_path_gems.rb +124 -0
  151. data/lib/rigor/environment/rbs_hierarchy.rb +6 -15
  152. data/lib/rigor/environment/rbs_loader.rb +480 -67
  153. data/lib/rigor/environment/reflection.rb +7 -7
  154. data/lib/rigor/environment/required_features.rb +0 -3
  155. data/lib/rigor/environment/ruby_library_roots.rb +1 -1
  156. data/lib/rigor/environment/vendored_signature_plan.rb +153 -0
  157. data/lib/rigor/environment.rb +41 -10
  158. data/lib/rigor/flow_contribution/merger.rb +4 -4
  159. data/lib/rigor/inference/acceptance.rb +93 -32
  160. data/lib/rigor/inference/block_parameter_binder.rb +2 -3
  161. data/lib/rigor/inference/block_run_count.rb +178 -0
  162. data/lib/rigor/inference/budget_trace.rb +8 -2
  163. data/lib/rigor/inference/builtins/exception_catalog.rb +2 -2
  164. data/lib/rigor/inference/builtins/numeric_catalog.rb +2 -5
  165. data/lib/rigor/inference/builtins/random_catalog.rb +2 -2
  166. data/lib/rigor/inference/callee_mutation_chain.rb +88 -77
  167. data/lib/rigor/inference/callee_write_census.rb +815 -0
  168. data/lib/rigor/inference/construction_escape.rb +217 -0
  169. data/lib/rigor/inference/declaration_walk/traversal.rb +1 -1
  170. data/lib/rigor/inference/deep_erasure.rb +39 -7
  171. data/lib/rigor/inference/def_handle.rb +1 -1
  172. data/lib/rigor/inference/def_node_resolver.rb +1 -1
  173. data/lib/rigor/inference/def_return_typer.rb +46 -4
  174. data/lib/rigor/inference/definer_resolution.rb +4 -2
  175. data/lib/rigor/inference/definers_index.rb +106 -0
  176. data/lib/rigor/inference/direct_ivar_writes.rb +300 -0
  177. data/lib/rigor/inference/element_read_widening.rb +49 -3
  178. data/lib/rigor/inference/expression_typer.rb +116 -49
  179. data/lib/rigor/inference/external_ancestor_resolution.rb +3 -4
  180. data/lib/rigor/inference/global_write_census.rb +76 -2
  181. data/lib/rigor/inference/global_writer_reach.rb +260 -0
  182. data/lib/rigor/inference/hkt_body.rb +1 -2
  183. data/lib/rigor/inference/hkt_body_parser.rb +3 -5
  184. data/lib/rigor/inference/hkt_reducer.rb +2 -2
  185. data/lib/rigor/inference/hkt_registry.rb +3 -5
  186. data/lib/rigor/inference/indexed_narrowing.rb +4 -7
  187. data/lib/rigor/inference/intervening_ivar_reset.rb +26 -4
  188. data/lib/rigor/inference/ivar_writer_census.rb +51 -0
  189. data/lib/rigor/inference/key_presence_guard.rb +2 -1
  190. data/lib/rigor/inference/loop_value_record.rb +8 -4
  191. data/lib/rigor/inference/match_rebinding/frame.rb +46 -0
  192. data/lib/rigor/inference/match_rebinding/yielding_match.rb +45 -0
  193. data/lib/rigor/inference/match_rebinding.rb +11 -1
  194. data/lib/rigor/inference/memo_audit.rb +55 -0
  195. data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +1 -1
  196. data/lib/rigor/inference/method_dispatcher/argument_distribution.rb +40 -0
  197. data/lib/rigor/inference/method_dispatcher/block_folding.rb +1 -1
  198. data/lib/rigor/inference/method_dispatcher/constant_folding.rb +3 -3
  199. data/lib/rigor/inference/method_dispatcher/contested_overloads.rb +89 -0
  200. data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +1 -1
  201. data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +1 -1
  202. data/lib/rigor/inference/method_dispatcher/no_match_fallback.rb +54 -0
  203. data/lib/rigor/inference/method_dispatcher/overload_selector.rb +39 -27
  204. data/lib/rigor/inference/method_dispatcher/random_folding.rb +1 -1
  205. data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +203 -17
  206. data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +1 -1
  207. data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +2 -2
  208. data/lib/rigor/inference/method_dispatcher/self_substitute.rb +2 -2
  209. data/lib/rigor/inference/method_dispatcher/set_folding.rb +9 -7
  210. data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +83 -20
  211. data/lib/rigor/inference/method_dispatcher/singleton_folding.rb +0 -1
  212. data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +50 -17
  213. data/lib/rigor/inference/method_dispatcher/struct_folding.rb +5 -5
  214. data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +4 -6
  215. data/lib/rigor/inference/method_dispatcher/uri_folding.rb +1 -1
  216. data/lib/rigor/inference/method_dispatcher.rb +64 -14
  217. data/lib/rigor/inference/module_function_state.rb +11 -1
  218. data/lib/rigor/inference/multi_target_binder.rb +1 -1
  219. data/lib/rigor/inference/mutation_rejoin.rb +240 -4
  220. data/lib/rigor/inference/mutation_widening.rb +157 -27
  221. data/lib/rigor/inference/narrowing.rb +47 -33
  222. data/lib/rigor/inference/optimistic_origin.rb +1 -1
  223. data/lib/rigor/inference/out_buffer_mutation.rb +72 -0
  224. data/lib/rigor/inference/parameter_inference_collector.rb +5 -6
  225. data/lib/rigor/inference/pre_eval_constants.rb +1 -1
  226. data/lib/rigor/inference/project_method_ownership.rb +6 -3
  227. data/lib/rigor/inference/project_yielder.rb +11 -17
  228. data/lib/rigor/inference/receiver_alias.rb +20 -0
  229. data/lib/rigor/inference/refined_dispatch/constructed_class.rb +3 -1
  230. data/lib/rigor/inference/refined_dispatch/own_method.rb +2 -1
  231. data/lib/rigor/inference/remover_holder_scan.rb +233 -0
  232. data/lib/rigor/inference/remover_narrowing.rb +224 -0
  233. data/lib/rigor/inference/rewrite_mutation.rb +53 -2
  234. data/lib/rigor/inference/scope_indexer/certainty.rb +0 -1
  235. data/lib/rigor/inference/scope_indexer/constant_ivar_value.rb +93 -0
  236. data/lib/rigor/inference/scope_indexer/declared_param_writes.rb +58 -15
  237. data/lib/rigor/inference/scope_indexer/derived_param_value.rb +112 -0
  238. data/lib/rigor/inference/scope_indexer/empty_seed.rb +99 -0
  239. data/lib/rigor/inference/scope_indexer/ivar_contributions.rb +135 -0
  240. data/lib/rigor/inference/scope_indexer.rb +137 -46
  241. data/lib/rigor/inference/self_call_ivar_writes.rb +84 -12
  242. data/lib/rigor/inference/set_mutation.rb +189 -0
  243. data/lib/rigor/inference/singleton_hook_decline.rb +1 -2
  244. data/lib/rigor/inference/statement_evaluator.rb +2328 -138
  245. data/lib/rigor/inference/struct_fold_safety.rb +4 -6
  246. data/lib/rigor/inference/synthetic_method_scanner.rb +5 -6
  247. data/lib/rigor/inference/toplevel_def_census.rb +59 -0
  248. data/lib/rigor/inference/unknown_store_widening.rb +103 -4
  249. data/lib/rigor/inference/unthreaded_rebinds.rb +2 -3
  250. data/lib/rigor/inference/void_tail_summary.rb +2 -1
  251. data/lib/rigor/language_server/buffer_table.rb +3 -3
  252. data/lib/rigor/language_server/completion_provider.rb +26 -20
  253. data/lib/rigor/language_server/config_warning_announcer.rb +28 -0
  254. data/lib/rigor/language_server/diagnostic_publisher.rb +8 -3
  255. data/lib/rigor/language_server/document_symbol_provider.rb +1 -1
  256. data/lib/rigor/language_server/folding_range_provider.rb +1 -2
  257. data/lib/rigor/language_server/hover_provider.rb +1 -7
  258. data/lib/rigor/language_server/hover_renderer.rb +6 -8
  259. data/lib/rigor/language_server/project_context.rb +39 -1
  260. data/lib/rigor/language_server/publish_batcher.rb +3 -4
  261. data/lib/rigor/language_server/selection_range_provider.rb +2 -4
  262. data/lib/rigor/language_server/server.rb +7 -3
  263. data/lib/rigor/language_server/signature_help_provider.rb +4 -4
  264. data/lib/rigor/lens/plugins.rb +1 -1
  265. data/lib/rigor/mcp/server.rb +73 -2
  266. data/lib/rigor/mcp.rb +1 -1
  267. data/lib/rigor/plugin/access_denied_error.rb +1 -2
  268. data/lib/rigor/plugin/bundled_catalog.rb +1 -12
  269. data/lib/rigor/plugin/io_boundary.rb +1 -1
  270. data/lib/rigor/plugin/loader.rb +25 -8
  271. data/lib/rigor/plugin/macro/heredoc_template.rb +7 -8
  272. data/lib/rigor/plugin/macro/trait_registry.rb +6 -9
  273. data/lib/rigor/plugin/manifest.rb +9 -13
  274. data/lib/rigor/plugin/registry.rb +3 -3
  275. data/lib/rigor/plugin/services.rb +2 -3
  276. data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +11 -0
  277. data/lib/rigor/plugin/trust_policy.rb +2 -2
  278. data/lib/rigor/plugin/type_node_resolver.rb +2 -4
  279. data/lib/rigor/plugin.rb +6 -8
  280. data/lib/rigor/plugin_gap_advisory.rb +5 -1
  281. data/lib/rigor/project_environment.rb +16 -2
  282. data/lib/rigor/protection/analysis_guard.rb +1 -1
  283. data/lib/rigor/protection/discovery_seed.rb +44 -5
  284. data/lib/rigor/protection/mutator.rb +1 -1
  285. data/lib/rigor/rbs_extended/envelope_scanner.rb +4 -6
  286. data/lib/rigor/rbs_extended/hkt_directives.rb +6 -10
  287. data/lib/rigor/rbs_extended/reporter.rb +27 -3
  288. data/lib/rigor/rbs_extended.rb +2 -3
  289. data/lib/rigor/reflection/constant_ancestors.rb +5 -3
  290. data/lib/rigor/rooted_glob.rb +15 -1
  291. data/lib/rigor/run_scoped_slots.rb +38 -0
  292. data/lib/rigor/runtime/jit.rb +1 -1
  293. data/lib/rigor/scope/discovery_index.rb +19 -6
  294. data/lib/rigor/scope/resolution_chain.rb +3 -1
  295. data/lib/rigor/scope.rb +365 -31
  296. data/lib/rigor/sig_gen/classification.rb +4 -0
  297. data/lib/rigor/sig_gen/effect_annotation.rb +3 -3
  298. data/lib/rigor/sig_gen/generator.rb +371 -58
  299. data/lib/rigor/sig_gen/generic_header_scan.rb +189 -0
  300. data/lib/rigor/sig_gen/inline_declarations.rb +2 -2
  301. data/lib/rigor/sig_gen/layout_index.rb +3 -3
  302. data/lib/rigor/sig_gen/method_candidate.rb +23 -4
  303. data/lib/rigor/sig_gen/observation_collector.rb +3 -5
  304. data/lib/rigor/sig_gen/observed_call.rb +1 -1
  305. data/lib/rigor/sig_gen/path_mapper.rb +6 -0
  306. data/lib/rigor/sig_gen/renderer.rb +15 -9
  307. data/lib/rigor/sig_gen/skip_reason_catalog.rb +15 -2
  308. data/lib/rigor/sig_gen/type_name_qualification.rb +69 -0
  309. data/lib/rigor/sig_gen/write_reporter.rb +63 -14
  310. data/lib/rigor/sig_gen/write_result.rb +23 -12
  311. data/lib/rigor/sig_gen/writer.rb +217 -37
  312. data/lib/rigor/type/acceptance_router.rb +2 -2
  313. data/lib/rigor/type/accepts_result.rb +1 -1
  314. data/lib/rigor/type/app.rb +4 -6
  315. data/lib/rigor/type/combinator.rb +9 -13
  316. data/lib/rigor/type/constant.rb +4 -5
  317. data/lib/rigor/type/hash_shape.rb +21 -40
  318. data/lib/rigor/type/union.rb +1 -1
  319. data/lib/rigor/type_node/identifier.rb +1 -2
  320. data/lib/rigor/type_node/resolver_chain.rb +1 -1
  321. data/lib/rigor/type_node/string_literal.rb +1 -2
  322. data/lib/rigor/type_node/symbol_literal.rb +1 -2
  323. data/lib/rigor/type_node/union.rb +3 -6
  324. data/lib/rigor/value_semantics.rb +1 -10
  325. data/lib/rigor/version.rb +1 -1
  326. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +2 -2
  327. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +2 -3
  328. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +1 -1
  329. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +38 -36
  330. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +4 -2
  331. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +6 -4
  332. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +1 -1
  333. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +1 -5
  334. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_scan.rb +0 -1
  335. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/erb_compiler.rb +2 -1
  336. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +1 -1
  337. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +66 -19
  338. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +1 -1
  339. data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +4 -3
  340. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/association_roots.rb +3 -2
  341. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/effects.rb +2 -2
  342. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +21 -31
  343. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +10 -16
  344. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +2 -3
  345. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +0 -1
  346. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +5 -4
  347. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +3 -4
  348. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +1 -1
  349. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +7 -12
  350. data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +1 -1
  351. data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +1 -1
  352. data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/symbolize_keys.rb +102 -0
  353. data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +19 -6
  354. data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +26 -13
  355. data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_index.rb +3 -3
  356. data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +1 -3
  357. data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +6 -6
  358. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +5 -6
  359. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +1 -1
  360. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/params_shape.rb +2 -3
  361. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +5 -8
  362. data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +0 -1
  363. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +1 -1
  364. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +10 -18
  365. data/plugins/rigor-ffi/lib/rigor/plugin/ffi/analyzer.rb +0 -1
  366. data/plugins/rigor-ffi/lib/rigor/plugin/ffi/discoverer.rb +0 -2
  367. data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +4 -5
  368. data/plugins/rigor-grape/lib/rigor/plugin/grape.rb +0 -2
  369. data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +6 -7
  370. data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +2 -4
  371. data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +2 -5
  372. data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +2 -2
  373. data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +6 -6
  374. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +2 -1
  375. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +3 -8
  376. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +2 -3
  377. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +5 -8
  378. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +1 -3
  379. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +2 -3
  380. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +1 -1
  381. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +4 -11
  382. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +1 -1
  383. data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +2 -1
  384. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +1 -1
  385. data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +2 -2
  386. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +3 -4
  387. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +6 -8
  388. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +3 -2
  389. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +4 -5
  390. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +6 -7
  391. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +1 -1
  392. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +2 -2
  393. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +17 -21
  394. data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +2 -3
  395. data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_discoverer.rb +3 -2
  396. data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_index.rb +4 -4
  397. data/sig/rigor/analysis/baseline.rbs +0 -3
  398. data/sig/rigor/analysis/fact_store.rbs +1 -0
  399. data/sig/rigor/analysis/reachability/scan_cache.rbs +1 -1
  400. data/sig/rigor/cli/diff_command.rbs +1 -1
  401. data/sig/rigor/cli/explain_command.rbs +1 -1
  402. data/sig/rigor/effects/registry.rbs +2 -2
  403. data/sig/rigor/inference.rbs +4 -1
  404. data/sig/rigor/plugin/additional_initializer.rbs +0 -5
  405. data/sig/rigor/plugin/base.rbs +1 -0
  406. data/sig/rigor/plugin/effect_attribution.rbs +3 -3
  407. data/sig/rigor/plugin/effect_edge.rbs +1 -1
  408. data/sig/rigor/plugin/effect_entry_points.rbs +3 -3
  409. data/sig/rigor/plugin/io_boundary.rbs +2 -1
  410. data/sig/rigor/plugin/manifest.rbs +9 -9
  411. data/sig/rigor/plugin/protocol_contract.rbs +3 -7
  412. data/sig/rigor/scope.rbs +23 -3
  413. data/skills/rigor-plugin-author/SKILL.md +4 -4
  414. data/skills/rigor-plugin-author/references/02-walker-and-types.md +5 -5
  415. data/skills/rigor-plugin-review/SKILL.md +3 -3
  416. data/skills/rigor-project-init/references/03-baseline-and-bugs.md +12 -1
  417. metadata +36 -3
@@ -29,35 +29,24 @@ module Rigor
29
29
  # @param pool_mode — reader returning the pool-mode flag.
30
30
  # @param cached_plugin_prepare_diagnostics — reader returning the prepare-diagnostic snapshot.
31
31
  # @param pre_eval_diagnostics_from_scanner — reader returning the pre-eval scanner diagnostics.
32
- # @param synthesized_namespaces_snapshot — reader.
33
- # @param quarantined_signatures_snapshot — reader returning the `signature_paths:` files skipped
34
- # because they do not parse (`[path, first_error_line]` pairs).
35
- # @param signature_standdowns_snapshot — reader returning the plugin-contributed signature files
36
- # that stood down against a colliding generic arity (#610), as
37
- # `[path, class_name, existing_arity, incoming_arity, existing_file]` tuples. Defaults to none so
38
- # a caller that snapshots nothing of the kind need not say so.
39
- # @param vendored_standdowns_snapshot — issue #1713 — reader returning what each required-feature-gated
40
- # vendored directory left out (`Environment::RbsLoader#vendored_standdowns`). Defaults to none.
41
- # @param env_build_failure_snapshot — reader returning the total RBS env-build failure tuple
42
- # (`[error_class, first_error_line, conflicting_buffer_names]`) or nil when the env built.
43
- # @param definition_build_failures_snapshot — issue #696 — reader returning the per-class
44
- # `RBS::DefinitionBuilder` failures the run observed, as `[class_name, error_class, member,
45
- # conflicting_buffer_names, unresolved_type_name_detail]` tuples (issue #997 added the fifth
46
- # element — `[token, location, refinement_hint]`, `nil` unless `error_class` is
47
- # `RBS::NoTypeFoundError`). Empty for a healthy sig set.
48
- # @param hkt_scan_failure_snapshot — issue #784 — reader returning the `[error_class_name,
49
- # first_message_line, raw_frame_or_nil, stage]` tuple whichever stage of the HKT-registry build
50
- # raised, or nil when both built (or were never demanded). `stage` is `:scan` (the RBS `type`-alias
51
- # scan) or `:overlay` (the plugin-manifest aggregation, #791), and picks the row's wording.
52
- # @param conformance_results_snapshot — reader.
32
+ # @param snapshots — the run's {RunSnapshots} store (ADR-116 WD3), read at row-build time. Its slots'
33
+ # shapes, as the rows below read them:
34
+ # - `quarantined_signatures` — the `signature_paths:` files skipped because they do not parse
35
+ # (`[path, first_error_line]` pairs);
36
+ # - `signature_standdowns` (#610) — `[path, class_name, existing_arity, incoming_arity,
37
+ # existing_file]` tuples, then (#2422) `[path, declaration, nil, nil, cause_file, :member]` ones;
38
+ # - `vendored_standdowns` (#1713) — `Environment::RbsLoader#vendored_standdowns`;
39
+ # - `env_build_failure` — `[error_class, first_error_line, conflicting_buffer_names]`, or nil;
40
+ # - `definition_build_failures` (#696) — `[class_name, error_class, member,
41
+ # conflicting_buffer_names, unresolved_type_name_detail, mixin_count]` tuples (#997 added the fifth
42
+ # element — `[token, location, refinement_hint]`, `nil` unless `error_class` is
43
+ # `RBS::NoTypeFoundError`; #2440 the sixth, {Environment::RbsLoader#variable_mixin_count});
44
+ # - `hkt_scan_failure` (#784) — `[error_class_name, first_message_line, raw_frame_or_nil, stage]`,
45
+ # or nil; `stage` is `:scan` or `:overlay` (#791) and picks the row's wording.
53
46
  def initialize(configuration:, rbs_extended_reporter:, boundary_cross_reporter:, # rubocop:disable Metrics/ParameterLists
54
47
  source_rbs_synthesis_reporter:, plugin_registry:, dependency_source_index:,
55
48
  pool_mode:, cached_plugin_prepare_diagnostics:,
56
- pre_eval_diagnostics_from_scanner:, synthesized_namespaces_snapshot:,
57
- quarantined_signatures_snapshot:, env_build_failure_snapshot:,
58
- definition_build_failures_snapshot:, hkt_scan_failure_snapshot:,
59
- conformance_results_snapshot:, signature_standdowns_snapshot: -> { [] },
60
- vendored_standdowns_snapshot: -> { [] }, pooled_run_disclosures: -> { [] },
49
+ pre_eval_diagnostics_from_scanner:, snapshots:, pooled_run_disclosures: -> { [] },
61
50
  served_run_disclosures: -> { [] }, pooled_trust_refusals: -> { [] })
62
51
  @configuration = configuration
63
52
  @rbs_extended_reporter = rbs_extended_reporter
@@ -68,14 +57,7 @@ module Rigor
68
57
  @pool_mode_reader = pool_mode
69
58
  @cached_plugin_prepare_diagnostics_reader = cached_plugin_prepare_diagnostics
70
59
  @pre_eval_diagnostics_from_scanner_reader = pre_eval_diagnostics_from_scanner
71
- @synthesized_namespaces_snapshot_reader = synthesized_namespaces_snapshot
72
- @quarantined_signatures_snapshot_reader = quarantined_signatures_snapshot
73
- @signature_standdowns_snapshot_reader = signature_standdowns_snapshot
74
- @vendored_standdowns_snapshot_reader = vendored_standdowns_snapshot
75
- @env_build_failure_snapshot_reader = env_build_failure_snapshot
76
- @definition_build_failures_snapshot_reader = definition_build_failures_snapshot
77
- @hkt_scan_failure_snapshot_reader = hkt_scan_failure_snapshot
78
- @conformance_results_snapshot_reader = conformance_results_snapshot
60
+ @snapshots = snapshots
79
61
  # Issue #1051 — reader for the pool coordinator's de-duplicated run-scoped disclosure table.
80
62
  # Empty on a sequential run, where `plugin_registry`'s own instances are the ones that registered.
81
63
  @pooled_run_disclosures_reader = pooled_run_disclosures
@@ -86,6 +68,14 @@ module Rigor
86
68
  @pooled_trust_refusals_reader = pooled_trust_refusals
87
69
  end
88
70
 
71
+ # ADR-116 WD3 — every post-analysis run-level row, in the contract order {RunLevelFacts.row_builders}
72
+ # declares: the `rbs.coverage.*` build-failure ladder widest consequence first, its `:info` notices,
73
+ # the conformance rows, the reporter streams, then the plugin run disclosures and the trust-refusal
74
+ # envelope, read last so every per-file plugin call has recorded its refusals.
75
+ def run_level_diagnostics
76
+ RunLevelFacts.row_builders.flat_map { |builder| public_send(builder) }
77
+ end
78
+
89
79
  # Pre-file diagnostic streams that fire once per run rather than per analyzed file: plugin load /
90
80
  # prepare envelopes, the ADR-10 dependency-source resolution surface, and the `expand_paths` errors
91
81
  # for `paths:` entries that don't exist or aren't `.rb`. Aggregated here so `#run` stays under the
@@ -94,9 +84,9 @@ module Rigor
94
84
  # ADR-15 Phase 4b — `plugin_prepare_diagnostics` runs on the coordinator's plugin registry under
95
85
  # sequential mode; under pool mode each worker re-runs `prepare` against its own plugin instances,
96
86
  # so the pool path drains the first worker's prepare-diagnostic snapshot into the aggregated
97
- # diagnostic stream instead (see {#analyze_files_in_pool}). Skipping the coordinator prepare in pool
98
- # mode avoids double-running `#prepare` against the coordinator-side plugin instances (which the
99
- # pool path never consults for per-file analysis).
87
+ # diagnostic stream instead (see {PoolCoordinator#analyze_files_in_pool}). Skipping the coordinator
88
+ # prepare in pool mode avoids double-running `#prepare` against the coordinator-side plugin instances
89
+ # (which the pool path never consults for per-file analysis).
100
90
  def pre_file_diagnostics(expansion)
101
91
  # ADR-18 slice 3 — prepare diagnostics are captured earlier in #run (before the synthetic-method
102
92
  # scanner) so cross-plugin facts are available to the scanner. We re-surface the captured
@@ -271,6 +261,9 @@ module Rigor
271
261
  project_root: Dir.pwd,
272
262
  auto_detect: @configuration.bundler_auto_detect
273
263
  )
264
+ # Issue #2441 — the project's own path gems are not dependencies missing RBS; the environment skips
265
+ # their collection copy, so the same set leaves the report here.
266
+ locked = locked.except(*project_own_gem_names(locked))
274
267
  return [] if locked.empty?
275
268
 
276
269
  bundle_sig_paths = Environment::BundleSigDiscovery.discover(
@@ -296,6 +289,16 @@ module Rigor
296
289
  [build_rbs_coverage_missing_diagnostic(missing)]
297
290
  end
298
291
 
292
+ # Issue #2441 — the same project-own set `Environment.for_project` skips the collection copy of.
293
+ def project_own_gem_names(locked)
294
+ Environment::ProjectPathGems.names(
295
+ locked,
296
+ paths: @configuration.paths, root: Dir.pwd,
297
+ exclude_patterns: @configuration.exclude_patterns, exclude_base: @configuration.exclude_base
298
+ )
299
+ end
300
+ private :project_own_gem_names
301
+
299
302
  # ADR-93 WD3 — the standalone residual. A bare `gem install rigortype` has no `rbs-inline` library,
300
303
  # so the spec's "annotations are official type sources whenever present" cannot be satisfied: the
301
304
  # annotated code reads `Dynamic[top]`. When the library is absent AND the project actually carries
@@ -379,7 +382,7 @@ module Rigor
379
382
  # the `reject-unparseable-signatures` feature promotes this rule to `:error` for anyone who opts in
380
383
  # (and by default at the next major).
381
384
  def rbs_quarantined_signature_diagnostics
382
- quarantined = quarantined_signatures_snapshot
385
+ quarantined = @snapshots[:quarantined_signatures]
383
386
  return [] if quarantined.empty?
384
387
 
385
388
  [build_rbs_quarantined_signature_diagnostic(quarantined)]
@@ -400,7 +403,7 @@ module Rigor
400
403
  # `reject-unparseable-signatures` bleeding-edge feature promotes it to `:error` for anyone who opts in
401
404
  # (and by default at the next major).
402
405
  def rbs_environment_build_failed_diagnostics
403
- failure = env_build_failure_snapshot
406
+ failure = @snapshots[:env_build_failure]
404
407
  return [] if failure.nil?
405
408
 
406
409
  [build_rbs_environment_build_failed_diagnostic(failure)]
@@ -426,7 +429,7 @@ module Rigor
426
429
  # a Rigor release turn a green build red with no user change (ADR-5 / AGENTS.md § FP discipline).
427
430
  # The `reject-unparseable-signatures` bleeding-edge feature promotes it to `:error`.
428
431
  def rbs_definition_build_failed_diagnostics
429
- failures = definition_build_failures_snapshot
432
+ failures = @snapshots[:definition_build_failures]
430
433
  return [] if failures.nil? || failures.empty?
431
434
 
432
435
  [build_rbs_definition_build_failed_diagnostic(failures)]
@@ -445,14 +448,14 @@ module Rigor
445
448
  # surface, no signature file is skipped, the environment builds. That is why this sits LAST on the
446
449
  # ladder, after its two `rbs.coverage.*` siblings above.
447
450
  def rbs_hkt_scan_failed_diagnostics
448
- failure = hkt_scan_failure_snapshot
451
+ failure = @snapshots[:hkt_scan_failure]
449
452
  return [] if failure.nil?
450
453
 
451
454
  [build_rbs_hkt_scan_failed_diagnostic(failure)]
452
455
  end
453
456
 
454
457
  def rbs_synthesized_namespace_diagnostics
455
- synthesized = synthesized_namespaces_snapshot
458
+ synthesized = @snapshots[:synthesized_namespaces]
456
459
  return [] if synthesized.nil? || synthesized.empty?
457
460
 
458
461
  [build_rbs_synthesized_namespace_diagnostic(synthesized)]
@@ -465,10 +468,12 @@ module Rigor
465
468
  # typing they are not getting and why, and — unlike the quarantine row this file used to be
466
469
  # misreported as — is not sent to remove a declaration the plugin owns.
467
470
  def rbs_plugin_signature_stood_down_diagnostics
468
- standdowns = signature_standdowns_snapshot
471
+ standdowns = @snapshots[:signature_standdowns]
469
472
  return [] if standdowns.nil? || standdowns.empty?
470
473
 
471
- standdowns.map { |entry| build_rbs_plugin_signature_stood_down_diagnostic(entry) }
474
+ members, files = standdowns.partition { |entry| entry[5] == :member }
475
+ files.map { |entry| build_rbs_plugin_signature_stood_down_diagnostic(entry) } +
476
+ members.group_by(&:first).map { |path, rows| build_rbs_plugin_member_stood_down_diagnostic(path, rows) }
472
477
  end
473
478
 
474
479
  # Issue #1713 — the other outcome that avoided a definition-build failure: a required-feature-gated
@@ -476,7 +481,7 @@ module Rigor
476
481
  # declares — a member, a whole type, or, when nothing narrower built, the directory. One `:info` per
477
482
  # directory, naming the declarations that stood down and the files that displaced them.
478
483
  def rbs_vendored_signature_stood_down_diagnostics
479
- standdowns = vendored_standdowns_snapshot
484
+ standdowns = @snapshots[:vendored_standdowns]
480
485
  return [] if standdowns.nil? || standdowns.empty?
481
486
 
482
487
  standdowns.map { |entry| build_rbs_vendored_signature_stood_down_diagnostic(entry) }
@@ -498,7 +503,7 @@ module Rigor
498
503
  # conformance; every analysis path, pooled or degraded, takes the snapshot `synthesized_namespaces`
499
504
  # comes from.
500
505
  def conforms_to_diagnostics
501
- results = conformance_results_snapshot
506
+ results = @snapshots[:conformance_results]
502
507
  return [] if results.nil? || results.empty?
503
508
 
504
509
  results.map { |record| build_conformance_diagnostic(record) }
@@ -630,7 +635,7 @@ module Rigor
630
635
  failures = failures.sort_by { |failure| failure.first.to_s }
631
636
  sample_size = 5
632
637
  files = failures.flat_map { |failure| Array(failure[3]) }
633
- .map { |name| relative_signature_path(name) }.uniq.sort
638
+ .map { |name| signature_source_label(name.to_s) }.uniq.sort
634
639
  Diagnostic.new(
635
640
  path: ".rigor.yml",
636
641
  line: 1,
@@ -641,32 +646,120 @@ module Rigor
641
646
  "Rigor still treats each class as KNOWN, so calls into it — real methods and typos " \
642
647
  "alike — silently read `Dynamic[top]` instead of resolving, and this run is quieter " \
643
648
  "than it should be rather than cleaner. #{definition_build_advice(failures.first)}",
644
- severity: :warning,
649
+ severity: selected_core_failure?(failures) ? :error : :warning,
645
650
  rule: "rbs.coverage.definition-build-failed",
646
651
  source_family: :builtin
647
652
  )
648
653
  end
649
654
 
655
+ # Issue #2517 — a class that does not build from the selected `core_root:` alone is that explicit choice
656
+ # failing, not a Rigor release disagreeing with the user's `sig/`, so it is an error. A failure that also
657
+ # names a file outside the core (a project `sig/` collision) keeps the warning it has without one.
658
+ def selected_core_failure?(failures)
659
+ core_root = @configuration.core_root
660
+ return false if core_root.nil?
661
+
662
+ prefix = File.join(core_root, "")
663
+ failures.any? do |failure|
664
+ buffers = Array(failure[3]).map(&:to_s)
665
+ !buffers.empty? && buffers.all? { |name| name.start_with?(prefix) }
666
+ end
667
+ end
668
+
650
669
  # The closing advice follows the FIRST failure's error class: `GenericParameterMismatchError` is two
651
670
  # declarations of one CLASS at different generic arity (#610); `NoTypeFoundError` (issue #997) is
652
671
  # ONE declaration naming a type that does not exist, which "remove the duplicate declaration" sends
653
672
  # its reader after a duplicate that is not there — the fifth tuple element
654
- # ({RbsLoader#unresolved_type_name_detail}) is non-nil for exactly that case. Every other error class
655
- # (the two duplicated-definition errors, `RecursiveAncestorError`, …) keeps the duplicate-declaration
656
- # wording, which is accurate for them.
673
+ # ({RbsLoader#unresolved_type_name_detail}) is non-nil for exactly that case. Issue #2440 — a
674
+ # duplicated instance variable, a superclass mismatch, a missing superclass and a type applied to
675
+ # the wrong arguments each get their own sentence, and when a `virtual:` (inline RBS) buffer is
676
+ # among the colliding sources the advice never tells the reader to remove it as if it were a file.
677
+ # Every other error class (the two duplicated-definition errors, `RecursiveAncestorError`, …) keeps
678
+ # the duplicate-declaration wording, which is accurate for them.
657
679
  def definition_build_advice(failure)
658
- _, error_class, _member, _buffers, unresolved = failure
659
- if error_class.to_s.end_with?("GenericParameterMismatchError")
680
+ _, error_class, member, buffers, unresolved = failure
681
+ inline = Array(buffers).any? { |name| name.to_s.start_with?("virtual:") }
682
+ case error_class.to_s.split("::").last
683
+ when "GenericParameterMismatchError"
660
684
  "Two signature sources declare the class with a different number of type parameters; make " \
661
- "the declarations agree (`rbs validate`) to restore type coverage."
662
- elsif unresolved
663
- unresolved_type_name_advice(unresolved)
685
+ "the declarations agree (`rbs validate`) to restore type coverage."
686
+ when "InstanceVariableDuplicationError" then variable_duplication_advice("instance variable", failure)
687
+ when "ClassInstanceVariableDuplicationError"
688
+ variable_duplication_advice("class instance variable", failure)
689
+ when "SuperclassMismatchError" then superclass_mismatch_advice(inline)
690
+ when "NoSuperclassFoundError" then no_superclass_advice(member)
691
+ when "InvalidTypeApplicationError" then invalid_type_application_advice(member)
664
692
  else
693
+ return unresolved_type_name_advice(unresolved) if unresolved
694
+
665
695
  "Two signature sources declare the same member; remove the duplicate declaration " \
666
696
  "(`rbs validate`) to restore type coverage."
667
697
  end
668
698
  end
669
699
 
700
+ # The sixth tuple slot ({RbsLoader#variable_mixin_count}) is set only when the failing class mixes in
701
+ # the variable's owner at least twice and the owner declares it once: rbs counts the variable once per
702
+ # mixin. Otherwise — a variable duplicated in the owner itself, inherited or not — the wording follows
703
+ # which sources collide: inline only, inline and a file, two files, or one file declaring it twice.
704
+ def variable_duplication_advice(noun, failure)
705
+ class_name, _, member, buffers, _, mixins = failure
706
+ if mixins.is_a?(Integer) && mixins >= 2
707
+ return mixin_variable_duplication_advice(noun, class_name.to_s.delete_prefix("::"),
708
+ member.to_s.delete_prefix("::"))
709
+ end
710
+
711
+ names = Array(buffers).map(&:to_s)
712
+ inline = names.count { |name| name.start_with?("virtual:") }
713
+ if inline >= 2 && inline == names.size
714
+ "Two inline `# @rbs` annotations declare the same #{noun} in one class, and RBS rejects the " \
715
+ "pair even when the types agree; keep one of them to restore type coverage."
716
+ elsif inline.positive?
717
+ "The same #{noun} is declared twice in one class, at least once by an inline `# @rbs` " \
718
+ "annotation, and RBS rejects the pair even when the types agree. Keep one declaration: " \
719
+ "regenerate the committed `.rbs` (`rbs-inline --output`) or remove its copy of the " \
720
+ "variable, or drop the annotation from the `.rb` file, to restore type coverage."
721
+ elsif names.size >= 2
722
+ "Two signature files declare the same #{noun} in one class, and RBS rejects the pair even " \
723
+ "when the types agree; keep one declaration (`rbs validate`) to restore type coverage."
724
+ else
725
+ "The same #{noun} is declared twice in one class, and RBS rejects the pair even when the " \
726
+ "types agree; keep one declaration (`rbs validate`) to restore type coverage."
727
+ end
728
+ end
729
+
730
+ def mixin_variable_duplication_advice(noun, klass, owner)
731
+ "`#{klass}` mixes in `#{owner}` (`include`, `extend` or `prepend`) more than once, in one " \
732
+ "declaration or across several, and RBS counts each #{noun} `#{owner}` declares once per mixin. " \
733
+ "Keep a single mixin of `#{owner}` in `#{klass}` (a committed `rbs-inline --output` file and the " \
734
+ "`.rb` file it came from count as two declarations) to restore type coverage."
735
+ end
736
+
737
+ def superclass_mismatch_advice(inline)
738
+ advice = "Two declarations of the class name different superclasses; make them name the same " \
739
+ "one, or leave the superclass off every declaration but one (a reopening needs none), " \
740
+ "to restore type coverage."
741
+ return advice unless inline
742
+
743
+ "#{advice} Where one side is an inline annotation, fix the annotation and regenerate the " \
744
+ "committed `.rbs` (`rbs-inline --output`), or remove the committed copy."
745
+ end
746
+
747
+ def no_superclass_advice(member)
748
+ name = member.to_s.delete_prefix("::")
749
+ subject = name.empty? ? "A superclass" : "`#{name}`"
750
+ "#{subject} is named as a superclass, but no loaded signature declares it; declare it in your " \
751
+ "`sig/` (or load the library that does through `libraries:`), or re-run `rigor sig-gen` if " \
752
+ "the signature was generated, to restore type coverage."
753
+ end
754
+
755
+ def invalid_type_application_advice(member)
756
+ name = member.to_s.delete_prefix("::")
757
+ subject = name.empty? ? "a type" : "`#{name}`"
758
+ "A signature applies #{subject} with the wrong number of type arguments, or applies them to the " \
759
+ "wrong class; match the arguments to the type parameters the class declares (`rbs validate`) " \
760
+ "to restore type coverage."
761
+ end
762
+
670
763
  # Issue #997 — `unresolved` is {RbsLoader#unresolved_type_name_detail}'s `[token, location,
671
764
  # refinement_hint]`. `refinement_hint` turns the message into a fix: the token is not a typo to
672
765
  # chase down but the start of a Rigor refinement name that is not valid in an RBS type position, and
@@ -777,6 +870,15 @@ module Rigor
777
870
  end
778
871
 
779
872
  # The absolute path is what the loader records; the user thinks in project-relative terms.
873
+ # Issue #2440 — a `virtual:<plugin>:<path>` buffer is named by the `.rb` file it was synthesized
874
+ # from, which is the file the user can open; the plugin id says how it became RBS.
875
+ def signature_source_label(name)
876
+ prefix, plugin_id, path = name.split(":", 3)
877
+ return relative_signature_path(name) unless prefix == "virtual" && plugin_id && path && !path.empty?
878
+
879
+ "#{relative_signature_path(path)} (inline RBS via #{plugin_id})"
880
+ end
881
+
780
882
  def relative_signature_path(path)
781
883
  root = "#{Dir.pwd}#{File::SEPARATOR}"
782
884
  path.start_with?(root) ? path.delete_prefix(root) : path
@@ -824,6 +926,33 @@ module Rigor
824
926
  )
825
927
  end
826
928
 
929
+ # Issue #2422 — one plugin signature file that loaded without the declarations another source also makes,
930
+ # naming each (sampled) with the file whose declaration was used instead. One row per file, not per
931
+ # declaration: an `rbs collection install` of a gem can overlap the plugin for it on hundreds. A method
932
+ # that composed with the other source's as an overload is not here; the plugin's overloads still bind.
933
+ # The wording covers a superclass a plugin's class header gave up (#2439) as well as a member.
934
+ def build_rbs_plugin_member_stood_down_diagnostic(path, rows)
935
+ labels = rows.map do |_path, declaration, _, _, cause_file|
936
+ cause = cause_file.nil? || cause_file.empty? ? "" : " (#{relative_signature_path(cause_file.to_s)})"
937
+ "`#{declaration}`#{cause}"
938
+ end
939
+ Diagnostic.new(
940
+ path: ".rigor.yml",
941
+ line: 1,
942
+ column: 1,
943
+ message: "`#{relative_signature_path(path.to_s)}` (a signature file a plugin contributes) loaded without " \
944
+ "#{rows.size} declaration(s) another signature source already makes: #{sampled(labels, 10)}. " \
945
+ "Conflicting declarations (two of one method or constant, or two different superclasses " \
946
+ "of one class) fail the build, so the plugin's stood down and the other source's, named in " \
947
+ "parentheses, is used; the rest of the plugin's file still " \
948
+ "loads. Nothing to fix unless you want the plugin's typing back, which needs that source to " \
949
+ "stop declaring it.",
950
+ severity: :info,
951
+ rule: "rbs.coverage.plugin-signature-stood-down",
952
+ source_family: :builtin
953
+ )
954
+ end
955
+
827
956
  def build_rbs_vendored_signature_stood_down_diagnostic(entry)
828
957
  dir, declarations, whole = entry
829
958
  Diagnostic.new(
@@ -936,9 +1065,12 @@ module Rigor
936
1065
  # all three cross the pool drain channel (see {RbsExtended::Reporter}); an entry with no position
937
1066
  # falls back to `.rigor.yml`-style file-level attribution.
938
1067
  def rbs_extended_reporter_diagnostics
939
- return [] if @rbs_extended_reporter.empty?
1068
+ unresolved_payload_diagnostics + lossy_projection_diagnostics + hkt_directive_diagnostics +
1069
+ deprecated_form_diagnostics
1070
+ end
940
1071
 
941
- unresolved = @rbs_extended_reporter.unresolved_payloads.map do |entry|
1072
+ def unresolved_payload_diagnostics
1073
+ @rbs_extended_reporter.unresolved_payloads.map do |entry|
942
1074
  build_positioned_reporter_diagnostic(
943
1075
  entry,
944
1076
  rule: "dynamic.rbs-extended.unresolved",
@@ -947,8 +1079,10 @@ module Rigor
947
1079
  "that contributes the referenced type vocabulary."
948
1080
  )
949
1081
  end
1082
+ end
950
1083
 
951
- lossy = @rbs_extended_reporter.lossy_projections.map do |entry|
1084
+ def lossy_projection_diagnostics
1085
+ @rbs_extended_reporter.lossy_projections.map do |entry|
952
1086
  build_positioned_reporter_diagnostic(
953
1087
  entry,
954
1088
  rule: "dynamic.shape.lossy-projection",
@@ -957,8 +1091,6 @@ module Rigor
957
1091
  "a `HashShape` / `Tuple` carrier or accept the unchanged result."
958
1092
  )
959
1093
  end
960
-
961
- unresolved + lossy + hkt_directive_diagnostics + deprecated_form_diagnostics
962
1094
  end
963
1095
 
964
1096
  # ADR-109 WD3 — one row per annotation still written in a spelling the grammar accepts but no
@@ -1330,38 +1462,6 @@ module Rigor
1330
1462
  def pre_eval_diagnostics_from_scanner
1331
1463
  @pre_eval_diagnostics_from_scanner_reader.call
1332
1464
  end
1333
-
1334
- def synthesized_namespaces_snapshot
1335
- @synthesized_namespaces_snapshot_reader.call
1336
- end
1337
-
1338
- def quarantined_signatures_snapshot
1339
- @quarantined_signatures_snapshot_reader.call
1340
- end
1341
-
1342
- def signature_standdowns_snapshot
1343
- @signature_standdowns_snapshot_reader.call
1344
- end
1345
-
1346
- def vendored_standdowns_snapshot
1347
- @vendored_standdowns_snapshot_reader.call
1348
- end
1349
-
1350
- def env_build_failure_snapshot
1351
- @env_build_failure_snapshot_reader.call
1352
- end
1353
-
1354
- def definition_build_failures_snapshot
1355
- @definition_build_failures_snapshot_reader.call
1356
- end
1357
-
1358
- def hkt_scan_failure_snapshot
1359
- @hkt_scan_failure_snapshot_reader.call
1360
- end
1361
-
1362
- def conformance_results_snapshot
1363
- @conformance_results_snapshot_reader.call
1364
- end
1365
1465
  end
1366
1466
  end
1367
1467
  end
@@ -78,7 +78,7 @@ module Rigor
78
78
  LABELS_CONSEQUENCE = "the label is not registered"
79
79
  private_constant :LABELS_CONSEQUENCE
80
80
 
81
- # @param rbs_loader — the run's loader; nil disables the pass.
81
+ # @param rbs_loader — the run's loader; nil skips the RBS walk, not the configured envelopes.
82
82
  # @param effect_table — the propagated graph.
83
83
  # @param discovery — forces and returns the cross-file discovery tables as
84
84
  # `[def_sources, singleton_def_sources, class_sources]`. Called only when a finding needs a