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
@@ -9,6 +9,7 @@ require_relative "../scope"
9
9
  require_relative "../cache/store"
10
10
  require_relative "../cache/rbs_descriptor"
11
11
  require_relative "../cache/file_digest"
12
+ require_relative "../cache/incremental_snapshot"
12
13
  require_relative "run_cache_key"
13
14
  require_relative "path_expansion"
14
15
  require_relative "../plugin"
@@ -74,6 +75,18 @@ module Rigor
74
75
  # file-positioned ones (`effect.annotations-unchecked`, `source-rbs-*`).
75
76
  :per_file_diagnostics
76
77
 
78
+ # Issues #796 / #794 — the two run-level rows a NARROWED run cannot re-derive from the files it
79
+ # analyses: the `definition-build-failed` set (whose producer is the analysis's own demand, and #696
80
+ # forbids Rigor demanding in its place) and the HKT-scan outcome (whose producer is an environment a
81
+ # nothing-changed recheck otherwise has no reason to build). {IncrementalSession} persists what a full
82
+ # run answers here and hands it back to the next narrowed run.
83
+ def run_level_rows
84
+ Cache::IncrementalSnapshot::RunLevelRows.new(
85
+ definition_build_failures: @snapshots.definition_build_failures,
86
+ hkt_scan_failure: @snapshots.hkt_scan_failure
87
+ )
88
+ end
89
+
77
90
  # ADR-46 — the per-file cross-file read records this run captured (empty unless
78
91
  # `record_dependencies: true`). Sequential analysis records into `@file_dependencies` via
79
92
  # {#analyze_file}; the fork pool records per-worker and marshals the records into the coordinator, so a
@@ -214,41 +227,40 @@ module Rigor
214
227
  end
215
228
  end
216
229
 
217
- # @param configuration [Rigor::Configuration]
218
- # @param explain [Boolean] surface fail-soft fallback events as `:info` diagnostics.
219
- # @param cache_store [Rigor::Cache::Store, nil] the persistent cache the runner exposes to producers
230
+ # @param explain — surface fail-soft fallback events as `:info` diagnostics.
231
+ # @param cache_store the persistent cache the runner exposes to producers
220
232
  # (`RbsConstantTable` and successors). Pass `nil` to disable caching for this run; the CLI's
221
233
  # `--no-cache` flag wires `nil` through. v0.0.9 group A slice 1 introduces the surface; later
222
234
  # slices route real producers through it.
223
- # @param workers [Integer] ADR-15 Phase 4b — when greater than zero, per-file analysis dispatches
235
+ # @param workers ADR-15 Phase 4b — when greater than zero, per-file analysis dispatches
224
236
  # across a pool of N workers. Default `0` keeps the sequential code path bit-for-bit unchanged.
225
237
  # Controlled via the `RIGOR_RACTOR_WORKERS` env var or `.rigor.yml` `parallel.workers:` (Phase 4c,
226
238
  # fully wired).
227
- # @param collect_stats [Boolean] when true (default), `#run` builds a {RunStats} summary exposed via
239
+ # @param collect_stats when true (default), `#run` builds a {RunStats} summary exposed via
228
240
  # `result.stats` — this forces the RBS env build at end-of-run so the `class_decl_paths` snapshot
229
241
  # has real source attribution. Set to false to skip the stats summary entirely; the CLI's
230
242
  # `--no-stats` threads `false` through to keep trivial-fixture runs from warming `.rigor/cache`.
231
- # @param prebuilt [Rigor::Analysis::ProjectScan, nil] when supplied, the runner adopts the pre-built
243
+ # @param prebuilt when supplied, the runner adopts the pre-built
232
244
  # plugin registry / dependency-source index / scanner outputs from the snapshot and skips the
233
245
  # per-call pre-passes that produce them. Used by long-lived integrations
234
246
  # (`Rigor::LanguageServer::ProjectContext`) to keep per-buffer requests fast — scanners walk the
235
247
  # project once per generation rather than once per request, and plugin `#prepare` runs once per
236
248
  # generation rather than once per request. Watched-file invalidation is the owner's responsibility;
237
249
  # the runner trusts the snapshot it was given.
238
- # @param environment [Rigor::Environment, nil] opt-in Environment override. When supplied, sequential
250
+ # @param environment opt-in Environment override. When supplied, sequential
239
251
  # mode uses the provided env instance in `#analyze_files` instead of building a fresh one via
240
252
  # `Environment.for_project`, and attaches the runner's per-run reporter pair onto the env's mutable
