rigortype 0.3.8 → 0.3.9

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 (447) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/data/capability_roles/capability_roles.rbs +36 -0
  4. data/data/gem_overlay/activesupport/core_ext.rbs +109 -13
  5. data/docs/handbook/02-everyday-types.md +17 -14
  6. data/docs/handbook/03-narrowing.md +37 -4
  7. data/docs/handbook/05-methods-and-blocks.md +1 -1
  8. data/docs/handbook/06-classes.md +2 -2
  9. data/docs/handbook/07-rbs-and-extended.md +14 -1
  10. data/docs/handbook/11-sig-gen.md +72 -1
  11. data/docs/handbook/README.md +1 -1
  12. data/docs/handbook/appendix-elixir.md +2 -2
  13. data/docs/handbook/appendix-go.md +2 -2
  14. data/docs/handbook/appendix-java-csharp.md +2 -2
  15. data/docs/handbook/appendix-mypy.md +2 -2
  16. data/docs/handbook/appendix-phpstan.md +1 -1
  17. data/docs/handbook/appendix-rust.md +1 -1
  18. data/docs/handbook/appendix-type-theory.md +4 -4
  19. data/docs/handbook/appendix-typescript.md +1 -1
  20. data/docs/llms.txt +2 -0
  21. data/docs/manual/02-cli-reference.md +32 -4
  22. data/docs/manual/03-configuration.md +11 -0
  23. data/docs/manual/04-diagnostics.md +11 -0
  24. data/docs/manual/07-plugins.md +15 -5
  25. data/docs/manual/08-skills.md +23 -2
  26. data/docs/manual/11-ci.md +9 -0
  27. data/docs/manual/15-type-protection-coverage.md +8 -0
  28. data/docs/manual/16-rbs-extended-annotations.md +6 -1
  29. data/docs/manual/18-removing-dead-code.md +10 -8
  30. data/docs/manual/plugins/rigor-actionpack.md +18 -0
  31. data/docs/manual/plugins/rigor-activerecord.md +28 -0
  32. data/docs/manual/plugins/rigor-activesupport-core-ext.md +32 -2
  33. data/docs/manual/plugins/rigor-rbs-inline.md +42 -1
  34. data/lib/rigor/analysis/baseline.rb +2 -2
  35. data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +1 -1
  36. data/lib/rigor/analysis/check_rules/dead_version_guard_arms.rb +1 -5
  37. data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +10 -2
  38. data/lib/rigor/analysis/check_rules/main_pass_collector.rb +1 -1
  39. data/lib/rigor/analysis/check_rules/published_constant_guard.rb +15 -6
  40. data/lib/rigor/analysis/check_rules/rule_ids.rb +1 -1
  41. data/lib/rigor/analysis/check_rules/rule_walk.rb +39 -4
  42. data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +1 -1
  43. data/lib/rigor/analysis/check_rules/shadowed_rescue_collector.rb +1 -1
  44. data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +2 -2
  45. data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +0 -1
  46. data/lib/rigor/analysis/check_rules.rb +200 -32
  47. data/lib/rigor/analysis/crash_signature.rb +8 -24
  48. data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +1 -1
  49. data/lib/rigor/analysis/dependency_source_inference/builder.rb +0 -2
  50. data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +0 -2
  51. data/lib/rigor/analysis/dependency_source_inference/index.rb +5 -5
  52. data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +1 -2
  53. data/lib/rigor/analysis/dependency_source_inference/walker.rb +4 -4
  54. data/lib/rigor/analysis/effects_cache_probe.rb +3 -4
  55. data/lib/rigor/analysis/erb_template_detector.rb +1 -2
  56. data/lib/rigor/analysis/fact_store.rb +6 -1
  57. data/lib/rigor/analysis/incremental.rb +16 -0
  58. data/lib/rigor/analysis/incremental_session.rb +81 -22
  59. data/lib/rigor/analysis/plugin_fact_fingerprint.rb +0 -1
  60. data/lib/rigor/analysis/reachability/graph.rb +3 -5
  61. data/lib/rigor/analysis/reachability/plugin_roots.rb +6 -5
  62. data/lib/rigor/analysis/reachability/project_files.rb +2 -2
  63. data/lib/rigor/analysis/reachability/scan.rb +5 -5
  64. data/lib/rigor/analysis/reachability/scan_cache.rb +2 -2
  65. data/lib/rigor/analysis/reachability/signature_scan.rb +2 -2
  66. data/lib/rigor/analysis/result.rb +1 -3
  67. data/lib/rigor/analysis/rule_catalog.rb +4 -1
  68. data/lib/rigor/analysis/run_cache_key.rb +1 -1
  69. data/lib/rigor/analysis/run_cache_probe.rb +3 -5
  70. data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +6 -8
  71. data/lib/rigor/analysis/runner/declaration_position.rb +1 -2
  72. data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +177 -26
  73. data/lib/rigor/analysis/runner/effect_annotation_residual_pass.rb +2 -3
  74. data/lib/rigor/analysis/runner/effect_envelope_pass.rb +9 -10
  75. data/lib/rigor/analysis/runner/pool_coordinator.rb +256 -88
  76. data/lib/rigor/analysis/runner/project_pre_passes.rb +12 -6
  77. data/lib/rigor/analysis/runner/run_snapshots.rb +6 -1
  78. data/lib/rigor/analysis/runner.rb +133 -35
  79. data/lib/rigor/analysis/worker_session.rb +9 -10
  80. data/lib/rigor/bleeding_edge.rb +12 -24
  81. data/lib/rigor/builtins/hkt_builtins.rb +2 -2
  82. data/lib/rigor/builtins/imported_refinements.rb +155 -21
  83. data/lib/rigor/builtins/predefined_constant_refinements.rb +5 -7
  84. data/lib/rigor/builtins/regex_refinement.rb +4 -4
  85. data/lib/rigor/builtins/static_return_refinements.rb +5 -6
  86. data/lib/rigor/cache/annotation_location.rb +2 -4
  87. data/lib/rigor/cache/descriptor.rb +58 -20
  88. data/lib/rigor/cache/engine_source.rb +4 -4
  89. data/lib/rigor/cache/file_digest.rb +9 -1
  90. data/lib/rigor/cache/incremental_snapshot.rb +40 -6
  91. data/lib/rigor/cache/rbs_class_ancestor_table.rb +0 -3
  92. data/lib/rigor/cache/rbs_class_type_param_names.rb +0 -3
  93. data/lib/rigor/cache/rbs_constant_table.rb +0 -3
  94. data/lib/rigor/cache/rbs_descriptor.rb +79 -11
  95. data/lib/rigor/cache/rbs_environment.rb +8 -4
  96. data/lib/rigor/cache/rbs_known_class_names.rb +0 -3
  97. data/lib/rigor/cache/store.rb +77 -32
  98. data/lib/rigor/cli/annotate_command.rb +5 -6
  99. data/lib/rigor/cli/check_command.rb +57 -10
  100. data/lib/rigor/cli/check_invocation.rb +6 -11
  101. data/lib/rigor/cli/check_runner_factory.rb +1 -5
  102. data/lib/rigor/cli/coverage_command.rb +1 -1
  103. data/lib/rigor/cli/coverage_mutation.rb +12 -3
  104. data/lib/rigor/cli/coverage_scan.rb +1 -5
  105. data/lib/rigor/cli/diff_command.rb +1 -1
  106. data/lib/rigor/cli/doc_links.rb +3 -3
  107. data/lib/rigor/cli/docs_command.rb +2 -2
  108. data/lib/rigor/cli/doctor_command.rb +85 -38
  109. data/lib/rigor/cli/effects_command.rb +2 -2
  110. data/lib/rigor/cli/effects_diff_renderer.rb +3 -3
  111. data/lib/rigor/cli/effects_snapshot_command.rb +1 -1
  112. data/lib/rigor/cli/explain_command.rb +34 -1
  113. data/lib/rigor/cli/fused_protection_report.rb +7 -1
  114. data/lib/rigor/cli/lsp_command.rb +1 -1
  115. data/lib/rigor/cli/mcp_command.rb +1 -1
  116. data/lib/rigor/cli/measurement_integrity_warning.rb +4 -5
  117. data/lib/rigor/cli/mutation_fork_scan.rb +6 -6
  118. data/lib/rigor/cli/mutation_protection_report.rb +7 -1
  119. data/lib/rigor/cli/plugin_command.rb +1 -1
  120. data/lib/rigor/cli/plugins_command.rb +2 -1
  121. data/lib/rigor/cli/prism_colorizer.rb +2 -2
  122. data/lib/rigor/cli/protection_fork_scan.rb +6 -6
  123. data/lib/rigor/cli/show_bleedingedge_command.rb +1 -1
  124. data/lib/rigor/cli/sig_gen_command.rb +2 -2
  125. data/lib/rigor/cli/skill_command.rb +1 -1
  126. data/lib/rigor/cli/skill_deep_probe.rb +4 -4
  127. data/lib/rigor/cli/skill_describe.rb +36 -35
  128. data/lib/rigor/cli/trace_command.rb +4 -4
  129. data/lib/rigor/cli/trace_renderer.rb +5 -6
  130. data/lib/rigor/cli/triage_command.rb +1 -1
  131. data/lib/rigor/cli/type_of_command.rb +10 -6
  132. data/lib/rigor/cli/type_scan_command.rb +4 -4
  133. data/lib/rigor/cli/unused_command.rb +11 -3
  134. data/lib/rigor/cli/upgrade_command.rb +1 -1
  135. data/lib/rigor/cli.rb +68 -6
  136. data/lib/rigor/config_audit.rb +30 -5
  137. data/lib/rigor/configuration/severity_profile.rb +6 -6
  138. data/lib/rigor/configuration.rb +43 -4
  139. data/lib/rigor/effects/attribution.rb +1 -3
  140. data/lib/rigor/effects/config_envelopes.rb +6 -8
  141. data/lib/rigor/effects/definition_lines.rb +25 -6
  142. data/lib/rigor/effects/effect_table.rb +0 -1
  143. data/lib/rigor/effects/entry_points.rb +0 -2
  144. data/lib/rigor/effects/envelope_check.rb +8 -8
  145. data/lib/rigor/effects/envelope_index.rb +5 -8
  146. data/lib/rigor/effects/framework_units.rb +4 -6
  147. data/lib/rigor/effects/identity.rb +4 -6
  148. data/lib/rigor/effects/inline_anchor.rb +7 -7
  149. data/lib/rigor/effects/label_intent.rb +3 -4
  150. data/lib/rigor/effects/liskov_check.rb +8 -8
  151. data/lib/rigor/effects/method_key.rb +1 -1
  152. data/lib/rigor/effects/plugin_facts.rb +4 -6
  153. data/lib/rigor/effects/propagator.rb +2 -3
  154. data/lib/rigor/effects/scanner.rb +1 -1
  155. data/lib/rigor/effects/signature_sources.rb +3 -5
  156. data/lib/rigor/effects/snapshot.rb +10 -10
  157. data/lib/rigor/effects/snapshot_diff.rb +1 -1
  158. data/lib/rigor/effects/unit_scan.rb +10 -10
  159. data/lib/rigor/effects/unknown_label_check.rb +3 -8
  160. data/lib/rigor/effects/unknown_label_report.rb +3 -4
  161. data/lib/rigor/environment/bundle_sig_discovery.rb +6 -6
  162. data/lib/rigor/environment/class_registry.rb +3 -1
  163. data/lib/rigor/environment/failure_slot.rb +2 -2
  164. data/lib/rigor/environment/installed_gem_set.rb +85 -0
  165. data/lib/rigor/environment/lockfile_resolver.rb +51 -4
  166. data/lib/rigor/environment/missing_gem_constant_index.rb +4 -4
  167. data/lib/rigor/environment/rbs_collection_discovery.rb +5 -5
  168. data/lib/rigor/environment/rbs_coverage_report.rb +5 -5
  169. data/lib/rigor/environment/rbs_hierarchy.rb +3 -1
  170. data/lib/rigor/environment/rbs_loader.rb +388 -59
  171. data/lib/rigor/environment.rb +105 -20
  172. data/lib/rigor/flow_contribution/merger.rb +0 -2
  173. data/lib/rigor/flow_contribution.rb +11 -13
  174. data/lib/rigor/inference/acceptance.rb +153 -8
  175. data/lib/rigor/inference/block_parameter_binder.rb +2 -3
  176. data/lib/rigor/inference/body_fixpoint.rb +5 -5
  177. data/lib/rigor/inference/budget_trace.rb +1 -5
  178. data/lib/rigor/inference/captured_locals.rb +2 -3
  179. data/lib/rigor/inference/closure_escape_analyzer.rb +2 -4
  180. data/lib/rigor/inference/coverage_scanner.rb +4 -6
  181. data/lib/rigor/inference/dynamic_origin.rb +1 -1
  182. data/lib/rigor/inference/element_read_widening.rb +168 -0
  183. data/lib/rigor/inference/expression_typer.rb +763 -143
  184. data/lib/rigor/inference/fork_map.rb +5 -7
  185. data/lib/rigor/inference/hkt_reducer.rb +2 -3
  186. data/lib/rigor/inference/hkt_registry.rb +4 -7
  187. data/lib/rigor/inference/index_write_widening.rb +1 -5
  188. data/lib/rigor/inference/macro_block_self_type.rb +1 -4
  189. data/lib/rigor/inference/method_dispatcher/block_folding.rb +2 -9
  190. data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +1 -1
  191. data/lib/rigor/inference/method_dispatcher/constant_folding.rb +305 -19
  192. data/lib/rigor/inference/method_dispatcher/data_folding.rb +1 -1
  193. data/lib/rigor/inference/method_dispatcher/file_folding.rb +1 -1
  194. data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +2 -2
  195. data/lib/rigor/inference/method_dispatcher/json_folding.rb +1 -1
  196. data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +7 -1
  197. data/lib/rigor/inference/method_dispatcher/math_folding.rb +41 -3
  198. data/lib/rigor/inference/method_dispatcher/method_folding.rb +2 -5
  199. data/lib/rigor/inference/method_dispatcher/overload_selector.rb +61 -47
  200. data/lib/rigor/inference/method_dispatcher/random_folding.rb +82 -0
  201. data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +165 -31
  202. data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +25 -4
  203. data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +2 -8
  204. data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +1 -1
  205. data/lib/rigor/inference/method_dispatcher/set_folding.rb +1 -1
  206. data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +1 -1
  207. data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +1 -1
  208. data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +1 -2
  209. data/lib/rigor/inference/method_dispatcher/struct_folding.rb +4 -5
  210. data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +85 -4
  211. data/lib/rigor/inference/method_dispatcher/time_folding.rb +1 -1
  212. data/lib/rigor/inference/method_dispatcher/universal_object_dispatch.rb +1 -2
  213. data/lib/rigor/inference/method_dispatcher/uri_folding.rb +1 -1
  214. data/lib/rigor/inference/method_dispatcher.rb +12 -13
  215. data/lib/rigor/inference/method_parameter_binder.rb +4 -6
  216. data/lib/rigor/inference/multi_target_binder.rb +1 -3
  217. data/lib/rigor/inference/mutation_rejoin.rb +168 -0
  218. data/lib/rigor/inference/mutation_widening.rb +100 -51
  219. data/lib/rigor/inference/narrowing.rb +299 -46
  220. data/lib/rigor/inference/optimistic_origin.rb +1 -7
  221. data/lib/rigor/inference/origin_lookup.rb +2 -3
  222. data/lib/rigor/inference/parameter_inference_collector.rb +5 -6
  223. data/lib/rigor/inference/pre_eval_constants.rb +6 -5
  224. data/lib/rigor/inference/precision_scanner.rb +3 -4
  225. data/lib/rigor/inference/project_patched_methods.rb +2 -2
  226. data/lib/rigor/inference/project_patched_scanner.rb +3 -3
  227. data/lib/rigor/inference/protection_scanner.rb +1 -2
  228. data/lib/rigor/inference/range_constant.rb +57 -0
  229. data/lib/rigor/inference/rbs_type_translator.rb +49 -11
  230. data/lib/rigor/inference/receiver_alias.rb +3 -3
  231. data/lib/rigor/inference/refinement_mutation.rb +72 -0
  232. data/lib/rigor/inference/scope_indexer.rb +688 -151
  233. data/lib/rigor/inference/statement_evaluator.rb +221 -50
  234. data/lib/rigor/inference/string_mutation.rb +60 -0
  235. data/lib/rigor/inference/struct_fold_safety.rb +6 -7
  236. data/lib/rigor/inference/synthetic_method_index.rb +1 -2
  237. data/lib/rigor/inference/synthetic_method_scanner.rb +4 -6
  238. data/lib/rigor/inference/version_guard.rb +28 -21
  239. data/lib/rigor/inference/void_origin.rb +3 -3
  240. data/lib/rigor/inference/void_tail_summary.rb +2 -4
  241. data/lib/rigor/language_server/buffer_table.rb +4 -4
  242. data/lib/rigor/language_server/completion_provider.rb +1 -1
  243. data/lib/rigor/language_server/debouncer.rb +1 -1
  244. data/lib/rigor/language_server/diagnostic_publisher.rb +4 -4
  245. data/lib/rigor/language_server/document_symbol_provider.rb +1 -1
  246. data/lib/rigor/language_server/folding_range_provider.rb +1 -1
  247. data/lib/rigor/language_server/hover_provider.rb +1 -1
  248. data/lib/rigor/language_server/hover_renderer.rb +2 -2
  249. data/lib/rigor/language_server/incremental_sync.rb +6 -6
  250. data/lib/rigor/language_server/project_context.rb +2 -5
  251. data/lib/rigor/language_server/publish_batcher.rb +2 -2
  252. data/lib/rigor/language_server/selection_range_provider.rb +2 -2
  253. data/lib/rigor/language_server/server.rb +9 -9
  254. data/lib/rigor/language_server/signature_help_provider.rb +1 -1
  255. data/lib/rigor/language_server/uri.rb +1 -1
  256. data/lib/rigor/plugin/base.rb +90 -21
  257. data/lib/rigor/plugin/bundled_catalog.rb +167 -0
  258. data/lib/rigor/plugin/effect_attribution.rb +7 -7
  259. data/lib/rigor/plugin/effect_entry_points.rb +3 -3
  260. data/lib/rigor/plugin/fact_store.rb +6 -6
  261. data/lib/rigor/plugin/io_boundary.rb +93 -8
  262. data/lib/rigor/plugin/isolation.rb +29 -6
  263. data/lib/rigor/plugin/loader.rb +31 -12
  264. data/lib/rigor/plugin/macro/heredoc_template.rb +1 -1
  265. data/lib/rigor/plugin/macro/trait_registry.rb +1 -1
  266. data/lib/rigor/plugin/manifest.rb +23 -1
  267. data/lib/rigor/plugin/registry.rb +42 -12
  268. data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +12 -1
  269. data/lib/rigor/plugin/trust_policy.rb +2 -4
  270. data/lib/rigor/plugin/type_node_resolver.rb +3 -3
  271. data/lib/rigor/plugin_gap_advisory.rb +96 -0
  272. data/lib/rigor/project_environment.rb +138 -0
  273. data/lib/rigor/protection/analysis_guard.rb +93 -14
  274. data/lib/rigor/protection/closure_kill_oracle.rb +67 -23
  275. data/lib/rigor/protection/dependency_closure.rb +5 -8
  276. data/lib/rigor/protection/diagnostic_oracle.rb +2 -2
  277. data/lib/rigor/protection/discovery_seed.rb +11 -11
  278. data/lib/rigor/protection/kill_signature.rb +2 -4
  279. data/lib/rigor/protection/measurement_integrity.rb +1 -3
  280. data/lib/rigor/protection/mutation_cache.rb +6 -9
  281. data/lib/rigor/protection/mutation_scanner.rb +12 -15
  282. data/lib/rigor/protection/mutator.rb +2 -1
  283. data/lib/rigor/protection/test_suite_oracle.rb +5 -5
  284. data/lib/rigor/rbs_extended/conformance_checker.rb +4 -3
  285. data/lib/rigor/rbs_extended/envelope_scanner.rb +4 -6
  286. data/lib/rigor/rbs_extended/reporter.rb +36 -10
  287. data/lib/rigor/rbs_extended.rb +61 -21
  288. data/lib/rigor/reflection/constant_path.rb +126 -0
  289. data/lib/rigor/reflection.rb +26 -10
  290. data/lib/rigor/runtime/jit.rb +6 -8
  291. data/lib/rigor/scope/discovery_index.rb +30 -0
  292. data/lib/rigor/scope.rb +203 -4
  293. data/lib/rigor/sig_gen/generator.rb +115 -22
  294. data/lib/rigor/sig_gen/layout_index.rb +3 -4
  295. data/lib/rigor/sig_gen/meta_class_shape.rb +3 -5
  296. data/lib/rigor/sig_gen/observation_collector.rb +17 -15
  297. data/lib/rigor/sig_gen/path_mapper.rb +4 -6
  298. data/lib/rigor/sig_gen/rbs_validity.rb +4 -4
  299. data/lib/rigor/sig_gen/renderer.rb +4 -5
  300. data/lib/rigor/sig_gen/skip_reason_catalog.rb +111 -0
  301. data/lib/rigor/sig_gen/superclass_spelling.rb +27 -0
  302. data/lib/rigor/sig_gen/type_elaborator.rb +1 -3
  303. data/lib/rigor/sig_gen/writer.rb +23 -6
  304. data/lib/rigor/signature_path_audit.rb +153 -6
  305. data/lib/rigor/source/literals.rb +0 -23
  306. data/lib/rigor/source/node_children.rb +0 -2
  307. data/lib/rigor/source/node_locator.rb +5 -11
  308. data/lib/rigor/source/node_walker.rb +2 -5
  309. data/lib/rigor/triage/catalogue.rb +1 -3
  310. data/lib/rigor/triage.rb +3 -5
  311. data/lib/rigor/type/accepts_result.rb +24 -6
  312. data/lib/rigor/type/combinator.rb +68 -5
  313. data/lib/rigor/type/data_class.rb +2 -2
  314. data/lib/rigor/type/data_instance.rb +4 -4
  315. data/lib/rigor/type/float_range.rb +128 -0
  316. data/lib/rigor/type/hash_shape.rb +5 -5
  317. data/lib/rigor/type/integer_range.rb +13 -8
  318. data/lib/rigor/type/nominal.rb +8 -2
  319. data/lib/rigor/type/refined.rb +3 -3
  320. data/lib/rigor/type/struct_class.rb +3 -3
  321. data/lib/rigor/type/struct_instance.rb +4 -4
  322. data/lib/rigor/type.rb +1 -0
  323. data/lib/rigor/type_node/generic.rb +1 -1
  324. data/lib/rigor/type_node/range_literal.rb +25 -0
  325. data/lib/rigor/type_node/resolver_chain.rb +1 -1
  326. data/lib/rigor/type_node.rb +1 -0
  327. data/lib/rigor/version.rb +1 -1
  328. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +0 -4
  329. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +0 -1
  330. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +0 -2
  331. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +1 -0
  332. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +0 -4
  333. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +3 -5
  334. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +1 -4
  335. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +1 -0
  336. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +33 -30
  337. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +0 -1
  338. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +1 -3
  339. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +28 -2
  340. data/plugins/rigor-actionpack/sig/action_controller.rbs +71 -0
  341. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +0 -4
  342. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +1 -1
  343. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +0 -1
  344. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +0 -2
  345. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/recurring_scan.rb +1 -1
  346. data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +1 -0
  347. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +3 -4
  348. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +1 -2
  349. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +1 -2
  350. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +42 -7
  351. data/plugins/rigor-activerecord/sig/active_record/framework.rbs +123 -0
  352. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +1 -0
  353. data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +9 -2
  354. data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +119 -14
  355. data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +1 -0
  356. data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +1 -0
  357. data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +9 -7
  358. data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +7 -3
  359. data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +1 -0
  360. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +8 -6
  361. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +11 -7
  362. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -11
  363. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +9 -4
  364. data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +1 -0
  365. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +0 -5
  366. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +0 -1
  367. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +0 -1
  368. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +8 -1
  369. data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +36 -4
  370. data/plugins/rigor-ffi-rzmq/lib/rigor/plugin/ffi_rzmq.rb +1 -0
  371. data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +8 -6
  372. data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +6 -3
  373. data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +1 -0
  374. data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +2 -1
  375. data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +0 -3
  376. data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +1 -0
  377. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +0 -5
  378. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/authorization_scan.rb +2 -2
  379. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +0 -1
  380. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +0 -1
  381. data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +1 -0
  382. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +0 -12
  383. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +1 -3
  384. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +0 -1
  385. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +1 -0
  386. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/acronyms.rb +5 -5
  387. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +1 -10
  388. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +3 -3
  389. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +2 -2
  390. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/grape_api_discoverer.rb +2 -2
  391. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +2 -2
  392. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +9 -10
  393. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +2 -3
  394. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +1 -0
  395. data/plugins/rigor-railties/lib/rigor/plugin/railties.rb +1 -0
  396. data/plugins/rigor-rbnacl/lib/rigor/plugin/rbnacl.rb +13 -1
  397. data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +128 -3
  398. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +0 -3
  399. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +0 -3
  400. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +1 -5
  401. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +2 -3
  402. data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +1 -0
  403. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +0 -3
  404. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +1 -0
  405. data/plugins/rigor-sassc/lib/rigor/plugin/sassc.rb +1 -0
  406. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +1 -9
  407. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +1 -0
  408. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +0 -4
  409. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/effects.rb +1 -1
  410. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/schedule_scan.rb +1 -1
  411. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +0 -1
  412. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +0 -2
  413. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +1 -0
  414. data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +1 -0
  415. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +2 -5
  416. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +1 -4
  417. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +3 -9
  418. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +4 -4
  419. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +1 -2
  420. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +4 -5
  421. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +7 -5
  422. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +5 -5
  423. data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +1 -0
  424. data/sig/rigor/analysis/reachability/scan_cache.rbs +12 -0
  425. data/sig/rigor/cache.rbs +2 -3
  426. data/sig/rigor/environment.rbs +5 -0
  427. data/sig/rigor/inference.rbs +3 -10
  428. data/sig/rigor/plugin/io_boundary.rbs +4 -0
  429. data/sig/rigor/plugin/manifest.rbs +2 -1
  430. data/sig/rigor/reflection.rbs +3 -1
  431. data/sig/rigor/scope.rbs +24 -3
  432. data/sig/rigor/sig_gen/skip_reason_catalog.rbs +14 -0
  433. data/sig/rigor/type.rbs +27 -1
  434. data/sig/rigor.rbs +1 -0
  435. data/skills/rigor-ask/SKILL.md +8 -6
  436. data/skills/rigor-plugin-author/references/02-walker-and-types.md +13 -2
  437. data/skills/rigor-project-init/SKILL.md +6 -3
  438. data/skills/rigor-project-init/references/02-configure.md +10 -6
  439. data/skills/rigor-project-init/references/06-agent-contract.md +67 -0
  440. data/skills/rigor-type-oracle/SKILL.md +228 -0
  441. data/skills/rigor-type-oracle/references/01-oracle-commands.md +261 -0
  442. data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +52 -0
  443. data/skills/rigor-type-oracle/references/03-gap-protocol.md +128 -0
  444. data/skills/rigor-unused-adjudicate/SKILL.md +8 -5
  445. metadata +26 -3
  446. data/lib/rigor/cli/probe_environment.rb +0 -85
  447. data/sig/rigor/inference/builtins/numeric_catalog.rbs +0 -3
