rigortype 0.3.8 → 0.4.0

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 (634) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/data/capability_roles/capability_roles.rbs +36 -0
  4. data/data/core_overlay/enumerable.rbs +51 -0
  5. data/data/core_overlay/enumerator.rbs +84 -0
  6. data/data/core_overlay/hash_rbs3.rbs +41 -0
  7. data/data/core_overlay/process.rbs +40 -0
  8. data/data/core_overlay/string_io.rbs +33 -0
  9. data/data/effects/core.yml +3 -3
  10. data/data/gem_overlay/activesupport/core_ext.rbs +236 -17
  11. data/docs/handbook/02-everyday-types.md +17 -14
  12. data/docs/handbook/03-narrowing.md +132 -14
  13. data/docs/handbook/04-tuples-and-shapes.md +8 -6
  14. data/docs/handbook/05-methods-and-blocks.md +1 -1
  15. data/docs/handbook/06-classes.md +2 -2
  16. data/docs/handbook/07-rbs-and-extended.md +19 -1
  17. data/docs/handbook/10-sorbet.md +9 -10
  18. data/docs/handbook/11-sig-gen.md +525 -13
  19. data/docs/handbook/README.md +1 -1
  20. data/docs/handbook/appendix-elixir.md +2 -2
  21. data/docs/handbook/appendix-go.md +2 -2
  22. data/docs/handbook/appendix-java-csharp.md +2 -2
  23. data/docs/handbook/appendix-mypy.md +2 -2
  24. data/docs/handbook/appendix-phpstan.md +1 -1
  25. data/docs/handbook/appendix-rust.md +1 -1
  26. data/docs/handbook/appendix-type-theory.md +4 -4
  27. data/docs/handbook/appendix-typescript.md +1 -1
  28. data/docs/llms.txt +2 -0
  29. data/docs/manual/02-cli-reference.md +95 -6
  30. data/docs/manual/03-configuration.md +18 -0
  31. data/docs/manual/04-diagnostics.md +15 -0
  32. data/docs/manual/07-plugins.md +15 -5
  33. data/docs/manual/08-skills.md +23 -2
  34. data/docs/manual/10-mcp-server.md +3 -2
  35. data/docs/manual/11-ci.md +9 -0
  36. data/docs/manual/15-type-protection-coverage.md +8 -0
  37. data/docs/manual/16-rbs-extended-annotations.md +46 -8
  38. data/docs/manual/18-removing-dead-code.md +10 -8
  39. data/docs/manual/19-effect-labels.md +10 -0
  40. data/docs/manual/plugins/README.md +7 -0
  41. data/docs/manual/plugins/rigor-actioncable.md +8 -1
  42. data/docs/manual/plugins/rigor-actionmailer.md +7 -0
  43. data/docs/manual/plugins/rigor-actionpack.md +261 -0
  44. data/docs/manual/plugins/rigor-active-model-serializers.md +153 -0
  45. data/docs/manual/plugins/rigor-activejob.md +7 -0
  46. data/docs/manual/plugins/rigor-activerecord.md +138 -4
  47. data/docs/manual/plugins/rigor-activestorage.md +8 -1
  48. data/docs/manual/plugins/rigor-activesupport-core-ext.md +43 -7
  49. data/docs/manual/plugins/rigor-grape.md +106 -0
  50. data/docs/manual/plugins/rigor-graphql.md +23 -2
  51. data/docs/manual/plugins/rigor-pundit.md +8 -1
  52. data/docs/manual/plugins/rigor-rails-i18n.md +10 -5
  53. data/docs/manual/plugins/rigor-rails-routes.md +7 -0
  54. data/docs/manual/plugins/rigor-rbs-inline.md +229 -1
  55. data/docs/manual/plugins/rigor-sidekiq.md +8 -1
  56. data/docs/manual/plugins/rigor-sorbet.md +21 -5
  57. data/exe/rigor +19 -4
  58. data/lib/rigor/analysis/baseline.rb +3 -3
  59. data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +1 -1
  60. data/lib/rigor/analysis/check_rules/dead_version_guard_arms.rb +1 -5
  61. data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +167 -2
  62. data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +10 -2
  63. data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +189 -0
  64. data/lib/rigor/analysis/check_rules/main_pass_collector.rb +6 -4
  65. data/lib/rigor/analysis/check_rules/published_constant_guard.rb +15 -6
  66. data/lib/rigor/analysis/check_rules/rule_ids.rb +21 -6
  67. data/lib/rigor/analysis/check_rules/rule_walk.rb +41 -5
  68. data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +1 -1
  69. data/lib/rigor/analysis/check_rules/shadowed_rescue_collector.rb +1 -1
  70. data/lib/rigor/analysis/check_rules/source_arity.rb +323 -0
  71. data/lib/rigor/analysis/check_rules/special_global_setters.rb +146 -0
  72. data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +38 -4
  73. data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +0 -1
  74. data/lib/rigor/analysis/check_rules.rb +718 -79
  75. data/lib/rigor/analysis/crash_signature.rb +8 -24
  76. data/lib/rigor/analysis/dependency_recorder.rb +23 -0
  77. data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +1 -1
  78. data/lib/rigor/analysis/dependency_source_inference/builder.rb +0 -2
  79. data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +0 -2
  80. data/lib/rigor/analysis/dependency_source_inference/index.rb +5 -5
  81. data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +1 -2
  82. data/lib/rigor/analysis/dependency_source_inference/walker.rb +4 -4
  83. data/lib/rigor/analysis/effects_cache_probe.rb +3 -4
  84. data/lib/rigor/analysis/erb_template_detector.rb +1 -2
  85. data/lib/rigor/analysis/fact_store.rb +15 -1
  86. data/lib/rigor/analysis/incremental.rb +42 -0
  87. data/lib/rigor/analysis/incremental_session.rb +117 -26
  88. data/lib/rigor/analysis/plugin_fact_fingerprint.rb +0 -1
  89. data/lib/rigor/analysis/project_scan.rb +11 -1
  90. data/lib/rigor/analysis/reachability/graph.rb +3 -5
  91. data/lib/rigor/analysis/reachability/plugin_roots.rb +5 -5
  92. data/lib/rigor/analysis/reachability/project_files.rb +2 -2
  93. data/lib/rigor/analysis/reachability/scan.rb +5 -5
  94. data/lib/rigor/analysis/reachability/scan_cache.rb +3 -2
  95. data/lib/rigor/analysis/reachability/signature_scan.rb +2 -2
  96. data/lib/rigor/analysis/result.rb +1 -3
  97. data/lib/rigor/analysis/rule_catalog.rb +131 -1
  98. data/lib/rigor/analysis/run_cache_key.rb +21 -12
  99. data/lib/rigor/analysis/run_cache_probe.rb +3 -5
  100. data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +6 -8
  101. data/lib/rigor/analysis/runner/declaration_position.rb +1 -2
  102. data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +340 -33
  103. data/lib/rigor/analysis/runner/effect_annotation_residual_pass.rb +2 -3
  104. data/lib/rigor/analysis/runner/effect_envelope_pass.rb +18 -14
  105. data/lib/rigor/analysis/runner/pool_coordinator.rb +357 -97
  106. data/lib/rigor/analysis/runner/project_pre_passes.rb +38 -13
  107. data/lib/rigor/analysis/runner/run_snapshots.rb +6 -1
  108. data/lib/rigor/analysis/runner.rb +407 -51
  109. data/lib/rigor/analysis/template_unit_collector.rb +303 -0
  110. data/lib/rigor/analysis/template_unit_paths.rb +91 -0
  111. data/lib/rigor/analysis/template_unit_positions.rb +293 -0
  112. data/lib/rigor/analysis/template_units.rb +399 -0
  113. data/lib/rigor/analysis/worker_session.rb +62 -20
  114. data/lib/rigor/bleeding_edge.rb +10 -24
  115. data/lib/rigor/builtins/hkt_builtins.rb +3 -2
  116. data/lib/rigor/builtins/imported_refinements.rb +159 -21
  117. data/lib/rigor/builtins/predefined_constant_refinements.rb +5 -7
  118. data/lib/rigor/builtins/regex_refinement.rb +21 -13
  119. data/lib/rigor/builtins/static_return_refinements.rb +7 -6
  120. data/lib/rigor/cache/annotation_location.rb +2 -4
  121. data/lib/rigor/cache/descriptor.rb +63 -20
  122. data/lib/rigor/cache/engine_source.rb +33 -5
  123. data/lib/rigor/cache/file_digest.rb +9 -1
  124. data/lib/rigor/cache/incremental_snapshot.rb +72 -6
  125. data/lib/rigor/cache/rbs_cache_producer.rb +4 -0
  126. data/lib/rigor/cache/rbs_class_ancestor_table.rb +0 -3
  127. data/lib/rigor/cache/rbs_class_type_param_names.rb +0 -3
  128. data/lib/rigor/cache/rbs_constant_table.rb +0 -3
  129. data/lib/rigor/cache/rbs_descriptor.rb +112 -14
  130. data/lib/rigor/cache/rbs_environment.rb +8 -4
  131. data/lib/rigor/cache/rbs_known_class_names.rb +0 -3
  132. data/lib/rigor/cache/store.rb +76 -32
  133. data/lib/rigor/ci_detector.rb +1 -0
  134. data/lib/rigor/cli/annotate_command.rb +5 -6
  135. data/lib/rigor/cli/check_command.rb +57 -10
  136. data/lib/rigor/cli/check_invocation.rb +6 -11
  137. data/lib/rigor/cli/check_runner_factory.rb +1 -5
  138. data/lib/rigor/cli/coverage_command.rb +1 -1
  139. data/lib/rigor/cli/coverage_mutation.rb +12 -3
  140. data/lib/rigor/cli/coverage_scan.rb +1 -5
  141. data/lib/rigor/cli/diff_command.rb +1 -1
  142. data/lib/rigor/cli/doc_links.rb +4 -4
  143. data/lib/rigor/cli/docs_command.rb +6 -6
  144. data/lib/rigor/cli/doctor_command.rb +85 -38
  145. data/lib/rigor/cli/effects_command.rb +2 -2
  146. data/lib/rigor/cli/effects_diff_renderer.rb +3 -3
  147. data/lib/rigor/cli/effects_snapshot_command.rb +1 -1
  148. data/lib/rigor/cli/explain_command.rb +34 -1
  149. data/lib/rigor/cli/fused_protection_report.rb +7 -1
  150. data/lib/rigor/cli/lsp_command.rb +1 -1
  151. data/lib/rigor/cli/mcp_command.rb +1 -1
  152. data/lib/rigor/cli/measurement_integrity_warning.rb +4 -5
  153. data/lib/rigor/cli/mutation_fork_scan.rb +6 -6
  154. data/lib/rigor/cli/mutation_protection_report.rb +7 -1
  155. data/lib/rigor/cli/plugin_command.rb +4 -4
  156. data/lib/rigor/cli/plugins_command.rb +2 -1
  157. data/lib/rigor/cli/prism_colorizer.rb +1 -2
  158. data/lib/rigor/cli/protection_fork_scan.rb +6 -6
  159. data/lib/rigor/cli/show_bleedingedge_command.rb +1 -1
  160. data/lib/rigor/cli/sig_gen_command.rb +212 -31
  161. data/lib/rigor/cli/skill_command.rb +2 -2
  162. data/lib/rigor/cli/skill_deep_probe.rb +4 -4
  163. data/lib/rigor/cli/skill_describe.rb +35 -35
  164. data/lib/rigor/cli/trace_command.rb +4 -4
  165. data/lib/rigor/cli/trace_renderer.rb +5 -6
  166. data/lib/rigor/cli/triage_command.rb +1 -1
  167. data/lib/rigor/cli/type_of_command.rb +29 -11
  168. data/lib/rigor/cli/type_of_renderer.rb +20 -9
  169. data/lib/rigor/cli/type_of_template_probe.rb +189 -0
  170. data/lib/rigor/cli/type_scan_command.rb +4 -4
  171. data/lib/rigor/cli/unused_command.rb +11 -3
  172. data/lib/rigor/cli/upgrade_command.rb +1 -1
  173. data/lib/rigor/cli.rb +89 -9
  174. data/lib/rigor/config_audit.rb +30 -5
  175. data/lib/rigor/configuration/severity_profile.rb +25 -9
  176. data/lib/rigor/configuration.rb +109 -7
  177. data/lib/rigor/effects/ancestry_recorder.rb +191 -0
  178. data/lib/rigor/effects/attribution.rb +12 -5
  179. data/lib/rigor/effects/callee_rule.rb +368 -0
  180. data/lib/rigor/effects/catalog.rb +7 -4
  181. data/lib/rigor/effects/collector.rb +11 -5
  182. data/lib/rigor/effects/config_envelopes.rb +15 -10
  183. data/lib/rigor/effects/definition_context.rb +179 -0
  184. data/lib/rigor/effects/definition_lines.rb +25 -6
  185. data/lib/rigor/effects/effect_table.rb +11 -4
  186. data/lib/rigor/effects/entry_points.rb +0 -2
  187. data/lib/rigor/effects/envelope_check.rb +9 -9
  188. data/lib/rigor/effects/envelope_index.rb +20 -8
  189. data/lib/rigor/effects/file_collection.rb +59 -5
  190. data/lib/rigor/effects/framework_units.rb +5 -7
  191. data/lib/rigor/effects/identity.rb +20 -6
  192. data/lib/rigor/effects/inline_anchor.rb +7 -7
  193. data/lib/rigor/effects/label_intent.rb +3 -4
  194. data/lib/rigor/effects/liskov_check.rb +8 -8
  195. data/lib/rigor/effects/local_ownership.rb +38 -12
  196. data/lib/rigor/effects/method_key.rb +22 -1
  197. data/lib/rigor/effects/mutation_classifier.rb +23 -12
  198. data/lib/rigor/effects/plugin_facts.rb +47 -37
  199. data/lib/rigor/effects/propagator.rb +297 -19
  200. data/lib/rigor/effects/registry.rb +1 -1
  201. data/lib/rigor/effects/scanner.rb +122 -73
  202. data/lib/rigor/effects/signature_sources.rb +4 -6
  203. data/lib/rigor/effects/snapshot.rb +12 -11
  204. data/lib/rigor/effects/snapshot_diff.rb +1 -1
  205. data/lib/rigor/effects/summary.rb +27 -4
  206. data/lib/rigor/effects/unit_scan.rb +393 -38
  207. data/lib/rigor/effects/unknown_label_check.rb +3 -8
  208. data/lib/rigor/effects/unknown_label_report.rb +3 -4
  209. data/lib/rigor/effects/visibility.rb +101 -0
  210. data/lib/rigor/environment/bundle_sig_discovery.rb +6 -6
  211. data/lib/rigor/environment/class_registry.rb +3 -1
  212. data/lib/rigor/environment/failure_slot.rb +2 -2
  213. data/lib/rigor/environment/installed_gem_set.rb +85 -0
  214. data/lib/rigor/environment/lockfile_resolver.rb +68 -4
  215. data/lib/rigor/environment/member_consistency/comparator.rb +708 -0
  216. data/lib/rigor/environment/member_consistency.rb +298 -0
  217. data/lib/rigor/environment/missing_gem_constant_index.rb +4 -4
  218. data/lib/rigor/environment/rbs_collection_discovery.rb +5 -5
  219. data/lib/rigor/environment/rbs_coverage_report.rb +5 -5
  220. data/lib/rigor/environment/rbs_hierarchy.rb +3 -1
  221. data/lib/rigor/environment/rbs_loader.rb +674 -79
  222. data/lib/rigor/environment.rb +174 -24
  223. data/lib/rigor/flow_contribution/merger.rb +0 -2
  224. data/lib/rigor/flow_contribution.rb +11 -13
  225. data/lib/rigor/hashing/xxh3.rb +264 -0
  226. data/lib/rigor/inference/acceptance.rb +292 -17
  227. data/lib/rigor/inference/block_auto_splat.rb +216 -0
  228. data/lib/rigor/inference/block_call_timing.rb +338 -0
  229. data/lib/rigor/inference/block_parameter_binder.rb +75 -30
  230. data/lib/rigor/inference/block_repetition.rb +71 -0
  231. data/lib/rigor/inference/body_fixpoint.rb +7 -6
  232. data/lib/rigor/inference/budget_trace.rb +3 -6
  233. data/lib/rigor/inference/builtins/method_catalog.rb +2 -1
  234. data/lib/rigor/inference/builtins/string_catalog.rb +1 -1
  235. data/lib/rigor/inference/captured_locals.rb +389 -18
  236. data/lib/rigor/inference/closure_escape_analyzer.rb +159 -17
  237. data/lib/rigor/inference/content_join.rb +200 -27
  238. data/lib/rigor/inference/coverage_scanner.rb +4 -6
  239. data/lib/rigor/inference/def_return_typer.rb +11 -7
  240. data/lib/rigor/inference/define_method_block_self.rb +64 -0
  241. data/lib/rigor/inference/dynamic_origin.rb +1 -1
  242. data/lib/rigor/inference/element_read_widening.rb +180 -0
  243. data/lib/rigor/inference/error_info.rb +196 -0
  244. data/lib/rigor/inference/expression_typer.rb +2124 -468
  245. data/lib/rigor/inference/external_ancestor_resolution.rb +267 -0
  246. data/lib/rigor/inference/fork_map.rb +5 -7
  247. data/lib/rigor/inference/fresh_frame_blocks.rb +127 -0
  248. data/lib/rigor/inference/global_write_census.rb +239 -0
  249. data/lib/rigor/inference/guard_rebinding.rb +447 -0
  250. data/lib/rigor/inference/hash_lookup_mutation.rb +88 -0
  251. data/lib/rigor/inference/hkt_reducer.rb +2 -3
  252. data/lib/rigor/inference/hkt_registry.rb +4 -7
  253. data/lib/rigor/inference/index_write_widening.rb +16 -7
  254. data/lib/rigor/inference/indexed_narrowing.rb +61 -9
  255. data/lib/rigor/inference/jump_targets.rb +82 -0
  256. data/lib/rigor/inference/last_line/implicit_self.rb +210 -0
  257. data/lib/rigor/inference/last_line/self_evidence.rb +329 -0
  258. data/lib/rigor/inference/last_line.rb +340 -0
  259. data/lib/rigor/inference/last_status.rb +144 -0
  260. data/lib/rigor/inference/macro_block_self_type.rb +168 -21
  261. data/lib/rigor/inference/match_rebinding/calls.rb +281 -0
  262. data/lib/rigor/inference/match_rebinding/frame.rb +148 -0
  263. data/lib/rigor/inference/match_rebinding/operands.rb +236 -0
  264. data/lib/rigor/inference/match_rebinding/self_calls.rb +83 -0
  265. data/lib/rigor/inference/match_rebinding.rb +392 -0
  266. data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +36 -0
  267. data/lib/rigor/inference/method_dispatcher/block_folding.rb +87 -33
  268. data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +1 -1
  269. data/lib/rigor/inference/method_dispatcher/constant_folding.rb +305 -19
  270. data/lib/rigor/inference/method_dispatcher/data_folding.rb +1 -1
  271. data/lib/rigor/inference/method_dispatcher/facet_distribution.rb +147 -0
  272. data/lib/rigor/inference/method_dispatcher/file_folding.rb +1 -1
  273. data/lib/rigor/inference/method_dispatcher/hash_transform_keys_folding.rb +191 -0
  274. data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +6 -2
  275. data/lib/rigor/inference/method_dispatcher/json_folding.rb +1 -1
  276. data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +7 -1
  277. data/lib/rigor/inference/method_dispatcher/match_data_folding.rb +159 -0
  278. data/lib/rigor/inference/method_dispatcher/math_folding.rb +41 -3
  279. data/lib/rigor/inference/method_dispatcher/method_folding.rb +2 -5
  280. data/lib/rigor/inference/method_dispatcher/overload_selector.rb +165 -111
  281. data/lib/rigor/inference/method_dispatcher/process_folding.rb +56 -0
  282. data/lib/rigor/inference/method_dispatcher/proven_overload.rb +72 -0
  283. data/lib/rigor/inference/method_dispatcher/random_folding.rb +82 -0
  284. data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +1046 -69
  285. data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +25 -4
  286. data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +2 -8
  287. data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +1 -1
  288. data/lib/rigor/inference/method_dispatcher/self_substitute.rb +142 -0
  289. data/lib/rigor/inference/method_dispatcher/set_folding.rb +1 -1
  290. data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +129 -54
  291. data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +1 -1
  292. data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +1 -2
  293. data/lib/rigor/inference/method_dispatcher/struct_folding.rb +5 -6
  294. data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +85 -4
  295. data/lib/rigor/inference/method_dispatcher/time_folding.rb +1 -1
  296. data/lib/rigor/inference/method_dispatcher/universal_object_dispatch.rb +1 -2
  297. data/lib/rigor/inference/method_dispatcher/uri_folding.rb +1 -1
  298. data/lib/rigor/inference/method_dispatcher.rb +225 -25
  299. data/lib/rigor/inference/method_parameter_binder.rb +12 -9
  300. data/lib/rigor/inference/multi_target_binder.rb +341 -55
  301. data/lib/rigor/inference/mutation_rejoin.rb +171 -0
  302. data/lib/rigor/inference/mutation_widening.rb +156 -85
  303. data/lib/rigor/inference/narrowing.rb +835 -162
  304. data/lib/rigor/inference/operand_effects.rb +167 -0
  305. data/lib/rigor/inference/operand_walk.rb +88 -0
  306. data/lib/rigor/inference/optimistic_origin.rb +153 -16
  307. data/lib/rigor/inference/origin_lookup.rb +2 -3
  308. data/lib/rigor/inference/parameter_inference_collector.rb +7 -7
  309. data/lib/rigor/inference/pre_eval_constants.rb +6 -5
  310. data/lib/rigor/inference/precision_scanner.rb +3 -4
  311. data/lib/rigor/inference/project_method_ownership.rb +136 -0
  312. data/lib/rigor/inference/project_patched_methods.rb +9 -4
  313. data/lib/rigor/inference/project_patched_scanner.rb +10 -6
  314. data/lib/rigor/inference/protection_scanner.rb +1 -2
  315. data/lib/rigor/inference/range_constant.rb +57 -0
  316. data/lib/rigor/inference/rbs_type_translator.rb +49 -11
  317. data/lib/rigor/inference/receiver_alias.rb +93 -4
  318. data/lib/rigor/inference/receiver_blind_block.rb +219 -0
  319. data/lib/rigor/inference/refinement_mutation.rb +76 -0
  320. data/lib/rigor/inference/repeated_or_writes.rb +463 -0
  321. data/lib/rigor/inference/return_barrier.rb +54 -0
  322. data/lib/rigor/inference/rewrite_mutation.rb +120 -0
  323. data/lib/rigor/inference/scope_indexer.rb +5228 -627
  324. data/lib/rigor/inference/statement_evaluator.rb +3452 -595
  325. data/lib/rigor/inference/stored_block_call.rb +54 -0
  326. data/lib/rigor/inference/string_mutation.rb +97 -0
  327. data/lib/rigor/inference/struct_fold_safety.rb +6 -7
  328. data/lib/rigor/inference/synthetic_method_index.rb +1 -2
  329. data/lib/rigor/inference/synthetic_method_scanner.rb +4 -6
  330. data/lib/rigor/inference/unknown_store_widening.rb +200 -0
  331. data/lib/rigor/inference/unthreaded_rebinds.rb +282 -0
  332. data/lib/rigor/inference/version_guard.rb +28 -21
  333. data/lib/rigor/inference/void_origin.rb +3 -3
  334. data/lib/rigor/inference/void_tail_summary.rb +2 -4
  335. data/lib/rigor/language_server/buffer_table.rb +4 -4
  336. data/lib/rigor/language_server/completion_provider.rb +1 -1
  337. data/lib/rigor/language_server/debouncer.rb +0 -1
  338. data/lib/rigor/language_server/diagnostic_publisher.rb +7 -6
  339. data/lib/rigor/language_server/document_symbol_provider.rb +1 -1
  340. data/lib/rigor/language_server/folding_range_provider.rb +1 -1
  341. data/lib/rigor/language_server/hover_provider.rb +1 -1
  342. data/lib/rigor/language_server/hover_renderer.rb +4 -4
  343. data/lib/rigor/language_server/incremental_sync.rb +6 -6
  344. data/lib/rigor/language_server/project_context.rb +7 -8
  345. data/lib/rigor/language_server/publish_batcher.rb +2 -2
  346. data/lib/rigor/language_server/selection_range_provider.rb +2 -2
  347. data/lib/rigor/language_server/server.rb +9 -9
  348. data/lib/rigor/language_server/signature_help_provider.rb +1 -1
  349. data/lib/rigor/language_server/uri.rb +1 -1
  350. data/lib/rigor/mcp/server.rb +2 -1
  351. data/lib/rigor/plugin/base.rb +258 -26
  352. data/lib/rigor/plugin/box_probe.rb +91 -0
  353. data/lib/rigor/plugin/bundled_catalog.rb +167 -0
  354. data/lib/rigor/plugin/effect_attribution.rb +65 -11
  355. data/lib/rigor/plugin/effect_entry_points.rb +3 -3
  356. data/lib/rigor/plugin/fact_store.rb +6 -6
  357. data/lib/rigor/plugin/io_boundary.rb +93 -8
  358. data/lib/rigor/plugin/isolation.rb +29 -6
  359. data/lib/rigor/plugin/loader.rb +33 -13
  360. data/lib/rigor/plugin/macro/block_as_method.rb +45 -6
  361. data/lib/rigor/plugin/macro/heredoc_template.rb +1 -1
  362. data/lib/rigor/plugin/macro/trait_registry.rb +1 -1
  363. data/lib/rigor/plugin/manifest.rb +94 -11
  364. data/lib/rigor/plugin/registry.rb +76 -12
  365. data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +21 -4
  366. data/lib/rigor/plugin/template_unit.rb +196 -0
  367. data/lib/rigor/plugin/trust_policy.rb +2 -4
  368. data/lib/rigor/plugin/type_node_resolver.rb +3 -3
  369. data/lib/rigor/plugin.rb +1 -0
  370. data/lib/rigor/plugin_gap_advisory.rb +96 -0
  371. data/lib/rigor/project_environment.rb +138 -0
  372. data/lib/rigor/protection/analysis_guard.rb +93 -14
  373. data/lib/rigor/protection/closure_kill_oracle.rb +67 -23
  374. data/lib/rigor/protection/dependency_closure.rb +5 -8
  375. data/lib/rigor/protection/diagnostic_oracle.rb +2 -2
  376. data/lib/rigor/protection/discovery_seed.rb +14 -12
  377. data/lib/rigor/protection/kill_signature.rb +1 -4
  378. data/lib/rigor/protection/measurement_integrity.rb +1 -3
  379. data/lib/rigor/protection/mutation_cache.rb +7 -11
  380. data/lib/rigor/protection/mutation_scanner.rb +12 -15
  381. data/lib/rigor/protection/mutator.rb +2 -1
  382. data/lib/rigor/protection/test_suite_oracle.rb +5 -5
  383. data/lib/rigor/rbs_extended/conformance_checker.rb +4 -3
  384. data/lib/rigor/rbs_extended/envelope_scanner.rb +4 -6
  385. data/lib/rigor/rbs_extended/reporter.rb +36 -10
  386. data/lib/rigor/rbs_extended.rb +88 -21
  387. data/lib/rigor/reflection/constant_ancestors.rb +97 -0
  388. data/lib/rigor/reflection/constant_path.rb +139 -0
  389. data/lib/rigor/reflection.rb +93 -110
  390. data/lib/rigor/runtime/jit.rb +6 -8
  391. data/lib/rigor/scope/discovery_index.rb +165 -2
  392. data/lib/rigor/scope.rb +1041 -32
  393. data/lib/rigor/sig_gen/alias_index.rb +289 -0
  394. data/lib/rigor/sig_gen/classification.rb +22 -5
  395. data/lib/rigor/sig_gen/declaration_equivalence.rb +127 -0
  396. data/lib/rigor/sig_gen/effect_annotation.rb +202 -0
  397. data/lib/rigor/sig_gen/generator.rb +673 -53
  398. data/lib/rigor/sig_gen/inline_declarations.rb +184 -0
  399. data/lib/rigor/sig_gen/layout_index.rb +3 -4
  400. data/lib/rigor/sig_gen/meta_class_shape.rb +3 -5
  401. data/lib/rigor/sig_gen/method_candidate.rb +47 -3
  402. data/lib/rigor/sig_gen/observation_collector.rb +18 -16
  403. data/lib/rigor/sig_gen/path_mapper.rb +4 -6
  404. data/lib/rigor/sig_gen/rbs_validity.rb +4 -4
  405. data/lib/rigor/sig_gen/renderer.rb +128 -14
  406. data/lib/rigor/sig_gen/skip_reason_catalog.rb +154 -0
  407. data/lib/rigor/sig_gen/superclass_spelling.rb +27 -0
  408. data/lib/rigor/sig_gen/type_elaborator.rb +1 -3
  409. data/lib/rigor/sig_gen/write_result.rb +19 -3
  410. data/lib/rigor/sig_gen/writer.rb +189 -41
  411. data/lib/rigor/sig_gen.rb +3 -0
  412. data/lib/rigor/signature_path_audit.rb +153 -6
  413. data/lib/rigor/source/literals.rb +0 -23
  414. data/lib/rigor/source/node_children.rb +0 -2
  415. data/lib/rigor/source/node_locator.rb +5 -11
  416. data/lib/rigor/source/node_walker.rb +0 -6
  417. data/lib/rigor/source/parameter_envelope.rb +72 -0
  418. data/lib/rigor/source.rb +1 -0
  419. data/lib/rigor/triage/catalogue.rb +1 -3
  420. data/lib/rigor/triage.rb +3 -5
  421. data/lib/rigor/type/accepts_result.rb +24 -6
  422. data/lib/rigor/type/combinator.rb +144 -5
  423. data/lib/rigor/type/data_class.rb +2 -2
  424. data/lib/rigor/type/data_instance.rb +4 -4
  425. data/lib/rigor/type/difference.rb +1 -0
  426. data/lib/rigor/type/float_range.rb +128 -0
  427. data/lib/rigor/type/hash_shape.rb +6 -6
  428. data/lib/rigor/type/integer_range.rb +13 -8
  429. data/lib/rigor/type/nominal.rb +8 -2
  430. data/lib/rigor/type/refined.rb +4 -3
  431. data/lib/rigor/type/struct_class.rb +3 -3
  432. data/lib/rigor/type/struct_instance.rb +4 -4
  433. data/lib/rigor/type.rb +1 -0
  434. data/lib/rigor/type_node/generic.rb +1 -1
  435. data/lib/rigor/type_node/range_literal.rb +25 -0
  436. data/lib/rigor/type_node/resolver_chain.rb +1 -1
  437. data/lib/rigor/type_node.rb +1 -0
  438. data/lib/rigor/version.rb +1 -1
  439. data/lib/rigor.rb +1 -0
  440. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +0 -4
  441. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +0 -1
  442. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +0 -2
  443. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/effects.rb +1 -0
  444. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +10 -5
  445. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +0 -4
  446. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +3 -5
  447. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +1 -4
  448. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +14 -4
  449. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +32 -30
  450. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +0 -1
  451. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +1 -3
  452. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_scan.rb +96 -0
  453. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/effects.rb +65 -8
  454. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/erb_compiler.rb +270 -0
  455. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/render_locals.rb +402 -0
  456. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +370 -0
  457. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_units.rb +132 -0
  458. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +264 -3
  459. data/plugins/rigor-actionpack/sig/action_controller.rbs +71 -0
  460. data/plugins/rigor-actionpack/sig/action_view.rbs +43 -0
  461. data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_discoverer.rb +220 -0
  462. data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_index.rb +56 -0
  463. data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers.rb +263 -0
  464. data/plugins/rigor-active-model-serializers/lib/rigor-active-model-serializers.rb +7 -0
  465. data/plugins/rigor-active-model-serializers/sig/active_model_serializers.rbs +45 -0
  466. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +0 -4
  467. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +2 -1
  468. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +0 -1
  469. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +0 -2
  470. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/recurring_scan.rb +1 -1
  471. data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +10 -5
  472. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +35 -3
  473. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/effects.rb +72 -12
  474. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +383 -7
  475. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +14 -6
  476. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +1 -2
  477. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +1 -2
  478. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +322 -41
  479. data/plugins/rigor-activerecord/sig/active_record/framework.rbs +123 -0
  480. data/plugins/rigor-activerecord/sig/active_record/relation.rbs +206 -31
  481. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +26 -14
  482. data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +9 -2
  483. data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +9 -2
  484. data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +290 -19
  485. data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +1 -0
  486. data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +3 -0
  487. data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +9 -7
  488. data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +7 -3
  489. data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +1 -0
  490. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +8 -6
  491. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +11 -7
  492. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -11
  493. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +9 -4
  494. data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +2 -0
  495. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +0 -5
  496. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +0 -1
  497. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +0 -1
  498. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +8 -1
  499. data/plugins/rigor-ffi/lib/rigor/plugin/ffi/types.rb +1 -1
  500. data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +36 -4
  501. data/plugins/rigor-ffi-rzmq/lib/rigor/plugin/ffi_rzmq.rb +1 -0
  502. data/plugins/rigor-grape/lib/rigor/plugin/grape.rb +141 -0
  503. data/plugins/rigor-grape/lib/rigor-grape.rb +6 -0
  504. data/plugins/rigor-grape/sig/grape.rbs +263 -0
  505. data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +8 -6
  506. data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +78 -5
  507. data/plugins/rigor-graphql/sig/graphql.rbs +485 -0
  508. data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +1 -0
  509. data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +2 -1
  510. data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +2 -3
  511. data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +1 -0
  512. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +0 -5
  513. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/authorization_scan.rb +2 -2
  514. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +0 -1
  515. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +0 -1
  516. data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +12 -7
  517. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +0 -12
  518. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +1 -3
  519. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +0 -1
  520. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +36 -37
  521. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/acronyms.rb +5 -5
  522. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +0 -10
  523. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +5 -3
  524. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +3 -2
  525. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/grape_api_discoverer.rb +2 -2
  526. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +2 -2
  527. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +9 -10
  528. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +2 -3
  529. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +10 -17
  530. data/plugins/rigor-railties/lib/rigor/plugin/railties.rb +1 -0
  531. data/plugins/rigor-rbnacl/lib/rigor/plugin/rbnacl.rb +13 -1
  532. data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline/same_line_annotations.rb +149 -0
  533. data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +324 -18
  534. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +0 -3
  535. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +0 -3
  536. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +1 -5
  537. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +2 -3
  538. data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +1 -0
  539. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +0 -3
  540. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +1 -0
  541. data/plugins/rigor-sassc/lib/rigor/plugin/sassc.rb +1 -0
  542. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +1 -9
  543. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +1 -0
  544. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +0 -4
  545. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/effects.rb +1 -1
  546. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/schedule_scan.rb +2 -1
  547. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +0 -1
  548. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +0 -2
  549. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +10 -5
  550. data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +1 -0
  551. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +2 -5
  552. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +1 -4
  553. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +3 -9
  554. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +4 -4
  555. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +1 -2
  556. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +3 -5
  557. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +7 -5
  558. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +51 -6
  559. data/plugins/rigor-sorbet/sig/sorbet.rbs +277 -0
  560. data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +1 -0
  561. data/sig/rigor/analysis/baseline.rbs +69 -7
  562. data/sig/rigor/analysis/fact_store.rbs +1 -1
  563. data/sig/rigor/analysis/project_scan.rbs +74 -0
  564. data/sig/rigor/analysis/reachability/scan_cache.rbs +12 -0
  565. data/sig/rigor/cache.rbs +2 -3
  566. data/sig/rigor/effects/config_envelopes.rbs +100 -0
  567. data/sig/rigor/effects/effect_table.rbs +60 -0
  568. data/sig/rigor/effects/envelope.rbs +97 -0
  569. data/sig/rigor/effects/envelope_index.rbs +33 -0
  570. data/sig/rigor/effects/file_collection.rbs +81 -0
  571. data/sig/rigor/effects/label.rbs +26 -0
  572. data/sig/rigor/effects/label_set.rbs +46 -0
  573. data/sig/rigor/effects/method_key.rbs +24 -0
  574. data/sig/rigor/effects/origin.rbs +50 -0
  575. data/sig/rigor/effects/plugin_facts.rbs +141 -0
  576. data/sig/rigor/effects/registry.rbs +68 -0
  577. data/sig/rigor/effects/summary.rbs +50 -0
  578. data/sig/rigor/effects/taint_cause.rbs +12 -0
  579. data/sig/rigor/environment.rbs +17 -10
  580. data/sig/rigor/inference/optimistic_origin.rbs +10 -0
  581. data/sig/rigor/inference.rbs +9 -14
  582. data/sig/rigor/plugin/additional_initializer.rbs +36 -0
  583. data/sig/rigor/plugin/base.rbs +30 -7
  584. data/sig/rigor/plugin/effect_ancestry.rbs +27 -0
  585. data/sig/rigor/plugin/effect_attribution.rbs +66 -0
  586. data/sig/rigor/plugin/effect_edge.rbs +33 -0
  587. data/sig/rigor/plugin/effect_entry_points.rbs +25 -0
  588. data/sig/rigor/plugin/io_boundary.rbs +4 -0
  589. data/sig/rigor/plugin/loader.rbs +3 -3
  590. data/sig/rigor/plugin/manifest.rbs +51 -11
  591. data/sig/rigor/plugin/protocol_contract.rbs +68 -0
  592. data/sig/rigor/plugin/registry.rbs +62 -1
  593. data/sig/rigor/plugin.rbs +1 -1
  594. data/sig/rigor/rbs_extended.rbs +1 -1
  595. data/sig/rigor/reflection.rbs +9 -6
  596. data/sig/rigor/scope.rbs +148 -12
  597. data/sig/rigor/sig_gen/skip_reason_catalog.rbs +21 -0
  598. data/sig/rigor/source.rbs +4 -4
  599. data/sig/rigor/testing.rbs +10 -4
  600. data/sig/rigor/type.rbs +33 -1
  601. data/sig/rigor.rbs +39 -20
  602. data/skills/rigor-ask/SKILL.md +16 -11
  603. data/skills/rigor-baseline-reduce/SKILL.md +4 -6
  604. data/skills/rigor-ci-setup/SKILL.md +17 -21
  605. data/skills/rigor-doctor/SKILL.md +24 -22
  606. data/skills/rigor-doctor/references/01-checks.md +97 -33
  607. data/skills/rigor-editor-setup/SKILL.md +6 -4
  608. data/skills/rigor-mcp-setup/SKILL.md +5 -4
  609. data/skills/rigor-monkeypatch-resolve/SKILL.md +5 -3
  610. data/skills/rigor-next-steps/SKILL.md +4 -2
  611. data/skills/rigor-plugin-author/SKILL.md +19 -23
  612. data/skills/rigor-plugin-author/references/01-plan-and-scaffold.md +9 -8
  613. data/skills/rigor-plugin-author/references/02-walker-and-types.md +25 -27
  614. data/skills/rigor-plugin-author/references/03-test-and-ship.md +6 -8
  615. data/skills/rigor-plugin-review/SKILL.md +6 -4
  616. data/skills/rigor-plugin-review/references/01-best-practices-checklist.md +2 -1
  617. data/skills/rigor-plugin-tune/SKILL.md +4 -2
  618. data/skills/rigor-project-init/SKILL.md +15 -10
  619. data/skills/rigor-project-init/references/01-detect.md +13 -9
  620. data/skills/rigor-project-init/references/02-configure.md +43 -14
  621. data/skills/rigor-project-init/references/03-baseline-and-bugs.md +14 -14
  622. data/skills/rigor-project-init/references/04-sig-uplift.md +27 -14
  623. data/skills/rigor-project-init/references/06-agent-contract.md +67 -0
  624. data/skills/rigor-protection-uplift/SKILL.md +4 -6
  625. data/skills/rigor-rbs-setup/SKILL.md +4 -2
  626. data/skills/rigor-type-oracle/SKILL.md +226 -0
  627. data/skills/rigor-type-oracle/references/01-oracle-commands.md +265 -0
  628. data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +52 -0
  629. data/skills/rigor-type-oracle/references/03-gap-protocol.md +125 -0
  630. data/skills/rigor-unused-adjudicate/SKILL.md +12 -7
  631. data/skills/rigor-upgrade/SKILL.md +13 -8
  632. metadata +133 -3
  633. data/lib/rigor/cli/probe_environment.rb +0 -85
  634. data/sig/rigor/inference/builtins/numeric_catalog.rbs +0 -3