241
253
  # `Reporters` slot via `Environment#attach_reporters!`. Long-lived consumers (LSP `ProjectContext`)
242
254
  # pass a shared env so per-publish work doesn't repeat the `Environment.for_project` build (bundler
243
255
  # / lockfile / collection discovery, RbsLoader construction). Pool mode ignores the override — each
244
256
  # worker continues to build its own Environment.
245
- # @param discovery_seed [Hash, nil] issue #260 — opt-in cross-file discovery tables, keyed by
257
+ # @param discovery_seed issue #260 — opt-in cross-file discovery tables, keyed by
246
258
  # {Scope::DiscoveryIndex} slot name, seeded onto every per-file scope through
247
259
  # `project_scope_seed_tables`. The ONE deliberate exception to "a `prebuilt:` runner carries no
248
260
  # discovery tables": {Protection::DiagnosticOracle} threads the table set Tier 2's site filter already
249
261
  # judges anchors against, so a site admitted because a sibling-file class resolved is also a site the
250
262
  # oracle can kill at. nil (the default) leaves the prebuilt/LSP contract byte-identical.
251
- # @param no_tolerated_effects [Boolean] ADR-103 WD1 / #385 — `rigor check --no-tolerated-effects`.
263
+ # @param no_tolerated_effects ADR-103 WD1 / #385 — `rigor check --no-tolerated-effects`.
252
264
  # Judges effect envelopes as if `effects.tolerated:` were empty. A judgment-time switch only: the
253
265
  # run, its collection and its cache identity are unchanged.
254
266
  def initialize(configuration:, explain: false, # rubocop:disable Metrics/ParameterLists,Metrics/AbcSize,Metrics/MethodLength
@@ -257,8 +269,12 @@ module Rigor
257
269
  buffer: nil, prebuilt: nil, environment: nil,
258
270
  record_dependencies: false, record_self_calls: false, analyze_only: nil,
259
271
  seed_bundles: nil, collect_seed_bundles: false, param_inferred_types: nil,
260
- discovery_seed: nil, no_tolerated_effects: false)
272
+ discovery_seed: nil, no_tolerated_effects: false,
273
+ restored_run_level_rows: nil)
261
274
  @configuration = configuration
275
+ # Issues #796 / #794 — the previous full run's run-level rows, supplied only by
276
+ # {IncrementalSession} on a narrowed run; see {PoolCoordinator#replay_restored_run_level_rows}.
277
+ @restored_run_level_rows = restored_run_level_rows
262
278
  @explain = explain
263
279
  @cache_store = enforce_read_only_cache(cache_store, buffer)
264
280
  @plugin_requirer = plugin_requirer
@@ -362,6 +378,8 @@ module Rigor
362
378
  # Issue #682 — the `Module.nesting` each class / module declaration HEADER is written in.
363
379
  @project_discovered_header_nestings = {}.freeze
364
380
  @project_discovered_includes = {}.freeze
381
+ # Issue #898 — the singleton-side twin of the include table (`extend M` / `extend self`).
382
+ @project_discovered_extends = {}.freeze
365
383
  @project_discovered_class_sources = {}.freeze
366
384
  # Issue #644 — the cross-file VALUE-constant publication table (`{qualified name => Type::Constant}`,
367
385
  # literal writes only) and its per-name write attribution. The first seeds `in_source_constants` on
@@ -388,6 +406,9 @@ module Rigor
388
406
  # (sequential + fork-worker) through `project_scope_seed_tables`. Empty unless the project lists
389
407
  # `pre_eval:` files that declare publishable constants, so a project without one is byte-identical.
390
408
  @project_pre_eval_constants = {}.freeze
409
+ # Issue #663 — the listed set {#publishable_pre_eval_constants} asks "is this writer one of ours?"
410
+ # against; a function of the configuration alone, so it outlives every discovery rebuild.
411
+ @pre_eval_path_set = nil
391
412
  # ADR-84 WD2 — per-run identity token for the user-method return memo's bucket (see
392
413
  # Scope::DiscoveryIndex#run_generation). Minted fresh in `run_analysis` so the memo never serves an
393
414
  # entry across a run boundary (LSP re-check, ADR-62 warm loop); nil until the first run so
@@ -479,9 +500,8 @@ module Rigor
479
500
  # so the result matches a one-file disk run; only the cross-file project pre-pass is empty (there is
480
501
  # one file, and the per-file indexer self-discovers its own classes / defs).