@@ -22,36 +22,36 @@ module Rigor
22
22
  # end-of-pass snapshots) is read through injected reader procs so this collaborator never calls back
23
23
  # into the {Runner} and the read happens at the exact point in the run the original inline read did.
24
24
  class DiagnosticAggregator # rubocop:disable Metrics/ClassLength
25
- # @param configuration [Rigor::Configuration]
26
- # @param rbs_extended_reporter [RbsExtended::Reporter]
27
- # @param boundary_cross_reporter [DependencySourceInference::BoundaryCrossReporter]
28
- # @param source_rbs_synthesis_reporter [Plugin::SourceRbsSynthesisReporter]
29
- # @param plugin_registry [#call] reader returning the current {Plugin::Registry} (varies per run).
30
- # @param dependency_source_index [#call] reader returning the current
25
+ # @param plugin_registry — reader returning the current {Plugin::Registry} (varies per run).
26
+ # @param dependency_source_index — reader returning the current
31
27
  # {DependencySourceInference::Index}.
32
- # @param pool_mode [#call] reader returning the pool-mode flag.
33
- # @param cached_plugin_prepare_diagnostics [#call] reader returning the prepare-diagnostic snapshot.
34
- # @param pre_eval_diagnostics_from_scanner [#call] reader returning the pre-eval scanner diagnostics.
35
- # @param synthesized_namespaces_snapshot [#call] reader.
36
- # @param quarantined_signatures_snapshot [#call] reader returning the `signature_paths:` files skipped
28
+ # @param pool_mode reader returning the pool-mode flag.
29
+ # @param cached_plugin_prepare_diagnostics reader returning the prepare-diagnostic snapshot.
30
+ # @param pre_eval_diagnostics_from_scanner reader returning the pre-eval scanner diagnostics.
31
+ # @param synthesized_namespaces_snapshot reader.
32
+ # @param quarantined_signatures_snapshot reader returning the `signature_paths:` files skipped
37
33
  # because they do not parse (`[path, first_error_line]` pairs).
