rigortype 0.3.7 → 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 (450) 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 +96 -15
  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 +39 -4
  22. data/docs/manual/03-configuration.md +11 -0
  23. data/docs/manual/04-diagnostics.md +12 -1
  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 +69 -13
  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 +100 -29
  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 +316 -40
  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 +430 -77
  76. data/lib/rigor/analysis/runner/project_pre_passes.rb +12 -6
  77. data/lib/rigor/analysis/runner/run_snapshots.rb +13 -3
  78. data/lib/rigor/analysis/runner.rb +200 -43
  79. data/lib/rigor/analysis/worker_session.rb +36 -12
  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 +166 -30
  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 +70 -0
  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_environment_marshal_patch.rb +39 -0
  97. data/lib/rigor/cache/rbs_known_class_names.rb +0 -3
  98. data/lib/rigor/cache/store.rb +85 -33
  99. data/lib/rigor/cli/annotate_command.rb +5 -6
  100. data/lib/rigor/cli/check_command.rb +57 -10
  101. data/lib/rigor/cli/check_invocation.rb +6 -11
  102. data/lib/rigor/cli/check_runner_factory.rb +1 -5
  103. data/lib/rigor/cli/coverage_command.rb +1 -1
  104. data/lib/rigor/cli/coverage_mutation.rb +12 -3
  105. data/lib/rigor/cli/coverage_scan.rb +1 -5
  106. data/lib/rigor/cli/diff_command.rb +1 -1
  107. data/lib/rigor/cli/doc_links.rb +3 -3
  108. data/lib/rigor/cli/docs_command.rb +2 -2
  109. data/lib/rigor/cli/doctor_command.rb +85 -38
  110. data/lib/rigor/cli/effects_command.rb +2 -2
  111. data/lib/rigor/cli/effects_diff_renderer.rb +3 -3
  112. data/lib/rigor/cli/effects_snapshot_command.rb +1 -1
  113. data/lib/rigor/cli/explain_command.rb +34 -1
  114. data/lib/rigor/cli/fused_protection_report.rb +7 -1
  115. data/lib/rigor/cli/lsp_command.rb +1 -1
  116. data/lib/rigor/cli/mcp_command.rb +1 -1
  117. data/lib/rigor/cli/measurement_integrity_warning.rb +4 -5
  118. data/lib/rigor/cli/mutation_fork_scan.rb +6 -6
  119. data/lib/rigor/cli/mutation_protection_report.rb +7 -1
  120. data/lib/rigor/cli/plugin_command.rb +1 -1
  121. data/lib/rigor/cli/plugins_command.rb +2 -1
  122. data/lib/rigor/cli/prism_colorizer.rb +2 -2
  123. data/lib/rigor/cli/protection_fork_scan.rb +6 -6
  124. data/lib/rigor/cli/show_bleedingedge_command.rb +1 -1
  125. data/lib/rigor/cli/sig_gen_command.rb +31 -2
  126. data/lib/rigor/cli/skill_command.rb +1 -1
  127. data/lib/rigor/cli/skill_deep_probe.rb +4 -4
  128. data/lib/rigor/cli/skill_describe.rb +36 -35
  129. data/lib/rigor/cli/trace_command.rb +4 -4
  130. data/lib/rigor/cli/trace_renderer.rb +5 -6
  131. data/lib/rigor/cli/triage_command.rb +1 -1
  132. data/lib/rigor/cli/type_of_command.rb +10 -6
  133. data/lib/rigor/cli/type_scan_command.rb +4 -4
  134. data/lib/rigor/cli/unused_command.rb +11 -3
  135. data/lib/rigor/cli/upgrade_command.rb +1 -1
  136. data/lib/rigor/cli.rb +68 -6
  137. data/lib/rigor/config_audit.rb +30 -5
  138. data/lib/rigor/configuration/severity_profile.rb +6 -6
  139. data/lib/rigor/configuration.rb +43 -4
  140. data/lib/rigor/effects/attribution.rb +1 -3
  141. data/lib/rigor/effects/config_envelopes.rb +6 -8
  142. data/lib/rigor/effects/definition_lines.rb +25 -6
  143. data/lib/rigor/effects/effect_table.rb +0 -1
  144. data/lib/rigor/effects/entry_points.rb +0 -2
  145. data/lib/rigor/effects/envelope_check.rb +8 -8
  146. data/lib/rigor/effects/envelope_index.rb +5 -8
  147. data/lib/rigor/effects/framework_units.rb +4 -6
  148. data/lib/rigor/effects/identity.rb +4 -6
  149. data/lib/rigor/effects/inline_anchor.rb +7 -7
  150. data/lib/rigor/effects/label_intent.rb +3 -4
  151. data/lib/rigor/effects/liskov_check.rb +8 -8
  152. data/lib/rigor/effects/method_key.rb +1 -1
  153. data/lib/rigor/effects/plugin_facts.rb +4 -6
  154. data/lib/rigor/effects/propagator.rb +2 -3
  155. data/lib/rigor/effects/scanner.rb +1 -1
  156. data/lib/rigor/effects/signature_sources.rb +3 -5
  157. data/lib/rigor/effects/snapshot.rb +10 -10
  158. data/lib/rigor/effects/snapshot_diff.rb +1 -1
  159. data/lib/rigor/effects/unit_scan.rb +10 -10
  160. data/lib/rigor/effects/unknown_label_check.rb +3 -8
  161. data/lib/rigor/effects/unknown_label_report.rb +3 -4
  162. data/lib/rigor/environment/bundle_sig_discovery.rb +6 -6
  163. data/lib/rigor/environment/class_registry.rb +3 -1
  164. data/lib/rigor/environment/failure_slot.rb +28 -0
  165. data/lib/rigor/environment/installed_gem_set.rb +85 -0
  166. data/lib/rigor/environment/lockfile_resolver.rb +51 -4
  167. data/lib/rigor/environment/missing_gem_constant_index.rb +4 -4
  168. data/lib/rigor/environment/rbs_collection_discovery.rb +5 -5
  169. data/lib/rigor/environment/rbs_coverage_report.rb +5 -5
  170. data/lib/rigor/environment/rbs_hierarchy.rb +3 -1
  171. data/lib/rigor/environment/rbs_loader.rb +613 -113
  172. data/lib/rigor/environment.rb +189 -27
  173. data/lib/rigor/flow_contribution/merger.rb +0 -2
  174. data/lib/rigor/flow_contribution.rb +11 -13
  175. data/lib/rigor/inference/acceptance.rb +153 -8
  176. data/lib/rigor/inference/block_parameter_binder.rb +2 -3
  177. data/lib/rigor/inference/body_fixpoint.rb +5 -5
  178. data/lib/rigor/inference/budget_trace.rb +1 -5
  179. data/lib/rigor/inference/captured_locals.rb +2 -3
  180. data/lib/rigor/inference/closure_escape_analyzer.rb +2 -4
  181. data/lib/rigor/inference/coverage_scanner.rb +4 -6
  182. data/lib/rigor/inference/dynamic_origin.rb +1 -1
  183. data/lib/rigor/inference/element_read_widening.rb +168 -0
  184. data/lib/rigor/inference/expression_typer.rb +763 -143
  185. data/lib/rigor/inference/fork_map.rb +5 -7
  186. data/lib/rigor/inference/hkt_reducer.rb +2 -3
  187. data/lib/rigor/inference/hkt_registry.rb +19 -10
  188. data/lib/rigor/inference/hkt_sugar_translator.rb +15 -21
  189. data/lib/rigor/inference/index_write_widening.rb +1 -5
  190. data/lib/rigor/inference/macro_block_self_type.rb +1 -4
  191. data/lib/rigor/inference/method_dispatcher/block_folding.rb +2 -9
  192. data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +1 -1
  193. data/lib/rigor/inference/method_dispatcher/constant_folding.rb +305 -19
  194. data/lib/rigor/inference/method_dispatcher/data_folding.rb +1 -1
  195. data/lib/rigor/inference/method_dispatcher/file_folding.rb +1 -1
  196. data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +2 -2
  197. data/lib/rigor/inference/method_dispatcher/json_folding.rb +1 -1
  198. data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +7 -1
  199. data/lib/rigor/inference/method_dispatcher/math_folding.rb +41 -3
  200. data/lib/rigor/inference/method_dispatcher/method_folding.rb +2 -5
  201. data/lib/rigor/inference/method_dispatcher/overload_selector.rb +61 -47
  202. data/lib/rigor/inference/method_dispatcher/random_folding.rb +82 -0
  203. data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +165 -31
  204. data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +25 -4
  205. data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +2 -8
  206. data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +1 -1
  207. data/lib/rigor/inference/method_dispatcher/set_folding.rb +1 -1
  208. data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +1 -1
  209. data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +1 -1
  210. data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +1 -2
  211. data/lib/rigor/inference/method_dispatcher/struct_folding.rb +4 -5
  212. data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +85 -4
  213. data/lib/rigor/inference/method_dispatcher/time_folding.rb +1 -1
  214. data/lib/rigor/inference/method_dispatcher/universal_object_dispatch.rb +1 -2
  215. data/lib/rigor/inference/method_dispatcher/uri_folding.rb +1 -1
  216. data/lib/rigor/inference/method_dispatcher.rb +12 -13
  217. data/lib/rigor/inference/method_parameter_binder.rb +4 -6
  218. data/lib/rigor/inference/multi_target_binder.rb +1 -3
  219. data/lib/rigor/inference/mutation_rejoin.rb +168 -0
  220. data/lib/rigor/inference/mutation_widening.rb +100 -51
  221. data/lib/rigor/inference/narrowing.rb +299 -46
  222. data/lib/rigor/inference/optimistic_origin.rb +1 -7
  223. data/lib/rigor/inference/origin_lookup.rb +2 -3
  224. data/lib/rigor/inference/parameter_inference_collector.rb +5 -6
  225. data/lib/rigor/inference/pre_eval_constants.rb +6 -5
  226. data/lib/rigor/inference/precision_scanner.rb +3 -4
  227. data/lib/rigor/inference/project_patched_methods.rb +2 -2
  228. data/lib/rigor/inference/project_patched_scanner.rb +3 -3
  229. data/lib/rigor/inference/protection_scanner.rb +1 -2
  230. data/lib/rigor/inference/range_constant.rb +57 -0
  231. data/lib/rigor/inference/rbs_type_translator.rb +49 -11
  232. data/lib/rigor/inference/receiver_alias.rb +3 -3
  233. data/lib/rigor/inference/refinement_mutation.rb +72 -0
  234. data/lib/rigor/inference/scope_indexer.rb +688 -151
  235. data/lib/rigor/inference/statement_evaluator.rb +221 -50
  236. data/lib/rigor/inference/string_mutation.rb +60 -0
  237. data/lib/rigor/inference/struct_fold_safety.rb +6 -7
  238. data/lib/rigor/inference/synthetic_method_index.rb +1 -2
  239. data/lib/rigor/inference/synthetic_method_scanner.rb +4 -6
  240. data/lib/rigor/inference/version_guard.rb +28 -21
  241. data/lib/rigor/inference/void_origin.rb +3 -3
  242. data/lib/rigor/inference/void_tail_summary.rb +2 -4
  243. data/lib/rigor/language_server/buffer_table.rb +4 -4
  244. data/lib/rigor/language_server/completion_provider.rb +1 -1
  245. data/lib/rigor/language_server/debouncer.rb +1 -1
  246. data/lib/rigor/language_server/diagnostic_publisher.rb +4 -4
  247. data/lib/rigor/language_server/document_symbol_provider.rb +1 -1
  248. data/lib/rigor/language_server/folding_range_provider.rb +1 -1
  249. data/lib/rigor/language_server/hover_provider.rb +1 -1
  250. data/lib/rigor/language_server/hover_renderer.rb +2 -2
  251. data/lib/rigor/language_server/incremental_sync.rb +6 -6
  252. data/lib/rigor/language_server/project_context.rb +2 -5
  253. data/lib/rigor/language_server/publish_batcher.rb +2 -2
  254. data/lib/rigor/language_server/selection_range_provider.rb +2 -2
  255. data/lib/rigor/language_server/server.rb +9 -9
  256. data/lib/rigor/language_server/signature_help_provider.rb +1 -1
  257. data/lib/rigor/language_server/uri.rb +1 -1
  258. data/lib/rigor/plugin/base.rb +90 -21
  259. data/lib/rigor/plugin/bundled_catalog.rb +167 -0
  260. data/lib/rigor/plugin/effect_attribution.rb +7 -7
  261. data/lib/rigor/plugin/effect_entry_points.rb +3 -3
  262. data/lib/rigor/plugin/fact_store.rb +6 -6
  263. data/lib/rigor/plugin/io_boundary.rb +93 -8
  264. data/lib/rigor/plugin/isolation.rb +29 -6
  265. data/lib/rigor/plugin/loader.rb +31 -12
  266. data/lib/rigor/plugin/macro/heredoc_template.rb +1 -1
  267. data/lib/rigor/plugin/macro/trait_registry.rb +1 -1
  268. data/lib/rigor/plugin/manifest.rb +23 -1
  269. data/lib/rigor/plugin/registry.rb +67 -14
  270. data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +12 -1
  271. data/lib/rigor/plugin/trust_policy.rb +2 -4
  272. data/lib/rigor/plugin/type_node_resolver.rb +3 -3
  273. data/lib/rigor/plugin_gap_advisory.rb +96 -0
  274. data/lib/rigor/project_environment.rb +138 -0
  275. data/lib/rigor/protection/analysis_guard.rb +93 -14
  276. data/lib/rigor/protection/closure_kill_oracle.rb +67 -23
  277. data/lib/rigor/protection/dependency_closure.rb +5 -8
  278. data/lib/rigor/protection/diagnostic_oracle.rb +2 -2
  279. data/lib/rigor/protection/discovery_seed.rb +11 -11
  280. data/lib/rigor/protection/kill_signature.rb +2 -4
  281. data/lib/rigor/protection/measurement_integrity.rb +1 -3
  282. data/lib/rigor/protection/mutation_cache.rb +6 -9
  283. data/lib/rigor/protection/mutation_scanner.rb +12 -15
  284. data/lib/rigor/protection/mutator.rb +2 -1
  285. data/lib/rigor/protection/test_suite_oracle.rb +5 -5
  286. data/lib/rigor/rbs_extended/conformance_checker.rb +4 -3
  287. data/lib/rigor/rbs_extended/envelope_scanner.rb +12 -13
  288. data/lib/rigor/rbs_extended/hkt_directives.rb +16 -1
  289. data/lib/rigor/rbs_extended/reporter.rb +122 -16
  290. data/lib/rigor/rbs_extended.rb +67 -22
  291. data/lib/rigor/reflection/constant_path.rb +126 -0
  292. data/lib/rigor/reflection.rb +26 -10
  293. data/lib/rigor/runtime/jit.rb +6 -8
  294. data/lib/rigor/scope/discovery_index.rb +30 -0
  295. data/lib/rigor/scope.rb +203 -4
  296. data/lib/rigor/sig_gen/generator.rb +181 -102
  297. data/lib/rigor/sig_gen/layout_index.rb +3 -4
  298. data/lib/rigor/sig_gen/meta_class_shape.rb +3 -5
  299. data/lib/rigor/sig_gen/observation_collector.rb +17 -15
  300. data/lib/rigor/sig_gen/path_mapper.rb +4 -6
  301. data/lib/rigor/sig_gen/rbs_validity.rb +4 -4
  302. data/lib/rigor/sig_gen/renderer.rb +17 -11
  303. data/lib/rigor/sig_gen/skip_reason_catalog.rb +111 -0
  304. data/lib/rigor/sig_gen/superclass_spelling.rb +27 -0
  305. data/lib/rigor/sig_gen/type_elaborator.rb +1 -3
  306. data/lib/rigor/sig_gen/writer.rb +23 -6
  307. data/lib/rigor/signature_path_audit.rb +153 -6
  308. data/lib/rigor/source/literals.rb +0 -23
  309. data/lib/rigor/source/node_children.rb +0 -2
  310. data/lib/rigor/source/node_locator.rb +5 -11
  311. data/lib/rigor/source/node_walker.rb +2 -5
  312. data/lib/rigor/triage/catalogue.rb +1 -3
  313. data/lib/rigor/triage.rb +3 -5
  314. data/lib/rigor/type/accepts_result.rb +24 -6
  315. data/lib/rigor/type/combinator.rb +68 -5
  316. data/lib/rigor/type/data_class.rb +2 -2
  317. data/lib/rigor/type/data_instance.rb +4 -4
  318. data/lib/rigor/type/float_range.rb +128 -0
  319. data/lib/rigor/type/hash_shape.rb +5 -5
  320. data/lib/rigor/type/integer_range.rb +13 -8
  321. data/lib/rigor/type/nominal.rb +8 -2
  322. data/lib/rigor/type/refined.rb +3 -3
  323. data/lib/rigor/type/struct_class.rb +3 -3
  324. data/lib/rigor/type/struct_instance.rb +4 -4
  325. data/lib/rigor/type.rb +1 -0
  326. data/lib/rigor/type_node/generic.rb +1 -1
  327. data/lib/rigor/type_node/range_literal.rb +25 -0
  328. data/lib/rigor/type_node/resolver_chain.rb +1 -1
  329. data/lib/rigor/type_node.rb +1 -0
  330. data/lib/rigor/version.rb +1 -1
  331. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +0 -4
  332. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +0 -1
  333. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +0 -2
  334. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +1 -0
  335. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +0 -4
  336. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +3 -5
  337. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +1 -4
  338. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +1 -0
  339. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +33 -30
  340. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +0 -1
  341. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +1 -3
  342. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +28 -2
  343. data/plugins/rigor-actionpack/sig/action_controller.rbs +71 -0
  344. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +0 -4
  345. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +1 -1
  346. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +0 -1
  347. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +0 -2
  348. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/recurring_scan.rb +1 -1
  349. data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +1 -0
  350. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +3 -4
  351. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +1 -2
  352. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +1 -2
  353. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +42 -7
  354. data/plugins/rigor-activerecord/sig/active_record/framework.rbs +123 -0
  355. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +1 -0
  356. data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +9 -2
  357. data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +119 -14
  358. data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +1 -0
  359. data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +1 -0
  360. data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +9 -7
  361. data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +7 -3
  362. data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +1 -0
  363. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +8 -6
  364. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +11 -7
  365. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -11
  366. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +9 -4
  367. data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +1 -0
  368. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +0 -5
  369. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +0 -1
  370. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +0 -1
  371. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +8 -1
  372. data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +36 -4
  373. data/plugins/rigor-ffi-rzmq/lib/rigor/plugin/ffi_rzmq.rb +1 -0
  374. data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +8 -6
  375. data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +6 -3
  376. data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +1 -0
  377. data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +2 -1
  378. data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +0 -3
  379. data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +1 -0
  380. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +0 -5
  381. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/authorization_scan.rb +2 -2
  382. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +0 -1
  383. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +0 -1
  384. data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +1 -0
  385. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +0 -12
  386. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +1 -3
  387. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +0 -1
  388. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +1 -0
  389. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/acronyms.rb +5 -5
  390. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +1 -10
  391. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +3 -3
  392. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +2 -2
  393. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/grape_api_discoverer.rb +2 -2
  394. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +2 -2
  395. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +9 -10
  396. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +2 -3
  397. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +1 -0
  398. data/plugins/rigor-railties/lib/rigor/plugin/railties.rb +1 -0
  399. data/plugins/rigor-rbnacl/lib/rigor/plugin/rbnacl.rb +13 -1
  400. data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +128 -3
  401. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +0 -3
  402. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +0 -3
  403. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +1 -5
  404. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +2 -3
  405. data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +1 -0
  406. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +0 -3
  407. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +1 -0
  408. data/plugins/rigor-sassc/lib/rigor/plugin/sassc.rb +1 -0
  409. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +1 -9
  410. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +1 -0
  411. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +0 -4
  412. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/effects.rb +1 -1
  413. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/schedule_scan.rb +1 -1
  414. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +0 -1
  415. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +0 -2
  416. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +1 -0
  417. data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +1 -0
  418. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +2 -5
  419. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +1 -4
  420. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +3 -9
  421. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +4 -4
  422. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +1 -2
  423. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +4 -5
  424. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +7 -5
  425. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +5 -5
  426. data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +1 -0
  427. data/sig/rigor/analysis/reachability/scan_cache.rbs +12 -0
  428. data/sig/rigor/cache.rbs +2 -3
  429. data/sig/rigor/environment.rbs +11 -0
  430. data/sig/rigor/inference.rbs +3 -10
  431. data/sig/rigor/plugin/io_boundary.rbs +4 -0
  432. data/sig/rigor/plugin/manifest.rbs +2 -1
  433. data/sig/rigor/reflection.rbs +3 -1
  434. data/sig/rigor/scope.rbs +24 -3
  435. data/sig/rigor/sig_gen/skip_reason_catalog.rbs +14 -0
  436. data/sig/rigor/type.rbs +27 -1
  437. data/sig/rigor.rbs +1 -0
  438. data/skills/rigor-ask/SKILL.md +8 -6
  439. data/skills/rigor-plugin-author/references/02-walker-and-types.md +13 -2
  440. data/skills/rigor-project-init/SKILL.md +6 -3
  441. data/skills/rigor-project-init/references/02-configure.md +10 -6
  442. data/skills/rigor-project-init/references/06-agent-contract.md +67 -0
  443. data/skills/rigor-type-oracle/SKILL.md +228 -0
  444. data/skills/rigor-type-oracle/references/01-oracle-commands.md +261 -0
  445. data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +52 -0
  446. data/skills/rigor-type-oracle/references/03-gap-protocol.md +128 -0
  447. data/skills/rigor-unused-adjudicate/SKILL.md +8 -5
  448. metadata +28 -3
  449. data/lib/rigor/cli/probe_environment.rb +0 -85
  450. data/sig/rigor/inference/builtins/numeric_catalog.rbs +0 -3