481
502
  #
482
- # @param source [String] Ruby source to analyze.
483
- # @param path [String] logical path for diagnostic locations.
484
- # @return [Result]
503
+ # @param source Ruby source to analyze.
504
+ # @param path logical path for diagnostic locations.
485
505
  def run_source(source:, path: "(source).rb")
486
506
  @in_memory_sources = { path => source }
487
507
  run([path])
@@ -607,7 +627,7 @@ module Rigor
607
627
  # arg-flooring surface). Only meaningful right after a run populated the memo (baseline / recheck),
608
628
  # before the bucket rolls. Keys are held live here; the session Marshals them for the snapshot.
609
629
  #
610
- # @return [Hash] `{ [path, "Class#method" | "Class.method"] => { keys:, returns:, effects: } }`.
630
+ # @return `{ [path, "Class#method" | "Class.method"] => { keys:, returns:, effects: } }`.
611
631
  def return_summaries
612
632
  memo = Inference::ExpressionTyper.harvest_return_memo
613
633
  return {} if memo.empty?
@@ -665,9 +685,9 @@ module Rigor
665
685
  # store) exactly as a real run's setup does, then re-drives each spec's def through the ADR-84 return
666
686
  # memo. Off any hot path — invoked only when declaration-stable changed pairs carry a persisted summary.
667
687
  #
668
- # @param paths [Array<String>, nil] analysis roots (nil → the configuration's `paths:`).
669
- # @param specs [Array<Hash>] each `{ class_name:, method_name:, singleton:, keys: [[receiver, args], …] }`.
670
- # @return [Hash] `{ [class_name, method_name, singleton] => [return_descriptor_or_nil, …] }`.
688
+ # @param paths analysis roots (nil → the configuration's `paths:`).
689
+ # @param specs each `{ class_name:, method_name:, singleton:, keys: [[receiver, args], …] }`.
690
+ # @return `{ [class_name, method_name, singleton] => [return_descriptor_or_nil, …] }`.
671
691
  def evaluate_return_types(paths, specs)
672
692
  return {} if specs.empty?
673
693
 
@@ -795,7 +815,7 @@ module Rigor
795
815
  # fixpoint over them, which is the pre-split behaviour and the retry the fail-soft posture wants.
796
816
  # Only when neither entry answers does the run re-analyse.
797
817
  #
798
- # @return [Boolean] whether this run was served.
818
+ # @return whether this run was served.
799
819
  def served_from_effect_entries?(descriptor)
800
820
  summary = peek_effect_summary(descriptor)
801
821
  if summary
@@ -1030,7 +1050,17 @@ module Rigor
1030
1050
  # contributes NO diagnostics and its result leaves through `#effect_table`, never through the
1031
1051
  # stream. Skipped entirely when collection did not run.
1032
1052
  close_effect_graph
1033
- diagnostics += @diagnostic_aggregator.rbs_quarantined_signature_diagnostics
1053
+ diagnostics + post_analysis_diagnostic_streams
1054
+ end
1055
+
1056
+ # The rbs-coverage build-failure ladder plus every remaining post-analysis stream
1057
+ # `#assemble_run_diagnostics` appends, in their fixed contract order (see the comments at each call
1058
+ # below and at the streams' own definitions). Split out of `#assemble_run_diagnostics` so that
1059
+ # method's `Metrics/AbcSize` stays under budget — every stream here is a plain `DiagnosticAggregator`
1060
+ # reader with no branching of its own, so the split changes nothing about WHEN or in WHAT order they
1061
+ # run.
1062
+ def post_analysis_diagnostic_streams
1063
+ diagnostics = @diagnostic_aggregator.rbs_quarantined_signature_diagnostics
1034
1064
  diagnostics += @diagnostic_aggregator.rbs_environment_build_failed_diagnostics
1035
1065
  # Issue #696 — after its env-wide twin and before the synthesized-namespace notice: the four
1036
1066
  # `rbs.coverage.*` build conditions surface widest-consequence first, and their relative order is
@@ -1040,12 +1070,20 @@ module Rigor
1040
1070
  # `type` alias would have contributed, never a class's own declared method surface, so it is the
1041
1071
  # narrowest-consequence rung on the same ladder.
1042
1072
  diagnostics += @diagnostic_aggregator.rbs_hkt_scan_failed_diagnostics