38
- # @param env_build_failure_snapshot [#call] reader returning the total RBS env-build failure tuple
34
+ # @param signature_standdowns_snapshot reader returning the plugin-contributed signature files
35
+ # that stood down against a colliding generic arity (#610), as
36
+ # `[path, class_name, existing_arity, incoming_arity, existing_file]` tuples. Defaults to none so
37
+ # a caller that snapshots nothing of the kind need not say so.
38
+ # @param env_build_failure_snapshot — reader returning the total RBS env-build failure tuple
39
39
  # (`[error_class, first_error_line, conflicting_buffer_names]`) or nil when the env built.
40
- # @param definition_build_failures_snapshot [#call] issue #696 — reader returning the per-class
40
+ # @param definition_build_failures_snapshot issue #696 — reader returning the per-class
41
41
  # `RBS::DefinitionBuilder` failures the run observed, as `[class_name, error_class, member,
42
42
  # conflicting_buffer_names]` tuples. Empty for a healthy sig set.
43
- # @param hkt_scan_failure_snapshot [#call] issue #784 — reader returning the `[error_class_name,
43
+ # @param hkt_scan_failure_snapshot issue #784 — reader returning the `[error_class_name,
44
44
  # first_message_line, raw_frame_or_nil, stage]` tuple whichever stage of the HKT-registry build