@@ -43,9 +43,9 @@ module Rigor
43
43
  RACY_WINDOW_NS = 2_000_000_000
44
44
  private_constant :RACY_WINDOW_NS
45
45
 
46
- # @param cache_path [String, nil] the configuration's cache root; nil or empty is an inert
46
+ # @param cache_path — the configuration's cache root; nil or empty is an inert
47
47
  # cache (every fetch computes, nothing persists).
48
- # @param target_ruby [String, nil] parse-affecting configuration, part of the identity.
48
+ # @param target_ruby — parse-affecting configuration, part of the identity.
49
49
  def self.open(cache_path, target_ruby: nil)
50
50
  return new(path: nil, header: nil) if cache_path.nil? || cache_path.to_s.empty?
51
51
 
@@ -26,8 +26,8 @@ module Rigor
26
26
  module SignatureScan
27
27
  module_function
28
28
 
29
- # @param file [String] path to a `.rbs` file.
30
- # @return [Array<Scan::Reference>] one file-level reference per distinct referenced name. Empty when the
29
+ # @param file — path to a `.rbs` file.
30
+ # @return one file-level reference per distinct referenced name. Empty when the
31
31
  # file cannot be read or parsed — a broken signature is the analyzer's business, not this scan's.
32
32
  def call(file)