1043
- diagnostics += @diagnostic_aggregator.rbs_synthesized_namespace_diagnostics
1073
+ # The synthesized-namespace notice, then (#610) the plugin-signature stand-down: the outcome that
1074
+ # AVOIDED a definition-build failure, so the quietest row on that ladder.
1075
+ diagnostics += @diagnostic_aggregator.rbs_coverage_notice_diagnostics
1044
1076
  diagnostics += @diagnostic_aggregator.conforms_to_diagnostics
1045
1077
  diagnostics += @diagnostic_aggregator.rbs_extended_reporter_diagnostics
1046
1078
  diagnostics += @diagnostic_aggregator.boundary_cross_diagnostics
1047
- diagnostics + @diagnostic_aggregator.source_rbs_synthesis_diagnostics
1079
+ diagnostics += @diagnostic_aggregator.source_rbs_synthesis_diagnostics
1080
+ # Issue #959 — read LAST (after `analyze_targets`, which already ran before this method is called),
1081
+ # so every per-file plugin call has had its chance to record a refusal on its (per-plugin-instance
1082
+ # memoised) `IoBoundary`, alongside the prepare-time refusals the same boundary instance may
1083
+ # already carry.
1084
+ diagnostics + @diagnostic_aggregator.plugin_trust_refusal_diagnostics
1048
1085
  end
1086
+ private :post_analysis_diagnostic_streams
1049
1087
 
1050
1088
  # #788 round 7 — runs per-file analysis over `targets` and exposes what it produced as
1051
1089
  # `#per_file_diagnostics`: the `analyze_files` return, stamped with the same severity profile the run's
@@ -1179,13 +1217,22 @@ module Rigor
1179
1217
  def build_run_dependency_descriptor(expansion, rbs_descriptor)
1180
1218
  entries = analyzed_file_entries(expansion) + discovery_file_entries(expansion) +
1181
1219
  pre_eval_file_entries + rbs_descriptor.files
1182
- globs = []
1220
+ # #979 — the signature ROOTS' listings, one glob row each. `rbs_descriptor.files` covers only the
1221
+ # `.rbs` files that existed while the run read them, so without these a signature file written after
1222
+ # the run left the slot validating fresh and the warm run answered without it.
1223
+ globs = rbs_descriptor.globs.dup
1183
1224
  @plugin_registry.plugins.each do |plugin|
1184
1225
  # Read the boundary WITHOUT triggering its lazy `@io_boundary ||=` initializer: plugin instances
1185
1226
  # are frozen after the run, and a plugin that never built a boundary read no files through it,
1186
1227
  # so it contributes no dependencies.
1187
1228
  boundary = plugin.instance_variable_get(:@io_boundary)
1188
- entries.concat(boundary.cache_descriptor.files) if boundary
1229
+ if boundary
1230
+ # #629 — a boundary carries GlobEntry listing rows too (`IoBoundary#list_directory`), and they
1231
+ # are the only edge back to a file the run decided was ABSENT from a directory it consulted.
1232
+ boundary_descriptor = boundary.cache_descriptor
1233
+ entries.concat(boundary_descriptor.files)
1234
+ globs.concat(boundary_descriptor.globs)
1235
+ end
1189
1236
  plugin.class.producers.each_value do |prod|
1190
1237
  globs.concat(plugin.send(:watch_glob_entries, prod[:watch])) if prod[:watch]
1191
1238
  end
@@ -1306,6 +1353,7 @@ module Rigor
1306
1353
  @project_discovered_superclasses = discovery.discovered_superclasses
1307
1354
  @project_discovered_header_nestings = discovery.discovered_header_nestings
1308
1355
  @project_discovered_includes = discovery.discovered_includes
1356
+ @project_discovered_extends = discovery.discovered_extends
1309
1357
  @project_discovered_class_sources = discovery.discovered_class_sources
1310
1358
  @project_constant_values = discovery.constant_values
1311
1359
  @published_constant_name_set = nil
@@ -1399,7 +1447,7 @@ module Rigor
1399
1447
  3.0.0 3.1.0 3.2.0 3.3.0 3.4.0 3.5.0 4.0.0 4.1.0 4.2.0
1400
1448
  ].freeze
1401
1449
 
1402
- # @return [String, nil] the lowest `target_ruby` this Prism build accepts, or nil if none of the
1450
+ # @return the lowest `target_ruby` this Prism build accepts, or nil if none of the
1403
1451
  # ladder parses. Memoised per process (the value is constant for a given Prism).
1404
1452
  def self.prism_supported_floor