45
45
  # raised, or nil when both built (or were never demanded). `stage` is `:scan` (the RBS `type`-alias
46
46
  # scan) or `:overlay` (the plugin-manifest aggregation, #791), and picks the row's wording.
47
- # @param conformance_results_snapshot [#call] reader.
47
+ # @param conformance_results_snapshot reader.
48
48
  def initialize(configuration:, rbs_extended_reporter:, boundary_cross_reporter:, # rubocop:disable Metrics/ParameterLists
49
49
  source_rbs_synthesis_reporter:, plugin_registry:, dependency_source_index:,
50
50
  pool_mode:, cached_plugin_prepare_diagnostics:,
51
51
  pre_eval_diagnostics_from_scanner:, synthesized_namespaces_snapshot:,
52
52
  quarantined_signatures_snapshot:, env_build_failure_snapshot:,
53
53
  definition_build_failures_snapshot:, hkt_scan_failure_snapshot:,
54
- conformance_results_snapshot:)
54
+ conformance_results_snapshot:, signature_standdowns_snapshot: -> { [] })
55
55
  @configuration = configuration
56
56
  @rbs_extended_reporter = rbs_extended_reporter
57
57
  @boundary_cross_reporter = boundary_cross_reporter
@@ -63,6 +63,7 @@ module Rigor
63
63
  @pre_eval_diagnostics_from_scanner_reader = pre_eval_diagnostics_from_scanner