33
33
  _, _, decls = ::RBS::Parser.parse_signature(::RBS::Buffer.new(name: file, content: File.read(file)))
@@ -7,7 +7,7 @@ module Rigor
7
7
  class Result
8
8
  attr_reader :diagnostics, :stats
9
9
 
10
- # @param stats [Rigor::Analysis::RunStats, nil] end-of-run telemetry (target file count, RBS class
10
+ # @param stats — end-of-run telemetry (target file count, RBS class
11
11
  # breakdown, wall + RSS) collected by the Runner. Nil when stats collection wasn't requested or wasn't
12
12
  # applicable (early-exit paths like `validate_target_ruby` failure).
13
13
  def initialize(diagnostics: [], stats: nil)
@@ -43,8 +43,6 @@ module Rigor
43
43
 
44
44
  # The diagnostics {#crashed?} answers true for, so a caller can name what it saw rather than only that
45
45
  # it saw something.
46
- #
47
- # @return [Array<Rigor::Analysis::Diagnostic>]
48
46
  def crash_diagnostics
49
47
  diagnostics.select { |diagnostic| CrashSignature.discards_file_analysis?(diagnostic) }
50
48
  end
@@ -642,7 +642,10 @@ module Rigor
642
642
  "Later write is `nil` — the `@cache = nil` clear-idiom is allowlisted.",