1405
1453
  @prism_supported_floor ||= PRISM_VERSION_LADDER.find do |candidate|
@@ -1504,7 +1552,8 @@ module Rigor
1504
1552
  synthetic_method_index: -> { @synthetic_method_index },
1505
1553
  project_patched_methods: -> { @project_patched_methods },
1506
1554
  project_scope_seed: -> { project_scope_seed_tables },
1507
- analyze_file: ->(path, environment) { analyze_file(path, environment) }
1555
+ analyze_file: ->(path, environment) { analyze_file(path, environment) },
1556
+ restored_run_level_rows: @restored_run_level_rows
1508
1557
  )
1509
1558
  @diagnostic_aggregator = DiagnosticAggregator.new(
1510
1559
  configuration: @configuration,
@@ -1518,6 +1567,7 @@ module Rigor
1518
1567
  pre_eval_diagnostics_from_scanner: -> { @pre_eval_diagnostics_from_scanner },
1519
1568
  synthesized_namespaces_snapshot: -> { @snapshots.synthesized_namespaces },
1520
1569
  quarantined_signatures_snapshot: -> { @snapshots.quarantined_signatures },
1570
+ signature_standdowns_snapshot: -> { @snapshots.signature_standdowns },
1521
1571
  env_build_failure_snapshot: -> { @snapshots.env_build_failure },
1522
1572
  definition_build_failures_snapshot: -> { @snapshots.definition_build_failures },
1523
1573
  hkt_scan_failure_snapshot: -> { @snapshots.hkt_scan_failure },
@@ -1752,7 +1802,7 @@ module Rigor
1752
1802
  unless @project_discovered_header_nestings.empty?
1753
1803
  tables[:discovered_header_nestings] = @project_discovered_header_nestings
1754
1804
  end
1755
- tables[:discovered_includes] = @project_discovered_includes unless @project_discovered_includes.empty?
1805
+ seed_mixin_tables(tables)
1756
1806
  unless @project_discovered_method_visibilities.empty?
1757
1807
  tables[:discovered_method_visibilities] = @project_discovered_method_visibilities
1758
1808
  end
@@ -1763,6 +1813,14 @@ module Rigor
1763
1813
  tables
1764
1814
  end
1765
1815
 
1816
+ # The two mixin tables: the ADR-24 instance-side `include` / `prepend` map and its #898 singleton-side
1817
+ # `extend` twin. Paired here because they are read as one picture of a class's ancestry, and split out
1818
+ # of {#project_scope_seed_tables} to keep it under the complexity budget.
1819
+ def seed_mixin_tables(tables)
1820
+ tables[:discovered_includes] = @project_discovered_includes unless @project_discovered_includes.empty?
1821
+ tables[:discovered_extends] = @project_discovered_extends unless @project_discovered_extends.empty?
1822
+ end
1823
+
1766
1824
  # ADR-46 slice 1 / issue #644 — the two SOURCE-ATTRIBUTION tables, read only by the recording accessors
1767
1825
  # (`Scope#record_class_dependency` for the class-declaration map, `Scope#record_constant_dependency`
1768
1826
  # for the constant-write map). A normal run carries neither. Extracted to keep
@@ -1802,12 +1860,6 @@ module Rigor
1802
1860
  tables[:published_constant_names] = names unless names.empty?
1803
1861
  end
1804
1862
 
1805
- # Issue #644 — the seeded `in_source_constants` table, joining the two cross-file constant producers.
1806
- # The whole-project literal table wins over a `pre_eval:` publication of the same name: both describe
1807
- # the same assignment, the literal table pins the value the write actually carries while ADR-17's
1808
- # widener erases it to the class, and listing a file under `pre_eval:` must never LOSE precision. The
1809
- # per-file table still wins over both (`ScopeIndexer.index`'s merge) — same-file stays the most
1810
- # specific authority.
1811
1863
  # Issue #644 — the LAST SEGMENTS of the published table, the run-wide half of
1812
1864
  # `Scope#published_constant?`. Seeded on EVERY run (unlike `constant_sources`, which only a recording
1813
1865
  # run needs) because {CheckRules::PublishedConstantGuard} asks the question on every `if` / `unless`.
@@ -1816,11 +1868,57 @@ module Rigor
1816
1868
  @project_constant_values.keys.to_set { |name| name.split("::").last }.freeze
1817
1869
  end
1818
1870
 
1871
+ # Issue #644 — the seeded `in_source_constants` table, joining the two cross-file constant producers.
1872
+ # The whole-project literal table wins over a `pre_eval:` publication of the same name: both describe
1873
+ # the same assignment, the literal table pins the value the write actually carries while ADR-17's
1874
+ # widener erases it to the class, and listing a file under `pre_eval:` must never LOSE precision. The
1875
+ # per-file table still wins over both (`ScopeIndexer.index`'s merge) — same-file stays the most
1876
+ # specific authority.
1819
1877
  def merged_seed_constants
1820
- return @project_constant_values if @project_pre_eval_constants.empty?
1821
- return @project_pre_eval_constants if @project_constant_values.empty?
1878
+ pre_eval = publishable_pre_eval_constants
1879
+ return @project_constant_values if pre_eval.empty?
1880
+ return pre_eval if @project_constant_values.empty?
1881
+
1882
+ pre_eval.merge(@project_constant_values).freeze
1883
+ end
1884
+
1885
+ # Issue #663 — the `pre_eval:` publication with every name an UNLISTED file also assigns retracted.
1886
+ # Without this a listed `X = :a` answered `Symbol` at every reader while a sibling `X = "str"` decided
1887
+ # the runtime value half the time: a confident wrong type, not lost precision, and the one asymmetry
1888
+ # #644's precedence work left standing. The retraction costs the opt-in nothing where it earns its
1889
+ # keep — a name only listed files write is untouched, and where the literal table also publishes it
1890
+ # already won (above).
1891
+ #
1892
+ # Conflict is read off #644's write attribution, which censuses every assigning form, so a name the
1893
+ # listed file's own typed walk widened is retracted by an unlisted `X += 1` or `A, X = 1, 2` as
1894
+ # readily as by a plain reassignment. Among LISTED files the rule is unchanged: `PreEvalConstants`
1895
+ # widens first and drops only on disagreement, so two listed files writing `1` and `2` still publish
1896
+ # `Integer` rather than being retracted for being two.
1897
+ def publishable_pre_eval_constants
1898
+ return @project_pre_eval_constants if @project_pre_eval_constants.empty?
1899
+
1900
+ listed = pre_eval_path_set
1901
+ kept = @project_pre_eval_constants.reject { |name, _| unlisted_constant_writer?(name, listed) }
1902
+ kept.size == @project_pre_eval_constants.size ? @project_pre_eval_constants : kept.freeze
1903
+ end
1904
+
1905
+ # True when some file outside `listed` assigns `name`. The wildcard key is consulted alongside the
1906
+ # name's own attribution ([#668](https://github.com/rigortype/rigor/issues/668)): a `k::X = 7` names
1907
+ # no target, and a listed file kept out of `paths:` (ADR-17 WD5 permits it) contributes no censused
1908
+ # name of its own for the wildcard's paths to have been folded into.
1909
+ def unlisted_constant_writer?(name, listed)
1910
+ segment = name.split("::").last
1911
+ writers = @project_constant_sources[name]
1912
+ wildcard = @project_constant_sources["#{Inference::ScopeIndexer::DYNAMIC_TARGET_PREFIX}#{segment}"]
1913
+ [writers, wildcard].any? do |paths|
1914
+ paths&.any? { |path| !listed.include?(File.expand_path(path)) }
1915
+ end
1916
+ end
1822
1917
 
1823
- @project_pre_eval_constants.merge(@project_constant_values).freeze
1918
+ # The listed `pre_eval:` files, expanded so a census path and a configured one compare as the same
1919
+ # file whichever spelling each arrived in.
1920
+ def pre_eval_path_set
1921
+ @pre_eval_path_set ||= @configuration.pre_eval.to_set { |path| File.expand_path(path) }
1824
1922
  end
1825
1923
 
1826
1924
  # ADR-46 — seed the instance + singleton `"path:line"` def-source tables (each only when non-empty).
@@ -3,6 +3,7 @@
3
3
  require "prism"
4
4
 
5
5
  require_relative "../environment"
6
+ require_relative "../project_environment"
6
7
  require_relative "../scope"
7
8
  require_relative "../cache/store"
8
9
  require_relative "../plugin"
@@ -73,12 +74,11 @@ module Rigor
73
74
  :rbs_extended_reporter, :boundary_cross_reporter,
74
75
  :prepare_diagnostics
75
76
 
76
- # @param configuration [Rigor::Configuration]
77
- # @param cache_store [Rigor::Cache::Store, nil] persistent cache the session exposes to plugin-side
77
+ # @param cache_store — persistent cache the session exposes to plugin-side
78
78
  # producers and the RBS loader. Pass `nil` to disable caching.
79
- # @param plugin_blueprints [Array<Rigor::Plugin::Blueprint>] replay descriptors. Empty array yields a
79
+ # @param plugin_blueprints replay descriptors. Empty array yields a
80
80
  # session with no plugin contributions.
81
- # @param explain [Boolean] when true, `#analyze` additionally emits one `:info` `fallback` diagnostic
81
+ # @param explain when true, `#analyze` additionally emits one `:info` `fallback` diagnostic
82
82
  # per directly-unrecognised node, mirroring {Rigor::Analysis::Runner#explain_diagnostics}.
83
83
  def initialize(configuration:, cache_store: nil, # rubocop:disable Metrics/MethodLength,Metrics/ParameterLists
84
84
  plugin_blueprints: [], explain: false, buffer: nil,
@@ -137,11 +137,7 @@ module Rigor
137
137
  rbs_extended_reporter: @rbs_extended_reporter,
138
138
  boundary_cross_reporter: @boundary_cross_reporter,
139
139
  source_rbs_synthesis_reporter: @source_rbs_synthesis_reporter,
140
- bundler_bundle_path: configuration.bundler_bundle_path,
141
- bundler_auto_detect: configuration.bundler_auto_detect,
142
- bundler_lockfile: configuration.bundler_lockfile,
143
- rbs_collection_lockfile: configuration.rbs_collection_lockfile,
144
- rbs_collection_auto_detect: configuration.rbs_collection_auto_detect,
140
+ **ProjectEnvironment.dependency_discovery_options(configuration),
145
141
  synthetic_method_index: @synthetic_method_index,
146
142
  project_patched_methods: @project_patched_methods,
147
143
  source_files: @source_files
@@ -271,7 +267,10 @@ module Rigor
271
267
  # `hkt_scan_failure` does: the directives are read by the registry scan, and under the pool the
272
268
  # PARENT never demands that scan, so a diagnostic wired off the parent's reporter would appear
273
269
  # at `--workers=0` and vanish at `--workers=N`. The demand above is what fills this.
274
- hkt_directive_errors: @rbs_extended_reporter.hkt_directive_errors
270
+ hkt_directive_errors: @rbs_extended_reporter.hkt_directive_errors,
271
+ # ADR-109 WD3 — the deprecated-form stream rides the same channel: the payload is read where
272
+ # the annotated method is dispatched, which under the pool is only ever inside a worker.
273
+ deprecated_forms: @rbs_extended_reporter.deprecated_forms
275
274
  },
276
275
  boundary_cross: @boundary_cross_reporter.entries,
277
276
  source_rbs_synthesis: @source_rbs_synthesis_reporter.entries,
@@ -51,14 +51,14 @@ module Rigor
51
51
  # migration note and a user's `bleeding_edge:` list both key on.
52
52
  #
53
53
  # @!attribute id
54
- # @return [String] the stable feature id (contract vocabulary).
54
+ # @return the stable feature id (contract vocabulary).
55
55
  # @!attribute summary
56
- # @return [String] a one-line description of what it changes. For a `:behaviour`
56
+ # @return a one-line description of what it changes. For a `:behaviour`
57
57
  # feature this is the *whole* explanation — there is no severity diff to read.
58
58
  # @!attribute kind
59
- # @return [Symbol] one of {KINDS}.
59
+ # @return one of {KINDS}.
60
60
  # @!attribute severity_overrides
61
- # @return [Hash{String => Symbol}] canonical rule id → the severity this feature
61
+ # @return canonical rule id → the severity this feature
62
62
  # imposes. Composed *below* the user's own `severity_overrides:` and *above* the
63
63
  # active `severity_profile` (see {Configuration::SeverityProfile.resolve}). Empty for
64
64
  # a `:behaviour` feature.
@@ -76,12 +76,10 @@ module Rigor
76
76
  super
77
77
  end
78
78
 
79
- # @return [Boolean]
80
79
  def severity?
81
80
  kind == :severity
82
81
  end
83
82
 
84
- # @return [Boolean]
85
83
  def behaviour?
86
84
  kind == :behaviour
87
85
  end
@@ -193,36 +191,30 @@ module Rigor
193
191
  # cleanup can lag graduation by as many releases as it takes. The id also stays in the
194
192
  # contract vocabulary the CHANGELOG migration note keys on. Entries are removed only once
195
193
  # no call site names them.
196
- #
197
- # @return [Array<String>]
198
194
  GRADUATED = [].freeze
199
195
 
200
196
  module_function
201
197
 
202
- # @return [Array<Feature>] the whole overlay.
198
+ # @return the whole overlay.
203
199
  def features
204
200
  FEATURES
205
201
  end
206
202
 
207
- # @return [Array<String>] every feature id in the overlay.
203
+ # @return every feature id in the overlay.
208
204
  def feature_ids
209
205
  FEATURES.map(&:id)
210
206
  end
211
207
 
212
- # @param id [String]
213
- # @return [Feature, nil]
214
208
  def feature(id)
215
209
  FEATURES.find { |f| f.id == id }
216
210
  end
217
211
 
218
- # @param id [String]
219
- # @return [Boolean] whether the id has graduated to default-on ({GRADUATED}).
212
+ # @return whether the id has graduated to default-on ({GRADUATED}).
220
213
  def graduated?(id)
221
214
  GRADUATED.include?(id)
222
215
  end
223
216
 
224
- # @param id [String]
225
- # @return [Boolean] whether the id names a feature this gem knows at all — queued or
217
+ # @return whether the id names a feature this gem knows at all — queued or
226
218
  # graduated. Distinct from "adopted"; see {Configuration#bleeding_edge_active?}.
227
219
  def known_id?(id)
228
220
  graduated?(id) || FEATURES.any? { |f| f.id == id }
@@ -234,10 +226,9 @@ module Rigor
234
226
  # `severity_overrides:` keeps an unknown rule id inert until it lands (robust across gem
235
227
  # versions).
236
228
  #
237
- # @param selector [Hash] `{ "mode" => "none" }`,
229
+ # @param selector `{ "mode" => "none" }`,
238
230
  # `{ "mode" => "all" }`, `{ "mode" => "all", "except" => [ids] }`,
239
231
  # or `{ "mode" => "list", "ids" => [ids] }`.
240
- # @return [Array<Feature>]
241
232
  def active_features(selector)
242
233
  case selector["mode"]
243
234
  when "all"
@@ -254,8 +245,7 @@ module Rigor
254
245
  # The merged severity-override map the active features impose for a selector. Frozen so
255
246
  # the result is `Ractor.shareable?`.
256
247
  #
257
- # @param selector [Hash] see {#active_features}.
258
- # @return [Hash{String => Symbol}]
248
+ # @param selector see {#active_features}.
259
249
  def severity_overrides_for(selector)
260
250
  active_features(selector).each_with_object({}) do |feature, acc|
261
251
  acc.merge!(feature.severity_overrides)
@@ -267,8 +257,7 @@ module Rigor
267
257
  # Precomputed once per Configuration; frozen (with frozen members) so the carrier stays
268
258
  # `Ractor.shareable?` across the worker boundary.
269
259
  #
270
- # @param selector [Hash] see {#active_features}.
271
- # @return [Set<String>]
260
+ # @param selector see {#active_features}.
272
261
  def active_ids_for(selector)
273
262
  Set.new(active_features(selector).map(&:id)).freeze
274
263
  end
@@ -276,8 +265,7 @@ module Rigor
276
265
  # Feature ids named by a selector that are NOT in the overlay (typo / graduated / from a
277
266
  # newer gem). Surfaced by `rigor show-bleedingedge` as a hint; never an error.
278
267
  #
279
- # @param selector [Hash] see {#active_features}.
280
- # @return [Array<String>]
268
+ # @param selector see {#active_features}.
281
269
  def unknown_selected_ids(selector)
282
270
  named =
283
271
  case selector["mode"]
@@ -118,7 +118,7 @@ module Rigor
118
118
  )
119
119
  end
120
120
 
121
- # @return [Rigor::Inference::HktRegistry] frozen registry
121
+ # @return frozen registry
122
122
  # pre-seeded with all bundled HKT registrations +
123
123
  # bodies. Allocated fresh each call rather than
124
124
  # memoised — memoisation through a module-level
@@ -242,7 +242,7 @@ module Rigor
242
242
  ["CSV", :parse_line, :singleton] => CSV_ROW_SPEC
243
243
  }.freeze
244
244
 
245
- # @return [Rigor::Type, nil] the reduced HKT type for
245
+ # @return the reduced HKT type for
246
246
  # the given (class_name, method_name, kind) triple,
247
247
  # or `nil` when no built-in override is registered.
248
248
  # When `arg_types` is supplied AND the entry carries a