64
64
  @synthesized_namespaces_snapshot_reader = synthesized_namespaces_snapshot
65
65
  @quarantined_signatures_snapshot_reader = quarantined_signatures_snapshot
66
+ @signature_standdowns_snapshot_reader = signature_standdowns_snapshot
66
67
  @env_build_failure_snapshot_reader = env_build_failure_snapshot
67
68
  @definition_build_failures_snapshot_reader = definition_build_failures_snapshot
68
69
  @hkt_scan_failure_snapshot_reader = hkt_scan_failure_snapshot
@@ -416,6 +417,26 @@ module Rigor
416
417
  [build_rbs_synthesized_namespace_diagnostic(synthesized)]
417
418
  end
418
419
 
420
+ # Issue #610 — the outcome that AVOIDED `rbs.coverage.definition-build-failed`'s rung: a signature
421
+ # file a loaded plugin contributes re-declared a class another loaded source (typically an `rbs
422
+ # collection install`) already declares at a DIFFERENT generic arity, so the plugin's file stood
423
+ # down rather than fail the class's definition build. One `:info` per file: the user is told what
424
+ # typing they are not getting and why, and — unlike the quarantine row this file used to be
425
+ # misreported as — is not sent to remove a declaration the plugin owns.
426
+ def rbs_plugin_signature_stood_down_diagnostics
427
+ standdowns = signature_standdowns_snapshot
428
+ return [] if standdowns.nil? || standdowns.empty?
429
+
430
+ standdowns.map { |entry| build_rbs_plugin_signature_stood_down_diagnostic(entry) }
431
+ end
432
+
433
+ # The two `:info` notices that close the `rbs.coverage.*` ladder, in this order: the namespace
434
+ # synthesis first, then the stand-down (#610) — the outcome that AVOIDED a definition-build failure
435
+ # and so the quietest row on it. One method so the runner's assembly reads them as one slot.
436
+ def rbs_coverage_notice_diagnostics
437
+ rbs_synthesized_namespace_diagnostics + rbs_plugin_signature_stood_down_diagnostics
438
+ end
439
+
419
440
  # Maps the per-run `rigor:v1:conforms-to` scan results into diagnostics (spec: `rbs-extended.md` §