643
643
  "Either side is Union / Dynamic / IntegerRange / a shape-varied carrier.",
644
644
  "Writes live in different classes that happen to share an ivar name.",
645
- "Writes are in `def self.foo` (singleton) bodies — those track separately."
645
+ "Writes are in a singleton body — `def self.foo` or a `class << self` def — those track " \
646
+ "separately.",
647
+ "Writes are in a `def` inside an anonymous-class factory block (`Class.new do … end`, " \
648
+ "`Module.new`, `Struct.new`, `Data.define`): that body defines another class."
646
649
  ],
647
650
  suppression: "`# rigor:disable ivar-write-mismatch` on the offending write.",
648
651
  severity_authored: :error,
@@ -80,7 +80,7 @@ module Rigor
80
80
  # collecting project's path-set churn is the same churn, and over-evicting costs one recompute.
81
81
  EFFECTS_GENERATION_CAP = GENERATION_CAP
82
82
 
83
- # @param rbs_config_entries [Array<Cache::Descriptor::ConfigEntry>] the RBS-derived config slots
83
+ # @param rbs_config_entries — the RBS-derived config slots
84
84
  # (`rbs.libraries` [+ `rbs.virtual_rbs`]). nil on any failure so a malformed key disables the cache.
85
85
  def descriptor(configuration:, files:, explain:, rbs_config_entries:)