@@ -29,13 +29,21 @@ errors_demo.rb:24:1: error: `User.find` expects at least 1 argument, got 0 [plug
29
29
  | --- | --- | --- |
30
30
  | Recognised `Model.find` / `Model.find_by` / `Model.where` call | `:info` | `plugin.activerecord.model-call` |
31
31
  | `Model.find_by(unknown: ...)` / `Model.where(unknown: ...)` | `:error` | `plugin.activerecord.unknown-column` |
32
- | `Model.find` with 0 args | `:error` | `plugin.activerecord.wrong-arity` |
32
+ | `Model.find` with 0 args and no block (unless the model defines `self.find`) | `:error` | `plugin.activerecord.wrong-arity` |
33
33
  | No schema source (`db/schema.rb` or `db/structure.sql`) present — reduced mode | `:info` | `plugin.activerecord.load-error` |
34
34
  | A schema source that exists but cannot be read or parsed | `:warning` | `plugin.activerecord.load-error` |
35
35
 
36
36
  Did-you-mean suggestions use `DidYouMean` fuzzy matching against
37
37
  the resolved table's column names.
38
38
 
39
+ A model that defines its own `self.find` owns that method's arity.
40
+ The plugin reports no `wrong-arity` for it, and no note for the
41
+ several-id or block form, where the call types as the model's
42
+ method rather than Rails' `find`. A single id is still noted as the
43
+ model, which is how it types. In an editor, a `self.find` in the
44
+ same file is not yet seen here, so the note and the error still
45
+ appear there ([#1329](https://github.com/rigortype/rigor/issues/1329)).
46
+
39
47
  ## Configuration
40
48
 
41
49
  ```yaml
@@ -61,8 +69,17 @@ All keys are optional. Tweak them when:
61
69
  ## What it infers
62
70
 
63
71
  The plugin contributes call-site types as well as diagnostics.
64
- Class-side: `User.find(1)` → `User`, `User.find_by(...)` →
65
- `User | nil`, `User.find_by!(...)` → non-nullable `User`.
72
+ Class-side: `User.find(1)` → `User`, `User.find(1, 2)` →
73
+ `Array[User]`, `User.find_by(...)` → `User | nil`,
74
+ `User.find_by!(...)` → non-nullable `User`. A single argument
75
+ stays `User` even when it is an Array (`User.find([1, 2])`), so
76
+ that an untyped one, such as `params[:id]`, keeps the model type.
77
+ A relation or association (`user.posts.find(1, 2)`) answers the
78
+ same way. With a block, `find` is `Enumerable#find` over the
79
+ records, on the class and on a relation alike:
80
+ `User.find { |u| u.admin? }` → `User | nil`, and it takes no id.
81
+ The block's parameter is the model on a relation; on the class
82
+ side it stays untyped.
66
83
  Instance-side: a column read (`user.name`) narrows to the
67
84
  column's value type, `user.admin?` to `bool`, and a singular
68
85
  association (`post.user`) to the target model.
@@ -76,6 +93,84 @@ Chained query methods keep the element type, and iteration
76
93
  scope invoked on a typed relation (`User.where(...).published`)
77
94
  never surfaces a false `call.undefined-method`.
78
95
 
96
+ A `scope` declared inside a concern's `included do ... end` block
97
+ counts as the including model's own. `Account.without_suspended`
98
+ types as `ActiveRecord::Relation[Account]` when `Account` includes
99
+ the concern that declares the scope — directly, or through another
100
+ concern that concern includes. A concern included once in your
101
+ base class (`ApplicationRecord`) reaches every model under it.
102
+ Attribution follows the `include` you wrote, not the name: a
103
+ model that includes nothing gets nothing, whatever some other
104
+ concern in the project declares.
105
+
106
+ The gate is the `included do ... end` block itself. A scope
107
+ declared some other way — in a `class_methods do` block, a
108
+ hand-written `def self.included(base)` with `base.class_eval`, or
109
+ directly in the body of your base class rather than in a concern —
110
+ is not folded, and the call stays as untyped as it was.
111
+
112
+ `belongs_to` / `has_one` / `has_many` /
113
+ `has_and_belongs_to_many` declared in that same `included do ...
114
+ end` block count as the including model's own too, with the same
115
+ `include`-edge attribution: `account.user` narrows to
116
+ `User | nil` when `Account` includes the concern that declares
117
+ `has_one :user`, and `where(user: ...)` stops reporting a false
118
+ `unknown-column`. A model that declares the association itself
119
+ keeps its own version.
120
+
121
+ ### The names a macro defines
122
+
123
+ Three macro families define ordinary instance methods that are
124
+ neither columns nor associations, and the model's recorded
125
+ surface now carries their names:
126
+
127
+ - `delegate :followers_count, to: :account_stat` — every
128
+ delegated name, including the `prefix:` spellings
129
+ (`delegate :can?, to: :user, prefix: true` defines
130
+ `user_can?`). `delegate` is read from the model body, from a
131
+ concern's `included do ... end`, and from a concern's own
132
+ top level, where it defines an instance method the including
133
+ model inherits.
134
+ - Attachment macros — Paperclip's `has_attached_file :avatar`
135
+ (`avatar`, `avatar=`, `avatar?`) and Active Storage's
136
+ `has_one_attached` / `has_many_attached` (`banner`,
137
+ `banner_attachment`, `banner_blob`; `docs`,
138
+ `docs_attachments`, `docs_blobs`). Paperclip's
139
+ `avatar_file_name` / `avatar_content_type` / `avatar_file_size`
140
+ / `avatar_updated_at` are real columns, so they come from your
141
+ schema rather than from the macro.
142
+ - `enum` value predicates — `enum :visibility, { limited: 4 },
143
+ suffix: :visibility` defines `limited_visibility?`, and
144
+ `prefix:` / `_prefix:` / `_suffix:` are read the same way. An
145
+ `enum` declared `instance_methods: false` defines none of
146
+ them, and none are recorded.
147
+
148
+ These are recorded as NAMES. Nothing here says what a delegated
149
+ method returns, and the plugin contributes no type for one — the
150
+ value is that a consumer asking "does this model answer
151
+ `followers_count`?" gets the right answer. The consumer this was
152
+ built for is
153
+ [`rigor-active-model-serializers`](rigor-active-model-serializers.md),
154
+ which types a serializer's `object` only when the candidate model
155
+ answers every name the serializer reads.
156
+
157
+ A declaration this plugin cannot read off the source contributes
158
+ nothing rather than a guess: a `prefix: true` whose `to:` is a
159
+ method call, a non-literal `prefix:`, a computed enum value list.
160
+
161
+ If the project also installs `activerecord` through
162
+ `rbs collection install`, the collection declares
163
+ `ActiveRecord::Relation` without a type parameter while the
164
+ plugin declares `ActiveRecord::Relation[Elem]`, and RBS cannot
165
+ hold both. The plugin's declaration stands down: relation call
166
+ sites still type as `ActiveRecord::Relation[Model]`, but calls
167
+ into a relation resolve against the collection's declaration,
168
+ so the plugin's element typing (`.first` as `Model?`, for
169
+ example) is unavailable, and the run reports one
170
+ `rbs.coverage.plugin-signature-stood-down` info row naming both
171
+ files. Nothing is broken; the plugin's typing returns only when
172
+ the collection stops declaring the class.
173
+
79
174
  `User.table_name` types as `String`, and as the exact string
80
175
  only when your source says the name: a literal
81
176
  `self.table_name = "people"` on the class or on an STI ancestor,
@@ -118,6 +213,21 @@ than none, so `Blog::Post`'s column, alias and association checks
118
213
  stand down entirely rather than run against a table that might not
119
214
  be the real one.
120
215
 
216
+ ## Framework constants resolve
217
+
218
+ The bundled signatures also name Active Record's exception hierarchy
219
+ (`ActiveRecordError` and the classes apps rescue: `RecordNotFound`,
220
+ `RecordInvalid`, `RecordNotSaved`, `StatementInvalid`,
221
+ `RecordNotUnique`, `StaleObjectError`, …), the `ActiveModel`
222
+ namespace, and `Arel`. `rescue ActiveRecord::RecordNotFound => e` types
223
+ `e` instead of leaving it opaque.
224
+
225
+ None of them declares a method surface — the declaration buys constant
226
+ resolution and asserts nothing else, so `e.record` and every other
227
+ member left out stays lenient rather than reported.
228
+ `ActiveRecord::Base` is deliberately **not** declared: closing it would
229
+ close every model in the project.
230
+
121
231
  ## Limitations
122
232
 
123
233
  - **Direct-superclass match only.** `class Admin < User` where
@@ -154,12 +264,25 @@ be the real one.
154
264
  the column-dependent half stands down — column readers stay
155
265
  untyped and `where(col:)` keys are not validated, exactly as they
156
266
  are for a table the schema does not describe. The plugin says so
157
- once per run at `:info`. Committing a schema dump (or pointing
267
+ once per run at `:info`, positioned on `.rigor.yml` — it is a
268
+ fact about your configuration, not about any one source file,
269
+ and you get the same single row with `--workers` as without. If
270
+ you baselined this row at its old position (a controller or a
271
+ model), that baseline entry no longer matches it — run `rigor
272
+ baseline regenerate`. Committing a schema dump (or pointing
158
273
  `schema_file` / `structure_sql_file` at one) turns the column half
159
274
  back on from the next cold run — a warm cache keeps serving the
160
275
  reduced index until it is invalidated, so use `rigor check
161
276
  --no-cache` (or `make cache-clean`) if you want to see the change
162
277
  immediately.
278
+ - **Every kind of relation shares one signature.**
279
+ `user.posts`, `user.posts.where(...)` and `Post.where(...)` all
280
+ type as `ActiveRecord::Relation[Post]`, although only the first
281
+ is an association's `CollectionProxy`, so the signature they share
282
+ accepts the widest argument list any of them takes.
283
+ `user.posts.delete_all(:nullify)` is valid and not reported. The
284
+ same call on the other two raises `ArgumentError` at run time, and
285
+ is not reported either.
163
286
  - **Column reads, not setters.** The plugin types instance-side
164
287
  column *reads* (`user.name`, `user.admin?`) and singular
165
288
  associations, but not the `name=` setter or the dirty-tracking
@@ -173,6 +296,17 @@ be the real one.
173
296
 
174
297
  ## Plugin internals
175
298
 
299
+ The plugin also answers `Plugin::Base#declared_members` (ADR-113
300
+ WD4): it enumerates each model's synthesized members — column
301
+ readers and `column?` predicates, association accessors, declared
302
+ scopes, enum attributes, and macro-defined names — off the prepared
303
+ model index, so `rigor lens` can list `User`'s members without a
304
+ grep-able declaration. A row carries the member-level type the
305
+ plugin commits to: `Dynamic[top]` for column readers on purpose
306
+ (the bare, receiver-less read's answer — a written `user.name`
307
+ still narrows to the column's type), and a type only where the
308
+ plugin already answers one at `check`.
309
+
176
310
  Architecture (the cached schema-parser → model-index → analyzer
177
311
  chain), the source layout, how to run the demo, and the plugin
178
312
  contract surfaces this plugin exercises are documented in the
@@ -40,12 +40,19 @@ arguments decline — those are covered by ActiveStorage's own RBS.
40
40
  | Rule | Severity | When |
41
41
  | --- | --- | --- |
42
42
  | `plugin.activestorage.attachment-call` | info | a recognised `model.attachment_name` call surfaces; confirms the model → attachment mapping |
43
- | `plugin.activestorage.load-error` | warning | discovery failed (e.g. the model directory is inaccessible under the IoBoundary trust policy) |
43
+ | `plugin.activestorage.load-error` | warning | discovery failed (e.g. the model directory is inaccessible under the IoBoundary trust policy) — once per run, on `.rigor.yml` |
44
44
 
45
45
  No `:error` diagnostics in this slice — the value is the
46
46
  return-type contribution; an "unknown attachment name" rule is a
47
47
  future slice.
48
48
 
49
+ The `load-error` warning is run-scoped: it is a fact about your
50
+ configuration, not about any one source file, so it is reported once
51
+ per run on `.rigor.yml` rather than repeated on every analysed file.
52
+ It is `:warning`, so if you baselined it at its old position that
53
+ entry no longer matches and the row fails a `--fail-on=warning` run —
54
+ regenerate with `rigor baseline regenerate`.
55
+
49
56
  ## Configuration
50
57
 
51
58
  ```yaml
@@ -36,21 +36,27 @@ path, no vendoring, no `signature_paths:` wiring.
36
36
 
37
37
  Roughly the top ~40 selectors plus their close neighbours, across:
38
38
 
39
- - **Object (universal)** — `#blank?`, `#present?`, `#presence`, `#try`,
40
- `#try!`, `#acts_like?` (+ `NilClass` / `TrueClass` / `FalseClass`).
39
+ - **Object (universal)** — `#blank?`, `#present?`, `#presence`,
40
+ `#presence_in`, `#try`, `#try!`, `#acts_like?`, `#deep_dup`, `#with`,
41
+ `#with_options`, `#html_safe?`, `Kernel#class_eval` (+ `NilClass` /
42
+ `TrueClass` / `FalseClass`).
41
43
  - **Integer / Float** — Duration multipliers (`#days`, `#hours`,
42
44
  `#minutes`, …) and Bytes multipliers (`#megabytes`, `#gigabytes`, …).
43
45
  - **String** — inflections (`#underscore`, `#camelize`, `#classify`,
44
46
  `#constantize`, `#pluralize`, …), filters (`#squish`, `#truncate`),
45
- `#html_safe`, `#starts_with?` / `#ends_with?`, conversions.
47
+ `#html_safe`, `#starts_with?` / `#ends_with?` (also on **Symbol**),
48
+ conversions and `#in_time_zone`.
46
49
  - **Time / Date / DateTime** — `.current`, `.zone`, `#yesterday`,
47
50
  `#tomorrow`, `#beginning_of_*` / `#end_of_*`, `#ago`, `#since`. `Time`
48
51
  additionally carries its **whole** Rails instance surface (see below);
49
52
  `Date` and `DateTime` carry the same subset they always did.
50
53
  - **Array** — `.wrap`, `#to_sentence`, `#in_groups_of`, `#second` …
51
54
  `#fifth`, `#compact_blank`, `#exclude?`.
52
- - **Hash** — `#symbolize_keys` / `#stringify_keys` (+ deep / bang),
53
- `#deep_merge`, `#with_indifferent_access`, `#except!`.
55
+ - **Hash** — `#symbolize_keys` / `#stringify_keys` (+ deep / bang) and
56
+ their `#to_options` alias, `#deep_merge`, `#reverse_merge` /
57
+ `#with_defaults` (+ bang), `#with_indifferent_access`, `#except!`,
58
+ `#extract!`.
59
+ - **Range** — `#overlaps?`, `#to_fs` / `#to_formatted_s`.
54
60
  - **Enumerable** — `#index_by`, `#index_with`, `#pluck`, `#exclude?`.
55
61
 
56
62
  ```ruby
@@ -129,8 +135,29 @@ singletons `.days_in_month`, `.days_in_year`, `.rfc3339`, `.use_zone`,
129
135
  `.find_zone` / `.find_zone!` and `.zone_default`.
130
136
 
131
137
  Where a return cannot honestly be named it is widened rather than
132
- guessed: `#in_time_zone` answers an `ActiveSupport::TimeWithZone`, which
133
- this bundle does not model, so it reads `untyped`.
138
+ guessed: `#in_time_zone` answers an `ActiveSupport::TimeWithZone` under a
139
+ zone and the receiver's own class when none is configured, so it reads
140
+ `untyped` rather than picking one of the two.
141
+
142
+ `ActiveSupport::TimeWithZone` itself **is** modelled, as a subclass of
143
+ `Time` — which is what `Time.current` and the whole `1.hour.ago` family
144
+ answer:
145
+
146
+ ```ruby
147
+ Time.current.time_zone # the zone (untyped)
148
+ Time.current.comparable_time # Time
149
+ Time.current.to_fs(:db) # String — Time's own surface, inherited
150
+ 1.hour.ago.time_zone # the same class from the Duration family
151
+ Time.now.time_zone # still call.undefined-method — a plain
152
+ # Time really does not have it
153
+ ```
154
+
155
+ Rails overrides `TimeWithZone#is_a?` to answer true for `::Time` and
156
+ forwards everything it does not define to the wrapped `Time`, so the
157
+ subclass says what a `Time` return said and adds the four readers a TWZ
158
+ has of its own. A `Time | TimeWithZone` union was measured instead and
159
+ rejected: it fires nothing, but types the whole downstream chain
160
+ `Dynamic[top]`.
134
161
 
135
162
  What is left out is twelve names, measured against a real
136
163
  `require "active_support/all"`: ten instance and two singleton, every one
@@ -145,6 +172,15 @@ code that does will see them reported.
145
172
  `Date` and `DateTime` are extended by the same ActiveSupport modules and
146
173
  do **not** carry this yet — `Date.current.past?` still reports.
147
174
 
175
+ ## `ActiveSupport::Concern` resolves
176
+
177
+ `extend ActiveSupport::Concern` is the first line of every concern in a
178
+ Rails app, and the constant used to resolve to nothing. The bundle now
179
+ names the module, along with the three members `extend` puts on the
180
+ extender — `included`, `prepended` and `class_methods` — so
181
+ `included do … end` keeps resolving rather than becoming a report on the
182
+ newly-named module. Everything else `Concern` responds to stays lenient.
183
+
148
184
  ## No diagnostics, no config
149
185
 
150
186
  The plugin emits no diagnostics and has no configuration knobs. It
@@ -0,0 +1,106 @@
1
+ # rigor-grape
2
+
3
+ Types the [Grape](https://github.com/ruby-grape/grape)
4
+ endpoint-declaration DSL so calls inside `class API < Grape::API`
5
+ bodies — and inside `Grape::Entity` subclasses from
6
+ [grape-entity](https://github.com/ruby-grape/grape-entity) — resolve to
7
+ real carriers instead of `Dynamic[top]`. It reads source only, with no
8
+ `grape` runtime dependency.
9
+
10
+ It ships bundled in `rigortype`. Activate it under `plugins:` (or let
11
+ bundler auto-detection pick it up when `grape` or `grape-entity` is in
12
+ `Gemfile.lock`):
13
+
14
+ ```yaml
15
+ plugins:
16
+ - rigor-grape
17
+ ```
18
+
19
+ ## What it types
20
+
21
+ ```ruby
22
+ class ThingsAPI < Grape::API
23
+ version "v1", using: :path
24
+ format :json
25
+
26
+ desc "List things" # Object?
27
+ route_setting :swagger, tags: %w[things] # Object?
28
+
29
+ params do # → Grape::Validations::ParamsScope
30
+ requires :id, type: Integer # Object?
31
+ optional :q, type: String # Object?
32
+ requires :filter, type: Hash do # nested scope re-enters ParamsScope
33
+ requires :state, type: String
34
+ end
35
+ mutually_exclusive :q, :filter
36
+ end
37
+
38
+ namespace :things do # self: the API::Instance class object
39
+ get "/:id" do # self: Grape::Endpoint
40
+ params # Hash[untyped, untyped]
41
+ error!("nope", 404) # bot
42
+ present Thing.first, with: Entities::Thing
43
+ end
44
+ end
45
+ end
46
+
47
+ class Entities::Thing < Grape::Entity
48
+ expose :id # Array[untyped]
49
+ expose :name do # `self` stays the class object
50
+ expose :first
51
+ end
52
+ format_with(:iso) { |d| d.to_s } # Object
53
+ end
54
+ ```
55
+
56
+ Recognised surfaces:
57
+
58
+ - **Class-body declarations** on `Grape::API` subclasses (including
59
+ through intermediate source base classes): `params`, `namespace` /
60
+ `group` / `resource` / `resources` / `segment` / `route_param` /
61
+ `version` / `given` / `mounted`, `get`/`put`/`post`/`delete`/`head`/
62
+ `patch`/`options`/`route`, `desc`, `route_setting`, `helpers`, `use`,
63
+ `mount`, `rescue_from`, the format/error-format setters, callbacks
64
+ (`before`/`after`/`before_validation`/`after_validation`), `prefix`,
65
+ `scope`, `contract`, and friends.
66
+ - **`params` block bodies** bind `self` to
67
+ `Grape::Validations::ParamsScope`, so `requires`, `optional`, `given`,
68
+ `with`, `use`, and the grouping macros (`mutually_exclusive`,
69
+ `exactly_one_of`, `at_least_one_of`, `all_or_none_of`) resolve —
70
+ including nested `requires :x, type: Hash do ... end` bodies.
71
+ - **Namespace-family bodies** (`namespace`, `route_param`, `version`,
72
+ `given`, `mounted`) bind `self` to the `Grape::API::Instance` class
73
+ object, matching Grape's `instance_eval`-on-class semantics, so nested
74
+ declarations resolve the same surface.
75
+ - **`desc 'x' do ... end` bodies** bind `self` to
76
+ `Grape::DSL::Desc::ConfigContext` — the closed `ROUTE_ATTRIBUTES`
77
+ setter surface — so `detail`, `success`, `failure`, `tags`,
78
+ `entity`, `hidden`, `is_array`, `consumes`, `headers`, `summary`,
79
+ `deprecated`, `named`, `nickname`, `produces`, `security`,
80
+ `http_codes`, `body_name`, `default`, `description`, and `params`
81
+ (the documentation setter, not `ParamsScope`) resolve.
82
+ - **Verb bodies** bind `self` to `Grape::Endpoint`, so `params`,
83
+ `headers`, `cookies`, `env`, `declared`, `present`, `error!`,
84
+ `status`, `redirect`, `body`, `content_type`, `route`,
85
+ `route_setting`, `stream`, `sendfile` resolve.
86
+ - **`Grape::Entity` class bodies**: `expose`, `unexpose`,
87
+ `with_options`, `documentation`, `format_with`, `root`,
88
+ `root_element`, `represent`, `present_collection`, `root_exposures`.
89
+ Nested `expose` bodies keep `self` on the class object, so they
90
+ resolve the same way.
91
+
92
+ ## Deferred
93
+
94
+ - `helpers do ... end` bodies (an anonymous module is `self` —
95
+ unnameable).
96
+ - Named `params :name` scopes inside `helpers` and `contract` schema
97
+ blocks.
98
+ - Value-level typing: `present`/`declared` results against the declared
99
+ entity or params, entity `represent` result typing.
100
+ - `Grape::Middleware` and custom-middleware DSL.
101
+
102
+ Calls on classes outside `Grape::API` / `Grape::Entity` ancestry keep
103
+ the `Dynamic` fallback, and DSL names the bundled signature does not
104
+ declare stay opaque rather than diagnosed — the declared classes are
105
+ registered as open receivers because Grape's runtime surface is
106
+ generated (`override_all_methods!`) and user base classes extend it.
@@ -58,11 +58,25 @@ name. `null:` extracts to `nullable:` (defaulting to `true`, mirroring
58
58
  graphql-ruby); `required:` defaults to `false`. The single-element
59
59
  `[String]` list form is recognised.
60
60
 
61
+ ## Typed DSL surface
62
+
63
+ Beyond the fact tables, the plugin bundles the graphql-ruby class-level
64
+ DSL signature, so calls inside a recognised subclass type as their real
65
+ carriers instead of staying opaque: `field` returns
66
+ `GraphQL::Schema::Field`, `argument` returns `GraphQL::Schema::Argument`,
67
+ `Enum.value` returns `GraphQL::Schema::EnumValue`, `description` /
68
+ `graphql_name` return their configured strings, and the `Schema`
69
+ registration macros (`query`, `mutation`, `use`, `orphan_types`, …)
70
+ return what they registered. A block parameter on `field`/`argument`
71
+ (`field(:comments) { |f| … }`) types as `GraphQL::Schema::Field` /
72
+ `GraphQL::Schema::Argument`.
73
+
61
74
  ## No diagnostics, no config
62
75
 
63
76
  The plugin emits no diagnostics and has no configuration knobs — it
64
- contributes the type tables above for other plugins to consume. It
65
- walks every `paths:` entry's `.rb` files for the schema-class shapes.
77
+ contributes the type tables and signature above for the engine and
78
+ other plugins to consume. It walks every `paths:` entry's `.rb` files
79
+ for the schema-class shapes.
66
80
 
67
81
  ## Limitations
68
82
 
@@ -72,6 +86,13 @@ walks every `paths:` entry's `.rb` files for the schema-class shapes.
72
86
  - **No `Schema.execute(...)` result typing.** Typing
73
87
  `Schema.execute(query).to_h` against the queried fields is a future
74
88
  plugin.
89
+ - **Interface DSL stays opaque.** `include GraphQL::Schema::Interface`
90
+ wires the DSL onto the includer through an include-time `extend`
91
+ hook RBS cannot express, so `field` inside an interface module is
92
+ not yet typed.
93
+ - **Zero-arity definition blocks keep an opaque `self`.**
94
+ `field :x do ... end` `instance_eval`s on the new `Field` at
95
+ runtime; only the explicit-parameter form (`{ |f| … }`) is typed.
75
96
  - **Constant-form types only.** The string form (`field :foo, "User"`)
76
97
  and the `<Type>.array` / `<Type>!` sugar chains are not recognised
77
98
  (the `[String]` bracket form is). Multi-element and empty list
@@ -33,7 +33,7 @@ authorize(Comment, :edit) # error: no policy class CommentPolicy (did you mean
33
33
  | `plugin.pundit.policy-call` | info | an `authorize` / `policy` / `policy_scope` call resolved to a discovered policy |
34
34
  | `plugin.pundit.unknown-policy-class` | error | the record maps to a `<Type>Policy` with no entry in the index (with a did-you-mean) |
35
35
  | `plugin.pundit.unknown-policy-method` | error | the policy exists but the `:action` has no `<action>?` predicate (lists known predicates + a did-you-mean) |
36
- | `plugin.pundit.load-error` | warning | policy discovery failed (parse/read error) — once per file |
36
+ | `plugin.pundit.load-error` | warning | policy discovery failed (parse/read error) — once per run, on `.rigor.yml` |
37
37
 
38
38
  The record maps to a policy by constant name or inferred
39
39
  `Nominal[T]` (`Post` → `PostPolicy`); `:update` normalises to
@@ -88,6 +88,13 @@ candidate rather than being guessed at.
88
88
  not validated when `local` has no inferred `Nominal[T]`.
89
89
  - **`Scope` policies** are validated for class existence, not for
90
90
  `Scope#resolve`.
91
+ - **The "failed to discover policies" warning is run-scoped.** It is
92
+ a fact about your configuration, not about any one source file, so
93
+ it is reported once per run on `.rigor.yml` rather than repeated on
94
+ every analysed file. It is `:warning`, so if you baselined it at its
95
+ old position that entry no longer matches and the row fails a
96
+ `--fail-on=warning` run — regenerate with `rigor baseline
97
+ regenerate`.
91
98
 
92
99
  ## Plugin internals
93
100
 
@@ -88,11 +88,16 @@ view templates containing lazy `t('.key')` calls.
88
88
  may come from controller instance variables not visible in the
89
89
  template source. Configure `view_search_paths:` to override the
90
90
  default `["app/views"]`.
91
- - **View diagnostics duplicate under `--workers`** — the view
92
- scan is a project-wide pass surfaced through the per-file
93
- diagnostic hook, so each fork-pool worker re-emits the full set
94
- (the same once-per-run limitation the `load-error` diagnostics
95
- carry). Default `rigor check` (sequential) is unaffected.
91
+ - **`load-error` rows are reported on `.rigor.yml`** — a locale
92
+ file that does not parse, or a locale or view scan that fails,
93
+ is reported once per run at `.rigor.yml:1:1`. They are
94
+ `:warning`, so if you baselined one at its old position on a
95
+ Ruby file, that entry no longer matches and the row fails a
96
+ `--fail-on=warning` run — regenerate with `rigor baseline
97
+ regenerate`. View diagnostics keep their view file position and
98
+ are reported once per run whatever `--workers` is set to
99
+ ([#1060](https://github.com/rigortype/rigor/issues/1060)); a
100
+ baseline entry recorded against a view still matches.
96
101
  - **Pluralization is recognised but not validated** — `count:` is
97
102
  treated as a reserved option; whether the locale defines
98
103
  `:zero` / `:one` / `:other` is not checked.
@@ -129,6 +129,13 @@ routed. Helper-name recognition for all three is unaffected.
129
129
  doesn't model) may not register, which can surface a false
130
130
  `unknown-helper`. Record those in a baseline, or
131
131
  `# rigor:disable` the line.
132
+ - **The "routes file did not load" warning is run-scoped.** It is a
133
+ fact about your configuration, not about any one source file, so
134
+ it is reported once per run on `.rigor.yml` rather than on the
135
+ first analysed file. It is `:warning`, so if you baselined it at
136
+ its old position that entry no longer matches and the row fails a
137
+ `--fail-on=warning` run — regenerate with `rigor baseline
138
+ regenerate`.
132
139
  - **Project-custom inflections** declared in
133
140
  `config/initializers/inflections.rb` are not yet fully ingested
134
141
  (ADR-39 slice 3); the standard ActiveSupport inflections are