420
441
  # "Explicit conformance directive"). A class that declares `conforms-to _Interface` but is missing
421
442
  # a required interface method surfaces as `rbs_extended.unsatisfied-conformance`; an unresolvable
@@ -436,16 +457,28 @@ module Rigor
436
457
  when RbsExtended::ConformanceChecker::IncompatibleSignature
437
458
  build_incompatible_signature_diagnostic(record)
438
459
  else # UnresolvedInterface
439
- build_reporter_diagnostic(
440
- record.location,
441
- rule: "dynamic.rbs-extended.unresolved",
442
- message: "`#{record.class_name}` declares `conforms-to #{record.interface_name}` but " \
443
- "interface `#{record.interface_name}` is not loaded. Check for a typo or add " \
444
- "the `sig`/library that declares it to the RBS load path."
445
- )
460
+ build_unresolved_conformance_diagnostic(record)
446
461
  end
447
462
  end
448
463
 
464
+ # Issue #928 — `:warning`, not the `:info` the other `dynamic.rbs-extended.unresolved` producers
465
+ # stamp. Those report that an inference fell back; this one reports that an assertion the author
466
+ # deliberately wrote is checking NOTHING, and the whole point of `conforms-to` is to be checked. It
467
+ # is not unsolicited either: only a project that wrote the directive can see it. Now that the
468
+ # capability-role catalog ships, the remaining way to reach this row is a name that does not exist.
469
+ def build_unresolved_conformance_diagnostic(record)
470
+ path, line, column = location_fields(record.location)
471
+ Diagnostic.new(
472
+ path: path, line: line, column: column,
473
+ message: "`#{record.class_name}` declares `conforms-to #{record.interface_name}` but " \
474
+ "interface `#{record.interface_name}` is not loaded. Check for a typo or add " \
475
+ "the `sig`/library that declares it to the RBS load path.",
476
+ severity: :warning,
477
+ rule: "dynamic.rbs-extended.unresolved",
478
+ source_family: :builtin
479
+ )
480
+ end
481
+
449
482
  def build_unsatisfied_conformance_diagnostic(record)
450
483
  path, line, column = location_fields(record.location)
451
484
  Diagnostic.new(
@@ -544,14 +577,27 @@ module Rigor
544
577
  "#{first_failure_clause(failures.first)}#{conflicting_files_clause(files, sample_size)} " \
545
578
  "Rigor still treats each class as KNOWN, so calls into it — real methods and typos " \
546
579
  "alike — silently read `Dynamic[top]` instead of resolving, and this run is quieter " \
547
- "than it should be rather than cleaner. Two signature sources declare the same " \
548
- "member; remove the duplicate declaration (`rbs validate`) to restore type coverage.",
580
+ "than it should be rather than cleaner. #{definition_build_advice(failures.first)}",
549
581
  severity: :warning,
550
582
  rule: "rbs.coverage.definition-build-failed",
551
583
  source_family: :builtin
552
584
  )