86
86
  Cache::Descriptor.new(
@@ -51,17 +51,15 @@ module Rigor
51
51
  # serves it instead. The decline is measured against the declarations alone, never against what they
52
52
  # would judge to, so it costs one glob and never a wrong answer.
53
53
  class RunCacheProbe
54
- # @param configuration [Rigor::Configuration]
55
- # @param cache_root [String]
56
- # @param explain [Boolean] the `--explain` flag (folded into the key, as the runner does).
54
+ # @param explain — the `--explain` flag (folded into the key, as the runner does).
57
55
  def initialize(configuration:, cache_root:, explain:)
58
56
  @configuration = configuration
59
57
  @cache_root = cache_root
60
58
  @explain = explain
61
59
  end
62
60
 
63
- # @param paths [Array<String>] the analysis roots (`@argv` or `configuration.paths`).
64
- # @return [Analysis::Result, nil] the cached run result with the severity profile applied and no stats
61
+ # @param paths — the analysis roots (`@argv` or `configuration.paths`).
62
+ # @return the cached run result with the severity profile applied and no stats
65
63
  # (matching a cache-served `Runner#run`), or nil to DECLINE — a miss / stale / unavailable cache — so
66
64
  # the caller loads the engine and runs the full path. Any failure declines rather than raising: the
67
65
  # probe must never turn a servable run into a crash.
@@ -66,7 +66,7 @@ module Rigor
66
66
  # via `RIGOR_LSP_POOL_MIN_BATCH` (mirrors `RIGOR_RACTOR_WORKERS`'s override shape).
67
67
  DEFAULT_MIN_BATCH_SIZE = 16
68
68
 
69
- # @return [Integer] `RIGOR_LSP_POOL_MIN_BATCH` when set to a non-empty value, else
69
+ # @return `RIGOR_LSP_POOL_MIN_BATCH` when set to a non-empty value, else
70
70
  # {DEFAULT_MIN_BATCH_SIZE}.
71
71
  def self.resolve_min_batch_size
72
72
  env_value = ENV.fetch("RIGOR_LSP_POOL_MIN_BATCH", nil)
@@ -75,19 +75,17 @@ module Rigor
75
75
  Integer(env_value)
76
76
  end
77
77
 
78
- # @param configuration [Rigor::Configuration]
79
- # @param cache_store [Rigor::Cache::Store, nil]
80
- # @param environment [Rigor::Environment] the warm, shared per-session Environment
78
+ # @param environment — the warm, shared per-session Environment
81
79
  # (`ProjectContext#environment`) every job's Runner reuses instead of rebuilding.
82
- # @param prebuilt [Rigor::Analysis::ProjectScan] the warm, shared pre-pass snapshot
80
+ # @param prebuilt — the warm, shared pre-pass snapshot
83
81
  # (`ProjectContext#project_scan`) every job's Runner adopts instead of re-scanning.
84
- # @param workers [Integer] pool size. `#analyze` degrades to sequential in-process execution — one
82
+ # @param workers — pool size. `#analyze` degrades to sequential in-process execution — one
85
83
  # job at a time, no `fork` — when fewer than 2 bindings are submitted, fewer than `min_batch_size`
86
84
  # bindings are submitted, `workers` is not positive, `fork` is unavailable on this platform, or
87
85
  # `cache_store` is nil. The middle two are the fork-pool-is-not-worth-it-yet gate documented on
88
86
  # {DEFAULT_MIN_BATCH_SIZE}; the last two mirror
89
87
  # {PoolCoordinator#analyze_files_in_pool}'s own fork-pool preconditions.
90
- # @param min_batch_size [Integer] see {DEFAULT_MIN_BATCH_SIZE}. Exposed as a constructor param
88
+ # @param min_batch_size — see {DEFAULT_MIN_BATCH_SIZE}. Exposed as a constructor param
91
89
  # (rather than read from the env internally) purely for spec control; production callers get the
92
90
  # resolved default.
93
91
  def initialize(configuration:, cache_store:, environment:, prebuilt:, workers:,
@@ -185,7 +183,7 @@ module Rigor
185
183
  degraded
186
184
  end
187
185
 
188
- # @return [Hash, nil] the child's `{index => diagnostics}` payload, or nil when the child exited
186
+ # @return the child's `{index => diagnostics}` payload, or nil when the child exited
189
187
  # abnormally or wrote no readable payload. `Marshal.load` is safe here: the blob was written by our
190
188
  # own forked child to a temp file we created.
191
189
  def fork_worker_payload(status, out_path)
@@ -20,8 +20,7 @@ module Rigor
20
20
 
21
21
  module_function
22
22
 
23
- # @param finding [#location]
24
- # @return [Array(String, Integer)] `[path, line]`
23
+ # @return `[path, line]`
25
24
  def of(finding)
26
25
  location = finding.location
27
26
  return [CONFIG_PATH, 1] if location.nil?
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../crash_signature"
3
4
  require_relative "../diagnostic"
4
5
  require_relative "../severity_stamp"
5
6
 
@@ -21,31 +22,36 @@ module Rigor
21
22
  # end-of-pass snapshots) is read through injected reader procs so this collaborator never calls back
22
23
  # into the {Runner} and the read happens at the exact point in the run the original inline read did.
23
24
  class DiagnosticAggregator # rubocop:disable Metrics/ClassLength
24
- # @param configuration [Rigor::Configuration]
25
- # @param rbs_extended_reporter [RbsExtended::Reporter]
26
- # @param boundary_cross_reporter [DependencySourceInference::BoundaryCrossReporter]
27
- # @param source_rbs_synthesis_reporter [Plugin::SourceRbsSynthesisReporter]
28
- # @param plugin_registry [#call] reader returning the current {Plugin::Registry} (varies per run).
29
- # @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
30
27
  # {DependencySourceInference::Index}.
31
- # @param pool_mode [#call] reader returning the pool-mode flag.
32
- # @param cached_plugin_prepare_diagnostics [#call] reader returning the prepare-diagnostic snapshot.
33
- # @param pre_eval_diagnostics_from_scanner [#call] reader returning the pre-eval scanner diagnostics.
34
- # @param synthesized_namespaces_snapshot [#call] reader.
35
- # @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
36
33
  # because they do not parse (`[path, first_error_line]` pairs).
37
- # @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
38
39
  # (`[error_class, first_error_line, conflicting_buffer_names]`) or nil when the env built.
39
- # @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
40
41
  # `RBS::DefinitionBuilder` failures the run observed, as `[class_name, error_class, member,
41
42
  # conflicting_buffer_names]` tuples. Empty for a healthy sig set.
42
- # @param conformance_results_snapshot [#call] reader.
43
+ # @param hkt_scan_failure_snapshot — issue #784 — reader returning the `[error_class_name,
44
+ # first_message_line, raw_frame_or_nil, stage]` tuple whichever stage of the HKT-registry build
45
+ # raised, or nil when both built (or were never demanded). `stage` is `:scan` (the RBS `type`-alias
46
+ # scan) or `:overlay` (the plugin-manifest aggregation, #791), and picks the row's wording.
47
+ # @param conformance_results_snapshot — reader.
43
48
  def initialize(configuration:, rbs_extended_reporter:, boundary_cross_reporter:, # rubocop:disable Metrics/ParameterLists
44
49
  source_rbs_synthesis_reporter:, plugin_registry:, dependency_source_index:,
45
50
  pool_mode:, cached_plugin_prepare_diagnostics:,
46
51
  pre_eval_diagnostics_from_scanner:, synthesized_namespaces_snapshot:,
47
52
  quarantined_signatures_snapshot:, env_build_failure_snapshot:,
48
- definition_build_failures_snapshot:, conformance_results_snapshot:)
53
+ definition_build_failures_snapshot:, hkt_scan_failure_snapshot:,
54
+ conformance_results_snapshot:, signature_standdowns_snapshot: -> { [] })
49
55
  @configuration = configuration
50
56
  @rbs_extended_reporter = rbs_extended_reporter
51
57
  @boundary_cross_reporter = boundary_cross_reporter
@@ -57,8 +63,10 @@ module Rigor
57
63
  @pre_eval_diagnostics_from_scanner_reader = pre_eval_diagnostics_from_scanner
58
64
  @synthesized_namespaces_snapshot_reader = synthesized_namespaces_snapshot
59
65
  @quarantined_signatures_snapshot_reader = quarantined_signatures_snapshot
66
+ @signature_standdowns_snapshot_reader = signature_standdowns_snapshot
60
67
  @env_build_failure_snapshot_reader = env_build_failure_snapshot
61
68
  @definition_build_failures_snapshot_reader = definition_build_failures_snapshot
69
+ @hkt_scan_failure_snapshot_reader = hkt_scan_failure_snapshot
62
70
  @conformance_results_snapshot_reader = conformance_results_snapshot
63
71
  end
64
72
 
@@ -315,9 +323,11 @@ module Rigor
315
323
  # user knows their sig set is malformed (`rbs validate` rejects it) and can fix it at the source.
316
324
  # Authored `:info`: the analysis already succeeded; this is advisory, never a gate. Empty for a
317
325
  # well-formed sig set.
318
- # An unparseable `.rbs` under `signature_paths:` is QUARANTINED so the rest of the env survives
319
- # (PR #50), which means the types it declares are silently absent — calls into them read
320
- # `Dynamic[top]`, and the run gets *quieter*, not louder. The stderr banner alone never reached CI:
326
+ # An unparseable or declaration-colliding `.rbs` under `signature_paths:` is QUARANTINED so the
327
+ # rest of the env survives (PR #50; issue #777 extends this to class-vs-module / constant
328
+ # collisions against bundled RBS), which means the types it declares are silently absent — calls
329
+ # into them read `Dynamic[top]`, and the run gets *quieter*, not louder. The stderr banner alone
330
+ # never reached CI:
321
331
  # it is not a diagnostic, so it is absent from `--format json` / SARIF / GitHub annotations / the LSP
322
332
  # and cannot move the exit code. This puts it in the diagnostic stream where every channel sees it.
323
333
  #
@@ -381,6 +391,25 @@ module Rigor
381
391
  [build_rbs_definition_build_failed_diagnostic(failures)]
382
392
  end
383
393
 
394
+ # Issue #784 — the fourth rung, narrowest consequence: one of the two builds behind
395
+ # `Environment#hkt_registry` raised instead of building. The `:scan` stage is the implicit HKT scan
396
+ # over RBS `type` aliases (ADR-20 WD2's `%a{rigor:v1:hkt_register / hkt_define}` overlay AND any
397
+ # recursive `type` alias in the project's own `.rbs` or an installed `rbs collection`); analysis
398
+ # proceeds over the PRE-scan registry — bundled builtins (`json::value`, …) plus the plugin overlay
399
+ # — so a `type` alias that would have registered as a type constructor reads its bound
400
+ # (`Dynamic[top]`) instead. The `:overlay` stage (#791) is the plugin-manifest aggregation, which
401
+ # sat ABOVE the seam until the run-owned demands made a raise there abort the run; it degrades one
402
+ # step further in and one step narrower — the plugin entries are dropped, the `.rbs` scan still
403
+ # runs. Either way everything else this run reports is unaffected: no class loses its method
404
+ # surface, no signature file is skipped, the environment builds. That is why this sits LAST on the
405
+ # ladder, after its two `rbs.coverage.*` siblings above.
406
+ def rbs_hkt_scan_failed_diagnostics
407
+ failure = hkt_scan_failure_snapshot
408
+ return [] if failure.nil?
409
+
410
+ [build_rbs_hkt_scan_failed_diagnostic(failure)]
411
+ end
412
+
384
413
  def rbs_synthesized_namespace_diagnostics
385
414
  synthesized = synthesized_namespaces_snapshot
386
415
  return [] if synthesized.nil? || synthesized.empty?
@@ -388,6 +417,26 @@ module Rigor
388
417
  [build_rbs_synthesized_namespace_diagnostic(synthesized)]
389
418
  end
390
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
+
391
440
  # Maps the per-run `rigor:v1:conforms-to` scan results into diagnostics (spec: `rbs-extended.md` §
392
441
  # "Explicit conformance directive"). A class that declares `conforms-to _Interface` but is missing
393
442
  # a required interface method surfaces as `rbs_extended.unsatisfied-conformance`; an unresolvable
@@ -408,16 +457,28 @@ module Rigor
408
457
  when RbsExtended::ConformanceChecker::IncompatibleSignature
409
458
  build_incompatible_signature_diagnostic(record)
410
459
  else # UnresolvedInterface
411
- build_reporter_diagnostic(
412
- record.location,
413
- rule: "dynamic.rbs-extended.unresolved",
414
- message: "`#{record.class_name}` declares `conforms-to #{record.interface_name}` but " \
415
- "interface `#{record.interface_name}` is not loaded. Check for a typo or add " \
416
- "the `sig`/library that declares it to the RBS load path."
417
- )
460
+ build_unresolved_conformance_diagnostic(record)
418
461
  end
419
462
  end
420
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
+
421
482
  def build_unsatisfied_conformance_diagnostic(record)
422
483
  path, line, column = location_fields(record.location)
423
484
  Diagnostic.new(
@@ -458,11 +519,12 @@ module Rigor
458
519
  path: ".rigor.yml",
459
520
  line: 1,
460
521
  column: 1,
461
- message: "#{quarantined.size} RBS file(s) under `signature_paths:` do not parse and were " \
462
- "SKIPPED: #{sample.join(', ')}#{suffix}. The rest of your RBS environment still " \
463
- "loaded, but the types those files declare are absent — calls into them read " \
464
- "`Dynamic[top]`, so this run is quieter than it should be, not cleaner. Fix the " \
465
- "parse error(s) (`rbs validate`) to restore that coverage.",
522
+ message: "#{quarantined.size} RBS file(s) under `signature_paths:` were SKIPPED " \
523
+ "(unparseable, or duplicated against bundled RBS): #{sample.join(', ')}#{suffix}. " \
524
+ "The rest of your RBS environment still loaded, but the types those files declare " \
525
+ "are absent — calls into them read `Dynamic[top]`, so this run is quieter than it " \
526
+ "should be, not cleaner. Fix the parse error(s) or remove the conflicting " \
527
+ "declaration(s) (`rbs validate`) to restore that coverage.",
466
528
  severity: :warning,
467
529
  rule: "rbs.coverage.quarantined-signature",
468
530
  source_family: :builtin
@@ -515,14 +577,27 @@ module Rigor
515
577
  "#{first_failure_clause(failures.first)}#{conflicting_files_clause(files, sample_size)} " \
516
578
  "Rigor still treats each class as KNOWN, so calls into it — real methods and typos " \
517
579
  "alike — silently read `Dynamic[top]` instead of resolving, and this run is quieter " \
518
- "than it should be rather than cleaner. Two signature sources declare the same " \
519
- "member; remove the duplicate declaration (`rbs validate`) to restore type coverage.",
580
+ "than it should be rather than cleaner. #{definition_build_advice(failures.first)}",
520
581
  severity: :warning,
521
582
  rule: "rbs.coverage.definition-build-failed",
522
583
  source_family: :builtin
523
584
  )
524
585
  end
525
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
+
526
601
  # `[class_name, error_class, member, buffers]`. The member is nil for the error classes that carry no
527
602
  # name at all (`RecursiveAncestorError`), and the clause then names the error class alone rather than
528
603
  # inventing a member.
@@ -550,6 +625,66 @@ module Rigor
550
625
  "#{sample.join(', ')}#{suffix}"
551
626
  end
552
627
 
628
+ # Issue #784 — one `:error` row per run, unlike its two `:warning` `rbs.coverage.*` siblings above.
629
+ # Those two are typically a collision between the user's OWN `sig/` and Rigor's bundled RBS, so an
630
+ # `:error` default would let a Rigor release turn a green project red with zero user change (ADR-5
631
+ # / AGENTS.md § FP discipline) — the reason both stay `:warning` by default. This row has no such
632
+ # neighbour: post-#783 the scan itself raising is an ANALYZER defect, never something a user's
633
+ # `sig/` could trigger on its own, so there is no green project this could newly redden. And the
634
+ # run was already non-zero before this row existed — issue #784's seam is what stopped the raise
635
+ # from reaching every file as N identical `internal analyzer error` rows in the first place, and
636
+ # THAT per-file rescue is what `Result#success?` was already reading as a failure; this row only
637
+ # makes the reason legible.
638
+ #
639
+ # One row per RUN, not per file: the scan is one build over the whole `signature_paths:` overlay
640
+ # (memoised — see {Environment#hkt_registry}), so every file that would have demanded it hit the
641
+ # exact same failure, and a row per file would say the same thing N times.
642
+ #
643
+ # `:rbs_build` (via {CrashSignature::RBS_BUILD_FAILURE_RULES}), not `:check_rule`: the analysis ran
644
+ # to completion over a DEGRADED type universe — every rule still fired, unlike `:check_rule`'s
645
+ # whole-file replacement — so a consumer gating on {CrashSignature.discards_file_analysis?} must
646
+ # keep reading this run's diagnostics rather than refuse it as a crash.
647
+ def build_rbs_hkt_scan_failed_diagnostic(failure)
648
+ error_class, first_line, frame, stage = failure
649
+ relative_frame = CrashSignature.relativize_frame(frame)
650
+ frame_clause = relative_frame ? " at #{relative_frame}" : ""
651
+ raised = "(#{error_class}): #{first_line}#{frame_clause}."
652
+ Diagnostic.new(
653
+ path: ".rigor.yml",
654
+ line: 1,
655
+ column: 1,
656
+ message: stage == :overlay ? hkt_overlay_failed_message(raised) : hkt_scan_failed_message(raised),
657
+ severity: :error,
658
+ rule: "rbs.coverage.hkt-scan-failed",
659
+ source_family: :builtin
660
+ )
661
+ end
662
+
663
+ def hkt_scan_failed_message(raised)
664
+ "The implicit HKT scan over RBS `type` aliases raised #{raised} Rigor fell back to the bundled " \
665
+ "and plugin HKT registrations, so a recursive `type` alias in your `.rbs` or an installed " \
666
+ "`rbs collection` no longer registers as a type constructor and reads its bound " \
667
+ "(`Dynamic[top]`) instead — this run is quieter than it should be, not cleaner. " \
668
+ "This is an analyzer defect, not a problem with your signatures; please report it " \
669
+ "with the message above."
670
+ end
671
+
672
+ # Issue #791 — the overlay stage of the same build, worded for the plugin it came from. The scan
673
+ # wording would send a user to their `.rbs` for a defect that is not there: what failed is the
674
+ # aggregation of the loaded plugins' manifest-declared HKT entries, and the message names the
675
+ # plugin whenever the raise was attributable to one (`Plugin::Registry#hkt_overlay_registry` puts
676
+ # the id in the message it re-raises). The degradation is narrower than the scan's, so the fallback
677
+ # sentence differs too: only the plugin entries are missing, and the user's own `.rbs` scan still
678
+ # ran on top of the bundled registrations.
679
+ def hkt_overlay_failed_message(raised)
680
+ "Building the plugin HKT overlay raised #{raised} Rigor skipped every plugin-declared HKT " \
681
+ "registration and analysed with the bundled ones plus your own `.rbs` overlay, so a type " \
682
+ "constructor a plugin declares reads its bound (`Dynamic[top]`) instead — this run is " \
683
+ "quieter than it should be, not cleaner. This is a defect in the named plugin or in Rigor, " \
684
+ "not a problem with your signatures; report it with the message above, or remove the plugin " \
685
+ "from `plugins:` to analyse without it."
686
+ end
687
+
553
688
  # The absolute path is what the loader records; the user thinks in project-relative terms.
554
689
  def relative_signature_path(path)
555
690
  root = "#{Dir.pwd}#{File::SEPARATOR}"
@@ -576,6 +711,42 @@ module Rigor
576
711
  )
577
712
  end
578
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
+
579
750
  def build_rbs_coverage_missing_diagnostic(missing)
580
751
  sample_size = 5
581
752
  sample = missing.first(sample_size).map(&:gem_name)
@@ -603,16 +774,19 @@ module Rigor
603
774
  # enable.
604
775
  # - `dynamic.shape.lossy-projection` for every shape-projection type function (`pick_of`, …) applied
605
776
  # to a carrier that loses precision (anything other than `HashShape` / `Tuple`).
777
+ # - `dynamic.rbs-extended.hkt-directive-invalid` for every malformed ADR-20 `rigor:v1:hkt_register` /
778
+ # `rigor:v1:hkt_define` the directive parser declined (issue #785).
606
779
  #
607
- # Both are authored `:info`; the severity profile re-stamps them per project taste. Path / line /
608
- # column come from the annotation's `RBS::Location` when available, falling back to
609
- # `.rigor.yml`-style file-level attribution otherwise.
780
+ # All three are authored `:info`; the severity profile re-stamps them per project taste. Every stream
781
+ # carries its `(path, line, column)` already flattened off the annotation's `RBS::Location`, because
782
+ # all three cross the pool drain channel (see {RbsExtended::Reporter}); an entry with no position
783
+ # falls back to `.rigor.yml`-style file-level attribution.
610
784
  def rbs_extended_reporter_diagnostics