553
585
  end
554
586
 
587
+ # The closing advice follows the FIRST failure's error class: `GenericParameterMismatchError` is two
588
+ # declarations of one CLASS at different generic arity (#610), and "remove the duplicate member"
589
+ # sends its reader after a member that does not exist.
590
+ def definition_build_advice(failure)
591
+ _, error_class, = failure
592
+ if error_class.to_s.end_with?("GenericParameterMismatchError")
593
+ "Two signature sources declare the class with a different number of type parameters; make " \
594
+ "the declarations agree (`rbs validate`) to restore type coverage."
595
+ else
596
+ "Two signature sources declare the same member; remove the duplicate declaration " \
597
+ "(`rbs validate`) to restore type coverage."
598
+ end
599
+ end
600
+
555
601
  # `[class_name, error_class, member, buffers]`. The member is nil for the error classes that carry no
556
602
  # name at all (`RecursiveAncestorError`), and the clause then names the error class alone rather than
557
603
  # inventing a member.
@@ -665,6 +711,42 @@ module Rigor
665
711
  )
666
712
  end
667
713
 
714
+ def build_rbs_plugin_signature_stood_down_diagnostic(entry)
715
+ path, class_name, existing_arity, incoming_arity, existing_file = entry
716
+ displaced_by = displacing_source_phrase(existing_file)
717
+ Diagnostic.new(
718
+ path: ".rigor.yml",
719
+ line: 1,
720
+ column: 1,
721
+ message: "`#{relative_signature_path(path.to_s)}` (a signature file a plugin contributes) declares " \
722
+ "`#{class_name.to_s.delete_prefix('::')}` with #{type_parameter_phrase(incoming_arity)}, " \
723
+ "but #{displaced_by} already declares it with #{type_parameter_phrase(existing_arity)}. " \
724
+ "Two declarations of one class at different generic arity fail its definition build, so " \
725
+ "the plugin's file stood down: calls into the class resolve against the other " \
726
+ "declaration, and the plugin's element typing for it is unavailable while both are " \
727
+ "loaded. Expected when a bundled plugin and an `rbs collection install` both declare " \
728
+ "the class; nothing to fix unless you want the plugin's typing back, which needs the " \
729
+ "other source to stop declaring the class.",
730
+ severity: :info,
731
+ rule: "rbs.coverage.plugin-signature-stood-down",
732
+ source_family: :builtin
733
+ )
734
+ end
735
+
736
+ def displacing_source_phrase(existing_file)
737
+ return "another loaded signature source" if existing_file.nil?
738
+
739
+ "`#{relative_signature_path(existing_file.to_s)}`"
740
+ end
741
+
742
+ def type_parameter_phrase(arity)
743
+ case arity
744
+ when nil, 0 then "no type parameters"
745
+ when 1 then "1 type parameter"
746
+ else "#{arity} type parameters"
747
+ end
748
+ end
749
+
668
750
  def build_rbs_coverage_missing_diagnostic(missing)
669
751
  sample_size = 5
670
752
  sample = missing.first(sample_size).map(&:gem_name)
@@ -722,7 +804,22 @@ module Rigor
722
804
  )
723
805
  end
724
806
 
725
- unresolved + lossy + hkt_directive_diagnostics
807
+ unresolved + lossy + hkt_directive_diagnostics + deprecated_form_diagnostics
808
+ end
809
+
810
+ # ADR-109 WD3 — one row per annotation still written in a spelling the grammar accepts but no
811
+ # longer displays. The row names the replacement because the deprecation window exists for exactly
812
+ # this edit, and it stays `:info`: the annotation resolved, the run is as green as it was.
813
+ def deprecated_form_diagnostics
814
+ @rbs_extended_reporter.deprecated_forms.map do |entry|
815
+ build_positioned_reporter_diagnostic(
816
+ entry,
817
+ rule: "dynamic.rbs-extended.deprecated-form",
818
+ message: "`#{entry.payload}` is a deprecated spelling; write `#{entry.replacement}`. The " \
819
+ "angle-bracket integer range is accepted for one deprecation window and removed " \
820
+ "at the next compatibility break (ADR-109)."
821
+ )
822
+ end
726
823
  end
727
824
 
728
825
  # Issue #785 — one row per declined HKT directive. The consequence sentence is the point: the parser
@@ -811,6 +908,56 @@ module Rigor
811
908
  end
812
909
  end
813
910
 