611
785
  return [] if @rbs_extended_reporter.empty?
612
786
 
613
787
  unresolved = @rbs_extended_reporter.unresolved_payloads.map do |entry|
614
- build_reporter_diagnostic(
615
- entry.source_location,
788
+ build_positioned_reporter_diagnostic(
789
+ entry,
616
790
  rule: "dynamic.rbs-extended.unresolved",
617
791
  message: "`RBS::Extended` directive payload could not be resolved: " \
618
792
  "#{entry.payload.inspect}. Check for typos or enable a plugin " \
@@ -621,8 +795,8 @@ module Rigor
621
795
  end
622
796
 
623
797
  lossy = @rbs_extended_reporter.lossy_projections.map do |entry|
624
- build_reporter_diagnostic(
625
- entry.source_location,
798
+ build_positioned_reporter_diagnostic(
799
+ entry,
626
800
  rule: "dynamic.shape.lossy-projection",
627
801
  message: "Shape projection `#{entry.head}` applied to a carrier without a " \
628
802
  "literal shape; the projection degrades to the input type. Author " \
@@ -630,7 +804,37 @@ module Rigor
630
804
  )
631
805
  end
632
806
 
633
- unresolved + lossy
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
823
+ end
824
+
825
+ # Issue #785 — one row per declined HKT directive. The consequence sentence is the point: the parser
826
+ # is fail-soft, so nothing else in the run tells the author that the constructor they registered is
827
+ # not there and that every `App[…]` naming it silently reads its bound.
828
+ def hkt_directive_diagnostics
829
+ @rbs_extended_reporter.hkt_directive_errors.map do |entry|
830
+ build_positioned_reporter_diagnostic(
831
+ entry,
832
+ rule: "dynamic.rbs-extended.hkt-directive-invalid",
833
+ message: "`RBS::Extended` HKT directive was declined: #{entry.message}. The type " \
834
+ "constructor stays unregistered, so an `App[...]` carrier naming it reads " \
835
+ "its bound (`Dynamic[top]`) instead of the type function."
836
+ )
837
+ end
634
838
  end
635
839
 
636
840
  # ADR-32 WD6 — drains the per-run {Plugin::SourceRbsSynthesisReporter} into
@@ -704,6 +908,56 @@ module Rigor
704
908
  end
705
909
  end
706
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
+
707
961
  def build_reporter_diagnostic(source_location, rule:, message:)
708
962
  path, line, column = location_fields(source_location)
709
963
  Diagnostic.new(
@@ -712,6 +966,20 @@ module Rigor
712
966
  )
713
967
  end
714
968
 
969
+ # The {RbsExtended::Reporter} form of the builder above: its three streams carry the position as
970
+ # `(path, line, column)` primitives rather than as the `RBS::Location` a conformance record holds,
971
+ # because they cross the pool drain channel (#785, #805). A missing component falls back exactly as
972
+ # {#location_fields} does for a missing location.
973
+ def build_positioned_reporter_diagnostic(entry, rule:, message:)
974
+ path = entry.path.to_s
975
+ Diagnostic.new(
976
+ path: path.empty? ? ".rigor.yml" : path,
977
+ line: entry.line || 1,
978
+ column: entry.column || 1,
979
+ message: message, severity: :info, rule: rule, source_family: :builtin
980
+ )
981
+ end
982
+
715
983
  def location_fields(source_location)
716
984
  return [".rigor.yml", 1, 1] if source_location.nil?
717
985
 
@@ -768,6 +1036,10 @@ module Rigor
768
1036
  @quarantined_signatures_snapshot_reader.call
769
1037
  end
770
1038
 
1039
+ def signature_standdowns_snapshot
1040
+ @signature_standdowns_snapshot_reader.call
1041
+ end
1042
+
771
1043
  def env_build_failure_snapshot
772
1044
  @env_build_failure_snapshot_reader.call
773
1045
  end
@@ -776,6 +1048,10 @@ module Rigor
776
1048
  @definition_build_failures_snapshot_reader.call
777
1049
  end
778
1050
 
1051
+ def hkt_scan_failure_snapshot
1052
+ @hkt_scan_failure_snapshot_reader.call
1053
+ end
1054
+
779
1055
  def conformance_results_snapshot
780
1056
  @conformance_results_snapshot_reader.call
781
1057
  end