911
+ # Issue #959 — surfaces the {Plugin::IoBoundary} refusal history each loaded plugin accumulated over
912
+ # the whole run (prepare AND every per-file call: `#io_boundary` is memoised per plugin instance, so
913
+ # one boundary sees both). `TrustPolicy#allow_read?` stays `File.expand_path`-only per ADR-2 — a
914
+ # project rooted under a symlink (macOS' `/tmp` → `/private/tmp` is the common case) can have every
915
+ # plugin read fall outside its own read roots with nothing said about it. One `:info` row per plugin
916
+ # that hit this, never one per path, naming the count and the first path so the row stays legible on
917
+ # a plugin that walked a whole out-of-scope subtree.
918
+ #
919
+ # Positioned here, in `#pre_file_diagnostics`'s post-analysis sibling list (called from
920
+ # `Runner#assemble_run_diagnostics`, which only runs on an ADR-45 cache MISS): the refusal history is
921
+ # a function of the plugin code and the resolved paths for THIS configuration, so it is deterministic
922
+ # across runs of the same inputs and the row that lands in a miss's cached diagnostics blob is the
923
+ # row a later warm HIT correctly re-serves — the same regeneration contract every other stream
924
+ # aggregated in `#pre_file_diagnostics` / `#assemble_run_diagnostics` already relies on (see
925
+ # `docs/type-specification/diagnostic-policy.md` § "Run-level rows and the record-and-validate
926
+ # cache"). It is also never routed through `IncrementalSession`'s per-file cache (`#788`): that cache
927
+ # holds only `Runner#per_file_diagnostics`, and this row is not part of that stream.
928
+ #
929
+ # Scope: `plugin_registry` here is the coordinator-side registry, which only actually RUNS `#prepare`
930
+ # / per-file analysis in sequential mode (`--workers` unset, the default) — a pooled run (`--workers
931
+ # N`) prepares and analyses on per-worker `WorkerSession` registries this reader never sees, so a
932
+ # refusal confined to a pooled worker's slice is not reported. Left out deliberately: draining it
933
+ # needs a fourth marshalled channel beside `drain_reporters` / `drain_dependencies` / `drain_effects`
934
+ # in `Runner::PoolCoordinator`, and the default (unpooled) path already covers the reported bug.
935
+ def plugin_trust_refusal_diagnostics
936
+ return [] if plugin_registry.empty?
937
+
938
+ plugin_registry.plugins.filter_map { |plugin| plugin_trust_refusal_diagnostic(plugin) }
939
+ end
940
+
941
+ def plugin_trust_refusal_diagnostic(plugin)
942
+ summary = plugin.io_boundary.refusal_summary
943
+ return nil if summary.nil?
944
+
945
+ plugin_id = plugin.manifest.id
946
+ Diagnostic.new(
947
+ path: ".rigor.yml", line: 1, column: 1,
948
+ message: "plugin #{plugin_id.inspect} had #{summary[:count]} read(s) refused by the trust " \
949
+ "policy; first refused path: #{summary[:first_path].inspect}, outside read root " \
950
+ "#{summary[:nearest_root].inspect}. Spell the path the way that read root spells it " \
951
+ "(a symlink alias such as macOS' /tmp does not match its real path), or add a " \
952
+ "`plugins_io.allowed_paths:` entry in .rigor.yml covering the path.",
953
+ severity: :info,
954
+ rule: "plugin_trust.read-refused",
955
+ source_family: :builtin
956
+ )
957
+ rescue StandardError
958
+ nil
959
+ end
960
+
814
961
  def build_reporter_diagnostic(source_location, rule:, message:)
815
962
  path, line, column = location_fields(source_location)
816
963
  Diagnostic.new(
@@ -889,6 +1036,10 @@ module Rigor
889
1036
  @quarantined_signatures_snapshot_reader.call
890
1037
  end
891
1038
 
1039
+ def signature_standdowns_snapshot
1040
+ @signature_standdowns_snapshot_reader.call
1041
+ end
1042
+
892
1043
  def env_build_failure_snapshot
893
1044
  @env_build_failure_snapshot_reader.call
894
1045
  end
@@ -58,8 +58,7 @@ module Rigor
58
58
  "every run of the project."
59
59
  private_constant :MESSAGE
60
60
 
61
- # @param configuration [Rigor::Configuration]
62
- # @param virtual_rbs [Array<Array(String, String)>, nil] `[buffer name, RBS source]` pairs the
61
+ # @param virtual_rbs — `[buffer name, RBS source]` pairs the
63
62
  # run ALREADY resolved; never a loader built for this pass. Empty / nil simply drops the
64
63
  # virtual-RBS stratum.
65
64
  def initialize(configuration:, virtual_rbs: nil)
@@ -67,7 +66,7 @@ module Rigor
67
66
  @virtual_rbs = virtual_rbs
68
67
  end
69
68
 
70
- # @return [Array<Diagnostic>] zero or one.
69
+ # @return zero or one.
71
70
  def diagnostics
72
71
  return NO_DIAGNOSTICS if @configuration.effects_enabled?
73
72
  return NO_DIAGNOSTICS if @configuration.disabled_rules.include?(RULE)
@@ -78,22 +78,21 @@ module Rigor
78
78
  LABELS_CONSEQUENCE = "the label is not registered"
79
79
  private_constant :LABELS_CONSEQUENCE
80
80
 
81
- # @param configuration [Rigor::Configuration]
82
- # @param rbs_loader [Rigor::Environment::RbsLoader, nil] the run's loader; nil disables the pass.
83
- # @param effect_table [Rigor::Effects::EffectTable] the propagated graph.
84
- # @param discovery [#call] forces and returns the cross-file discovery tables as
81
+ # @param rbs_loader — the run's loader; nil disables the pass.
82
+ # @param effect_table the propagated graph.
83
+ # @param discovery forces and returns the cross-file discovery tables as
85
84
  # `[def_sources, singleton_def_sources, class_sources]`. Called only when a finding needs a
86
85
  # position — a judged-clean envelope never forces it.
87
- # @param sources [Hash{String => String}] in-memory sources, for the buffer-backed run path.
88
- # @param unit_sources [Hash{String => Array<String>}] `Runner#effect_sources` — where each effect
86
+ # @param sources in-memory sources, for the buffer-backed run path.
87
+ # @param unit_sources `Runner#effect_sources` — where each effect
89
88
  # unit is defined, which is what an `effects.envelopes[].match:` path glob selects on. Its paths
90
89
  # are relativised against the working directory, which is the project root for every run that
91
90
  # reaches here (the same assumption `Snapshot.build` makes about `reach:`).
92
- # @param ancestry [#call, nil] returns the run's as-written superclass table
91
+ # @param ancestry returns the run's as-written superclass table
93
92
  # (`FileCollection#superclasses`) — the nominal relation `effect.liskov-widened` reads. A
94
93
  # lambda, and called only once an envelope exists, because merging the run's collections is
95
- # not free.
96
- # @param apply_tolerated [Boolean] false runs the judgment with an empty tolerated set
94
+ # not free. nil leaves that relation empty.
95
+ # @param apply_tolerated false runs the judgment with an empty tolerated set
97
96
  # (`--no-tolerated-effects`).
98
97
  def initialize(configuration:, rbs_loader:, effect_table:, discovery:, # rubocop:disable Metrics/ParameterLists
99
98
  sources: nil, unit_sources: nil, ancestry: nil, apply_tolerated: true,
@@ -109,7 +108,7 @@ module Rigor
109
108
  @apply_tolerated = apply_tolerated
110
109
  end
111
110
 
112
- # @return [Array<Diagnostic>] one per (method, exceeding label) plus one per unrecognised
111
+ # @return one per (method, exceeding label) plus one per unrecognised
113
112
  # label, suppression already applied.
114
113
  def diagnostics
115
114
  return NO_DIAGNOSTICS unless @configuration.effects_check?