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
data/sig/rigor/source.rbs CHANGED
@@ -4,11 +4,11 @@ module Rigor
4
4
  class OutOfRangeError < StandardError
5
5
  end
6
6
 
7
- def self.at_position: (source: String, root: untyped, line: Integer, column: Integer) -> untyped?
8
- def self.at_offset: (root: untyped, offset: Integer) -> untyped?
7
+ def self.at_position: (source: String, root: untyped, line: Integer, column: Integer) -> ::Prism::Node?
8
+ def self.at_offset: (root: untyped, offset: Integer) -> ::Prism::Node?
9
9
  def initialize: (source: String, root: untyped) -> void
10
- def at_position: (line: Integer, column: Integer) -> untyped?
11
- def at_offset: (Integer offset) -> untyped?
10
+ def at_position: (line: Integer, column: Integer) -> ::Prism::Node?
11
+ def at_offset: (Integer offset) -> ::Prism::Node?
12
12
  end
13
13
 
14
14
  module Literals
@@ -1,9 +1,15 @@
1
1
  module Rigor
2
2
  module Testing
3
- def self?.dump_type: (untyped value) -> untyped
4
- def self?.assert_type: (String expected, untyped value) -> untyped
3
+ # Both helpers return `value` unchanged (lib/rigor/testing.rb); the type variable carries the
4
+ # argument's type through so a probed expression stays typed downstream instead of widening to
5
+ # `Dynamic[top]`. `A` binds only on a dispatch that carries a scope — a `Rigor.` /
6
+ # `Rigor::Testing.` receiver, or an including class that is RBS-known. A bare `dump_type(x)` after
7
+ # `include Rigor::Testing` in a discovered-only class still reaches the ancestor fallback without a
8
+ # scope and answers `Dynamic[top]`, as it did under `-> untyped` (#303 follow-up).
9
+ def self?.dump_type: [A] (A value) -> A
10
+ def self?.assert_type: [A] (String expected, A value) -> A
5
11
  end
6
12
 
7
- def self.dump_type: (untyped value) -> untyped
8
- def self.assert_type: (String expected, untyped value) -> untyped
13
+ def self.dump_type: [A] (A value) -> A
14
+ def self.assert_type: [A] (String expected, A value) -> A
9
15
  end
data/sig/rigor/type.rbs CHANGED
@@ -1,6 +1,6 @@
1
1
  module Rigor
2
2
  module Type
3
- type t = Top | Bot | Dynamic | Constant | IntegerRange | Nominal | Singleton | Union | Difference | Refined | Intersection | Tuple | HashShape | DataClass | DataInstance | StructClass | StructInstance | BoundMethod | Result | Maybe | App
3
+ type t = Top | Bot | Dynamic | Constant | IntegerRange | FloatRange | Nominal | Singleton | Union | Difference | Refined | Intersection | Tuple | HashShape | DataClass | DataInstance | StructClass | StructInstance | BoundMethod | Result | Maybe | App
4
4
 
5
5
  type accepts_mode = :strict | :gradual | :loose
6
6
 
@@ -115,7 +115,30 @@ module Rigor
115
115
  def inspect: () -> String
116
116
  end
117
117
 
118
+ class FloatRange
119
+ ALIAS_NAMES: Hash[[Float, Float], String]
120
+ attr_reader min: Float
121
+ attr_reader max: Float
122
+ def initialize: (Float min, Float max, ?exclude_end: bool) -> void
123
+ def exclude_end?: () -> bool
124
+ def canonical_max: () -> Float
125
+ def universal?: () -> bool
126
+ def covers?: (untyped value) -> bool
127
+ def describe: (?Symbol verbosity) -> String
128
+ def generic_description: () -> String
129
+ def erase_to_rbs: () -> "Float"
130
+ def top: () -> Trinary
131
+ def bot: () -> Trinary
132
+ def dynamic: () -> Trinary
133
+ def accepts: (Type::t other, ?mode: accepts_mode) -> AcceptsResult
134
+ def ==: (untyped other) -> bool
135
+ def eql?: (untyped other) -> bool
136
+ def hash: () -> Integer
137
+ def inspect: () -> String
138
+ end
139
+
118
140
  class Nominal
141
+ EMPTY_TYPE_ARGS: Array[Type::t]
119
142
  attr_reader class_name: String
120
143
  attr_reader type_args: Array[Type::t]
121
144
  def initialize: (String class_name, ?Array[Type::t] type_args) -> void
@@ -406,8 +429,14 @@ module Rigor
406
429
  attr_reader trinary: Trinary
407
430
  attr_reader mode: accepts_mode
408
431
  attr_reader reasons: Array[String]
432
+ # sig-gen gap: #1155 — the memoized `||=` return is an honest union with an
433
+ # untyped arm (the slot read cannot prove the memoized value), so sig-gen
434
+ # skips it (sig.skipped.untyped-return); the runtime result is always
435
+ # AcceptsResult and the row is hand-written.
409
436
  def self.yes: (?mode: accepts_mode, ?reasons: (Array[String] | String)?) -> AcceptsResult
437
+ # sig-gen gap: #1155 — same memoized `||=` untyped-return gap as `self.yes`.
410
438
  def self.no: (?mode: accepts_mode, ?reasons: (Array[String] | String)?) -> AcceptsResult
439
+ # sig-gen gap: #1155 — same memoized `||=` untyped-return gap as `self.yes`.
411
440
  def self.maybe: (?mode: accepts_mode, ?reasons: (Array[String] | String)?) -> AcceptsResult
412
441
  def initialize: (Trinary trinary, ?mode: accepts_mode, ?reasons: (Array[String] | String)?) -> void
413
442
  def yes?: () -> bool
@@ -460,6 +489,9 @@ module Rigor
460
489
  def self?.negative_int: () -> IntegerRange
461
490
  def self?.non_positive_int: () -> IntegerRange
462
491
  def self?.universal_int: () -> IntegerRange
492
+ def self?.float_range: (Float min, Float max, ?exclude_end: bool) -> FloatRange
493
+ def self?.non_nan_float: () -> FloatRange
494
+ def self?.finite_float: () -> FloatRange
463
495
  def self?.tuple_of: (*Type::t elements) -> Tuple
464
496
  def self?.hash_shape_of: (?Hash[untyped, Type::t]? pairs, **untyped options) -> HashShape
465
497
  def self?.data_class_of: (members: Array[Symbol], ?class_name: String?) -> DataClass
data/sig/rigor.rbs CHANGED
@@ -24,6 +24,7 @@ module Rigor
24
24
 
25
25
  class CLI
26
26
  EXIT_USAGE: Integer
27
+ EXIT_INTERNAL_ERROR: Integer
27
28
 
28
29
  def self.start: (?Array[String] argv, ?out: untyped, ?err: untyped) -> Integer
29
30
 
@@ -123,32 +124,50 @@ module Rigor
123
124
  attr_reader buffer: untyped
124
125
  attr_reader file_dependencies: Hash[String, untyped]
125
126
  attr_reader analyzed_files: Array[String]
126
- def initialize: (configuration: Configuration, ?explain: bool, ?cache_store: untyped, ?plugin_requirer: untyped, ?workers: Integer, ?collect_stats: bool, ?buffer: untyped, ?prebuilt: untyped, ?environment: untyped, ?record_dependencies: bool, ?analyze_only: untyped) -> void
127
+ def initialize: (configuration: Configuration, ?explain: bool, ?cache_store: untyped, ?plugin_requirer: untyped, ?workers: Integer, ?collect_stats: bool, ?buffer: untyped, ?prebuilt: Analysis::ProjectScan?, ?environment: untyped, ?record_dependencies: bool, ?analyze_only: untyped) -> void
127
128
  def run: (?Array[String] paths) -> Result
128
129
  def run_source: (source: String, ?path: String) -> Result
129
130
  def analysis_file_set: (?Array[String] paths) -> Array[String]
130
131
  def file_dependents: () -> Hash[String, untyped]
131
- def prepare_project_scan: (?paths: Array[String]) -> untyped
132
+ def prepare_project_scan: (?paths: Array[String]) -> Analysis::ProjectScan
132
133
  # ADR-103 — the propagated effect graph and the merged per-file collections behind it. A report
133
- # surface: never a diagnostic, empty when the configuration carries no `effects:` block. Typed
134
- # `untyped` for the same reason `cache_store` is — `Rigor::Effects` is not sig-covered yet
135
- # (`spec/rigor/public_api_drift_spec.rb`), and a named reference would raise `RBS::UnknownTypeName`.
136
- def effect_table: () -> untyped
137
- def effect_collection: () -> untyped
138
- # #381 — `{ "Class#m" => [path] }`, which the snapshot's `reach:` globs match against. Same
139
- # `untyped` reasoning as its two siblings above.
140
- def effect_sources: () -> untyped
141
- # #387 — the loaded plugins' compiled effect contributions, read by `rigor effects` so the snapshot's
142
- # vocabulary is the one the collection window scanned under. Same `untyped` reasoning again.
143
- def effect_plugin_facts: () -> untyped
134
+ # surface: never a diagnostic, empty when the configuration carries no `effects:` block.
135
+ def effect_table: () -> Effects::EffectTable
136
+ def effect_collection: () -> Effects::FileCollection
137
+ # ADR-103 WD9 (#391): the resolved envelope index `rigor sig-gen`'s annotation emission
138
+ # consults, built on demand so a warm-cache run still serves the same strata.
139
+ def effect_envelopes: () -> Effects::EnvelopeIndex
140
+ # #381 — `{ "Class#m" => [path] }`, which the snapshot's `reach:` globs match against.
141
+ def effect_sources: () -> Hash[String, Array[String]]
142
+ # #387 — the loaded plugins' compiled effect contributions, read by `rigor effects` so the
143
+ # snapshot's vocabulary is the one the collection window scanned under.
144
+ def effect_plugin_facts: () -> Effects::PluginFacts
145
+ # The run's as-written superclass table — what `effect.liskov-widened` reads.
146
+ def effect_ancestry: () -> Hash[String, String]
147
+ # `{ "lib/a.rb" => FileCollection, … }` — the per-file collections the caches persist (#382).
148
+ def effect_collections_by_path: () -> Hash[String, Effects::FileCollection]
149
+ # Issue #382 — adopt persisted collections as this run's own (the warm-hit half of the
150
+ # whole-run effects slot).
151
+ def adopt_effect_collections: (Hash[String, Effects::FileCollection] collections,
152
+ ?table: Effects::EffectTable?) -> void
153
+ # #482 — adopt the served run's small summary entry, collections left behind a loader.
154
+ def adopt_effect_summary: (table: Effects::EffectTable, sources: Hash[String, Array[String]],
155
+ ancestry: Hash[String, String], collections_loader: untyped) -> void
156
+ # Whether this run's effect collections came from the whole-run effects slot (#382).
157
+ def effects_served_from_cache?: () -> bool
144
158
  # The incremental session's read surface (ADR-46 / ADR-67 / ADR-103) — `IncrementalSession`
145
- # drives a live Runner through these between rechecks. Typed `untyped` like the cache / effects
146
- # readers above until their namespaces are sig-covered.
147
- def return_summaries: () -> untyped
148
- def param_inferred_types: () -> untyped
149
- def effect_collections_by_path: () -> untyped
150
- def collect_param_inference_table: (untyped files) -> untyped
151
- def evaluate_return_types: (untyped paths, untyped specs) -> untyped
159
+ # drives a live Runner through these between rechecks.
160
+ # sig-gen gap: #1008 — `result` is populated by `collect_return_summaries` mutating it by
161
+ # reference from a sibling method; sig-gen folds only the `{}` seed and the empty-memo early
162
+ # return, so it proposes the seed shape instead of the honest, usually-non-empty contract.
163
+ # Keys are `[path, "Class#method"]` pairs; values are `{ keys:, returns:, effects: }` bundles.
164
+ def return_summaries: () -> Hash[[String, String], Hash[Symbol, untyped]]
165
+ # ADR-67 — `[class_name, method_name, kind] => { param_name => Type }`.
166
+ def param_inferred_types: () -> Hash[[String, Symbol, Symbol], Hash[Symbol, Type::t]]
167
+ def collect_param_inference_table: (untyped files) -> Hash[[String, Symbol, Symbol], Hash[Symbol, Type::t]]
168
+ # `{ class_name:, method_name:, singleton: }` spec triple => the per-key return descriptors
169
+ # (`describe(:short)` strings; nil for a missing/bodyless def).
170
+ def evaluate_return_types: (untyped paths, untyped specs) -> Hash[[String, Symbol, bool], Array[String?]]
152
171
  end
153
172
  end
154
173
 
@@ -1,7 +1,9 @@
1
1
  ---
2
2
  name: rigor-ask
3
- description: |
4
- Answer any question about Rigor by investigating, not from memory — Rigor is niche and version-specific, so run its tools and read its bundled docs, then answer from what you saw. Use `rigor docs` (handbook + manual, offline and version-matched) and `rigor explain <rule>`; for the user's own code, `rigor check` / `annotate` / `type-of`. Covers: why a line is flagged or whether it's a false positive; the type model (narrowing, refinements, `Dynamic`, RBS); config keys, flags, baselines; comparisons to Sorbet, Steep, mypy, PHPStan; whether Rigor handles Rails, RSpec, or a given gem; how to type a method; "what is Rigor / why use it / is it right for us?". Trigger on any Rigor question seeking understanding — even casual, comparative, or grumbling. Skip only when it's purely "set it up / fix / reduce it for me" (use rigor-next-steps).
3
+ description: >-
4
+ Answer a question about Rigor from version-matched bundled docs and tool output. Use when the user
5
+ asks why a diagnostic fired, how a type/config/flag works, or how Rigor compares with another tool; not
6
+ when they ask you to set up, fix, or reduce something.
5
7
  license: MPL-2.0
6
8
  metadata:
7
9
  version: 0.2.0
@@ -30,11 +32,12 @@ Two things make that easy, and you have both offline:
30
32
  `type-of` / `triage` / `coverage` answer from what Rigor inferred. A
31
33
  concrete inferred type beats any abstract explanation.
32
34
 
33
- This is the user's shortcut: they only ever need to remember two skills —
34
- **`rigor-next-steps`** ("what should we do next?") and **`rigor-ask`**
35
- ("answer this about Rigor"). They ask in plain language; *you* turn it
36
- into the right lookup or analysis so they never have to remember the
37
- command.
35
+ This is the user's shortcut: they only ever need to remember three
36
+ skills — **`rigor-next-steps`** ("what should we do next?"),
37
+ **`rigor-ask`** ("answer this about Rigor"), and **`rigor-type-oracle`**
38
+ ("before you write a type, ask Rigor"). They ask in plain language; *you*
39
+ turn it into the right lookup or analysis so they never have to remember
40
+ the command.
38
41
 
39
42
  ## Prefer the live map over this skill's tables
40
43
 
@@ -50,8 +53,9 @@ rigor --help # the live command + flag list
50
53
  rigor skill --full rigor-ask # the current version of this skill itself
51
54
  ```
52
55
 
53
- Never cite a page, flag, or rule id you have not just seen in one of these
54
- — that is this skill's whole discipline. If `rigor` is not installed, you
56
+ Cite a page, flag, or rule id only after you have seen it in this
57
+ install — `rigor docs`, `rigor --help`, `rigor explain`, or the gem's own
58
+ files (see "If the docs don't cover it"). If `rigor` is not installed, you
55
59
  can still answer high-level "what is Rigor?" questions from the web
56
60
  <https://rigor.typedduck.fail/llms.txt>, but for anything version-specific
57
61
  install it first (see `rigor-next-steps`).
@@ -79,7 +83,7 @@ Everything here is read-only and needs no network.
79
83
  | `rigor triage` | Cluster the project's diagnostics by rule / receiver / method — for "what's the shape of my errors?". |
80
84
  | `rigor coverage [--protection]` | Type / type-protection coverage — for "how well-typed is this?" and "where are the holes?". |
81
85
  | `rigor plugins` | Which plugins are installed and enabled *here* — the honest answer to "does Rigor support <gem/framework>?". |
82
- | `rigor sig-gen <path>` | Generate RBS for code — for "how do I type this?". Offer it and show the result; this project prefers sig-gen over hand-written RBS. |
86
+ | `rigor sig-gen <path>` | Generate RBS for code — for "how do I type this?". Offer it and show the result — generated RBS is derived; hand-written RBS is a guess until `rigor check` agrees (see `rigor-type-oracle`). |
83
87
 
84
88
  ## Where the answer lives
85
89
 
@@ -125,8 +129,9 @@ A good hand-off is two or three sentences of orientation plus the pointer:
125
129
  - CI → **`rigor-ci-setup`** · editor → **`rigor-editor-setup`** · MCP agent → **`rigor-mcp-setup`**
126
130
  - baseline reduction → **`rigor-baseline-reduce`** · coverage holes → **`rigor-protection-uplift`**
127
131
  - a missing gem/DSL → **`rigor-plugin-author`** · monkey-patch clusters → **`rigor-monkeypatch-resolve`**
132
+ - about to *write* a type (RBS, `#:`, a Sorbet `sig`, a YARD tag, a doc sentence) → **`rigor-type-oracle`**
128
133
 
129
- When in doubt, give less and point — it respects the user's "two skills
134
+ When in doubt, give less and point — it respects the user's "three skills
130
135
  to remember" promise and keeps each answer to the part only `rigor-ask`
131
136
  can give.
132
137
 
@@ -1,7 +1,9 @@
1
1
  ---
2
2
  name: rigor-baseline-reduce
3
- description: |
4
- Work a Rigor project's `.rigor-baseline.yml` down rule by rule: prioritise with `rigor triage`, sample call sites, classify each as real bug / stylistic-safe / false positive, then fix, `# rigor:disable`, or open a Rigor issue — and regenerate the baseline. Triggers: "reduce the rigor baseline", "fix some baseline diagnostics", "what rigor issue should I fix next?". NOT for first-time setup (use rigor-project-init) or authoring a plugin (use rigor-plugin-author).
3
+ description: >-
4
+ Reduce an existing `.rigor-baseline.yml` rule by rule by triaging sites, fixing or intentionally
5
+ suppressing them, and regenerating the baseline. Use for baseline diagnostics already acknowledged by a
6
+ project; not for first-time setup or plugin authoring.
5
7
  license: MPL-2.0
6
8
  metadata:
7
9
  version: 0.1.0
@@ -37,10 +39,6 @@ header names). If `rigor` is not on `PATH`, this task needs it: run
37
39
 
38
40
  ## Phase 0 — When to use this skill
39
41
 
40
- Trigger when the user says "reduce the rigor baseline", "fix some
41
- baseline diagnostics", "what should I fix next in rigor?", or asks to
42
- work down the diagnostics a previous onboarding parenthesised.
43
-
44
42
  **Precondition: the project is in acknowledge mode.** This skill
45
43
  operates on a `.rigor-baseline.yml` that `.rigor.yml` /
46
44
  `.rigor.dist.yml` declares via `baseline:`. A strict-mode project
@@ -1,7 +1,9 @@
1
1
  ---
2
2
  name: rigor-ci-setup
3
- description: |
4
- Wire Rigor type-checking into a project's CI pipeline: run it in its own isolated Ruby-4.0 job and surface diagnostics inline on the pull / merge request via a CI-native output format (SARIF, GitHub Actions annotations, GitLab Code Quality, Checkstyle, JUnit) or through reviewdog. Triggers: "add Rigor to CI", "run rigor in GitHub Actions / GitLab CI", "show Rigor errors on the PR", "set up reviewdog for rigor". NOT for first-time project configuration (use rigor-project-init to create `.rigor.yml` first) or reducing a baseline (use rigor-baseline-reduce).
3
+ description: >-
4
+ Set up Rigor in a project's CI and surface diagnostics on pull or merge requests. Use when adding or
5
+ changing GitHub Actions, GitLab CI, SARIF, or reviewdog wiring; not for first-time Rigor configuration
6
+ or baseline reduction.
5
7
  license: MPL-2.0
6
8
  metadata:
7
9
  version: 0.1.0
@@ -31,7 +33,6 @@ Rigor is installed:
31
33
  ```sh
32
34
  rigor skill --full rigor-ci-setup # this skill's current workflow, in one call
33
35
  rigor docs ci # the manual's CI chapter — the actual templates
34
- rigor docs --list manual | grep ci-templates # ready-to-copy template files
35
36
  ```
36
37
 
37
38
  If you already loaded this skill *via* `rigor skill` you have the current
@@ -61,7 +62,7 @@ these markers from the project root and let them drive the platform choice:
61
62
  | `bitbucket-pipelines.yml` / `azure-pipelines.yml` / `.drone.yml` | that platform (generic recipe) |
62
63
  | none of the above | no CI yet — **ask** the user which platform they use |
63
64
 
64
- Concretely (the agent has file tools — use them):
65
+ Concretely:
65
66
 
66
67
  - List `.github/workflows/*.yml` and `.gitlab-ci.yml`. **If
67
68
  `.github/workflows/rigor.yml` already exists, read it** — this is an
@@ -108,10 +109,8 @@ this is the *decision*:
108
109
  ## Phase 2 — Apply the matching template
109
110
 
110
111
  Take the template for your (platform, surface) choice from `rigor docs ci`
111
- — or copy a ready file listed by `rigor docs --list manual | grep
112
- ci-templates` (GitHub annotations / SARIF / reviewdog, and GitLab). Copy it
113
- in, adjust nothing but the trigger unless asked, and pin the version next
114
- (Phase 3).
112
+ (GitHub annotations / SARIF / reviewdog, and GitLab). Copy it in, adjust
113
+ nothing but the trigger unless asked, and pin the version next (Phase 3).
115
114
 
116
115
  **reviewdog is platform-specific.** It reads Rigor's `checkstyle`
117
116
  (preferred — light, no code scanning) or `sarif`, but the `-reporter` must
@@ -142,14 +141,11 @@ The exact recipe (the `BUNDLE_GEMFILE` wiring, the Dependabot entry) is in
142
141
  - **Determinism.** Add `--no-cache` in CI if you want each run independent
143
142
  of any persisted `.rigor/cache`.
144
143
  - **Cache persistence (opposite trade).** When the Rigor job's runtime
145
- matters, persist `.rigor/cache` with the CI's cache facility. Current
146
- Rigor detects CI and validates the restored cache by content hash
147
- automatically (`cache.validation: auto`); on versions before the
148
- `auto` default, **also set `RIGOR_STRICT_VALIDATION=1` on the job** —
149
- without it a fresh checkout's regenerated stat tuples make the plugin
150
- watch-glob cache slots read as stale on every run. A self-hosted
151
- runner that reuses its workspace opts back into the faster stat check
152
- with `cache.validation: stat`. Snippets: `rigor docs ci`
144
+ matters, persist `.rigor/cache` with the CI's cache facility. Rigor
145
+ detects CI and validates the restored cache by content hash
146
+ automatically (`cache.validation: auto`). A self-hosted runner that
147
+ reuses its workspace opts back into the faster stat check with
148
+ `cache.validation: stat`. Snippets: `rigor docs ci`
153
149
  § "Persisting the analysis cache across runs".
154
150
 
155
151
  ## Verify
@@ -165,12 +161,12 @@ The exact recipe (the `BUNDLE_GEMFILE` wiring, the Dependabot entry) is in
165
161
 
166
162
  - Manual: `rigor`'s CI chapter — the authoritative templates, severity
167
163
  mapping, and pinning recipe, **offline and version-matched** with
168
- `rigor docs ci` (ready files: `rigor docs --list manual | grep
169
- ci-templates`). Web fallback, before Rigor is installed:
170
- <https://github.com/rigortype/rigor/blob/master/docs/manual/11-ci.md>.
171
- - [ADR-51](../../docs/adr/51-ci-diagnostic-output-formats.md)
164
+ `rigor docs ci`. Web fallback, before Rigor is installed:
165
+ <https://github.com/rigortype/rigor/blob/master/docs/manual/11-ci.md>
166
+ (ready-to-copy files in `docs/manual/ci-templates/` beside it).
167
+ - [ADR-51](https://github.com/rigortype/rigor/blob/master/docs/adr/51-ci-diagnostic-output-formats.md)
172
168
  — the output-format surface (the severity / identifier contract).
173
- - [ADR-27](../../docs/adr/27-tool-distribution-model.md)
169
+ - [ADR-27](https://github.com/rigortype/rigor/blob/master/docs/adr/27-tool-distribution-model.md)
174
170
  — why Rigor installs standalone and runs in its own job.
175
171
  - [reviewdog](https://github.com/reviewdog/reviewdog) /
176
172
  [action-setup](https://github.com/reviewdog/action-setup).
@@ -1,7 +1,9 @@
1
1
  ---
2
2
  name: rigor-doctor
3
- description: |
4
- Validate that a project's Rigor setup is actually healthy — config parses with no silently-inert values, every configured plugin loads, the baseline is not stale, and the bundled paths resolve — by running Rigor's existing validators and interpreting them. Triggers: "is my Rigor setup correct?", "check my rigor config", "rigor diagnostics look wrong / suspicious", "validate rigor setup", "why is rigor reporting nothing / everything?". NOT for first-time setup (use rigor-project-init) or for working real diagnostics down (use rigor-baseline-reduce).
3
+ description: >-
4
+ Validate that a project's Rigor configuration, plugins, paths, and baseline are actually healthy. Use
5
+ when diagnostics are suspicious or setup behavior is wrong; not for first-time onboarding or reducing
6
+ ordinary diagnostics.
5
7
  license: MPL-2.0
6
8
  metadata:
7
9
  version: 0.1.0
@@ -11,12 +13,13 @@ metadata:
11
13
  # Rigor Doctor
12
14
 
13
15
  `rigor skill describe` reports what *exists* (presence checks). This skill
14
- goes a level deeper: it *runs* Rigor's own validators to confirm the setup
15
- is actually working — the difference between "a `.rigor.yml` is present"
16
- and "it parses, loads its plugins, and analyses the right files." Reach for
17
- it when the diagnostics look wrong (suspiciously zero, or suspiciously
18
- many) or after editing the config. It needs no special command — it
19
- orchestrates checks Rigor already ships and interprets the results.
16
+ goes a level deeper: `rigor doctor` *runs* Rigor's own setup validators
17
+ (config audit, RBS environment, plugin loading, baseline drift, plugin
18
+ gaps, install layout) and this skill interprets the result — the
19
+ difference between "a `.rigor.yml` is present" and "it parses, loads its
20
+ plugins, and analyses the right files." Reach for it when the diagnostics
21
+ look wrong (suspiciously zero, or suspiciously many) or after editing the
22
+ config.
20
23
 
21
24
  ## First: load the version-current copy
22
25
 
@@ -44,25 +47,24 @@ header names). If `rigor` is not on `PATH`, this task needs it: run
44
47
 
45
48
  ## What it validates
46
49
 
47
- Four validators, each a check Rigor already ships. The exact commands and
48
- how to read each output live in the version-current
50
+ `rigor doctor` runs the setup checks in one pass (`--format json` gives
51
+ each finding's `checks[].id` and `status`) and exits non-zero when any
52
+ check fails. It does not check whether the analysis sees the right
53
+ files; that is a separate look at `stats.target_files` in
54
+ `rigor check --format json`. What each check id means and how to act on
55
+ it live in the version-current
49
56
  [`references/01-checks.md`](references/01-checks.md) (loaded per the
50
- directive above):
51
-
52
- 1. **Config resolves with nothing silently inert** — no `config_warnings`.
53
- 2. **Every configured plugin loads** — `rigor plugins --strict` is clean.
54
- 3. **The baseline is not stale** (if one exists) — no large drift.
55
- 4. **The analysis is actually seeing your code** — the source-file count
56
- matches the project.
57
+ directive above).
57
58
 
58
59
  ## Interpreting the result
59
60
 
60
- - **All clean** → the setup is healthy; any diagnostics are about the
61
- code, not the configuration. Move on to `rigor-baseline-reduce` or
61
+ - **All clean** (no `fail` or `warn` finding, and the file count matches
62
+ the project) → the setup is healthy; any diagnostics are about the code,
63
+ not the configuration. Move on to `rigor-baseline-reduce` or
62
64
  `rigor-protection-uplift`.
63
- - **A `config_warning` or a plugin failure** → that is the real problem;
64
- fixing it usually clears a whole cluster of confusing downstream
65
- diagnostics at once.
65
+ - **A `config_audit`, `rbs_environment`, or `plugins` failure** → that is
66
+ the real problem; fixing it usually clears a whole cluster of confusing
67
+ downstream diagnostics at once.
66
68
 
67
69
  For deeper symptoms (hover shows `untyped` everywhere, completion empty,
68
70
  LSP silent) read the manual's troubleshooting chapter — offline and
@@ -1,52 +1,116 @@
1
- # 01 — The four checks
1
+ # 01 — The checks
2
2
 
3
- Each check runs a validator Rigor already ships and interprets its
4
- output. Run them in order; the first failure is usually the root cause of
5
- a cluster of confusing downstream diagnostics.
6
-
7
- ## 1. Config resolves with nothing silently inert
3
+ ## Run `rigor doctor`
8
4
 
9
5
  ```sh
10
- rigor check --format json # read the `config_warnings` array
6
+ rigor doctor # human-readable: [FAIL] / [WARN] / [PASS] lines
7
+ rigor doctor --format json # machine-readable
11
8
  ```
12
9
 
13
- `rigor check` audits the config and emits `config_warnings` for the typo
14
- class whose only symptom is a confusing downstream error: a
15
- `signature_paths:` that is missing / not a directory / holds no `.rbs`
16
- (which would turn every covered call into a false `call.undefined-method`
17
- at `evidence_tier: high`), a `libraries:` name RBS does not recognise, a
18
- `disable:` / `severity_overrides:` id naming no real rule, or a missing
19
- `bundler` / `rbs_collection` path. **Each warning here is a real
20
- misconfiguration — fix it.** None appearing is the healthy state.
21
-
22
- ## 2. Every configured plugin loads
10
+ It runs one scoped analysis, audits the config, loads the plugins, and
11
+ checks baseline drift in a single pass, then prints a finding per
12
+ problem with a hint. The JSON shape:
23
13
 
24
- ```sh
25
- rigor plugins --strict
14
+ ```json
15
+ { "status": "issues_found",
16
+ "checks": [ { "id": "plugins", "status": "fail",
17
+ "message": "Plugin load errors: 1",
18
+ "hint": "Run `rigor plugins --strict` for the full per-plugin report." } ] }
26
19
  ```
27
20
 
28
- Reports the activation status of each plugin in `plugins:`; `--strict`
29
- exits non-zero on any failure. A failure is usually a misspelled id or a
21
+ - Top-level `status` is `issues_found` when any check has `status: "fail"`,
22
+ otherwise `clean` — a run with only `warn` findings still reads `clean`,
23
+ so read the `checks` array too.
24
+ - `checks[].status` is `fail`, `warn`, or `pass`. A check with nothing to
25
+ report is usually **absent**, not `pass`; only `rbs_environment` reports
26
+ a `pass` line.
27
+ - The command exits non-zero when any check fails.
28
+
29
+ Fix `fail` findings first, in the order below: an early failure is usually
30
+ the root cause of a cluster of confusing downstream diagnostics.
31
+
32
+ ## The check ids
33
+
34
+ ### `config_audit` — config resolves with nothing silently inert
35
+
36
+ `fail` with a count of configuration warnings. Doctor gives only the
37
+ count; the individual warnings are in `rigor check --format json` under
38
+ `config_warnings`. They cover the typo class whose only symptom is a
39
+ confusing downstream error: a `signature_paths:` that is missing / not a
40
+ directory / holds no `.rbs` (which would turn every covered call into a
41
+ false `call.undefined-method` at `evidence_tier: high`), a `libraries:`
42
+ name RBS does not recognise, a `disable:` / `severity_overrides:` id
43
+ naming no real rule, or a missing `bundler` / `rbs_collection` path.
44
+ **Each warning is a real misconfiguration — fix it.**
45
+
46
+ ### `rbs_environment` — the type universe loaded
47
+
48
+ - `fail` — the RBS environment is empty (zero classes). It failed to build
49
+ or loaded no signatures: look for duplicate declarations across
50
+ `signature_paths:`, or run `rbs collection install` for gem signatures.
51
+ - `warn` — degraded: one or more `signature_paths:` files did not parse
52
+ and were skipped. The run is quieter, not cleaner — the types those
53
+ files declare are gone. Run `rbs validate` on the `sig/` set and fix
54
+ the parse error.
55
+ - `pass` — healthy, with the class count.
56
+
57
+ ### `plugins` — every configured plugin loads
58
+
59
+ `fail` with a count of plugin load errors. Run `rigor plugins --strict`
60
+ for the per-plugin report. A failure is usually a misspelled id or a
30
61
  plugin whose `signature_paths:` did not resolve. Fix it, or the plugin's
31
62
  type knowledge is silently absent.
32
63
 
33
- ## 3. The baseline is not stale (if one exists)
64
+ ### `plugin_skew` — a bundled plugin came from another installation
34
65
 
35
- ```sh
36
- rigor baseline drift
37
- ```
66
+ `warn` when a bundled plugin was loaded from a different `rigortype`
67
+ installation than the engine. The engine and its bundled plugins are
68
+ versioned together, so a mismatched copy can produce wrong diagnostics.
69
+ Make sure a single `rigortype` is on the load path.
70
+
71
+ ### `baseline` — the baseline is not stale (if one exists)
72
+
73
+ - `fail` — drift: some baseline buckets are over their recorded count,
74
+ cleared, or reducible. The hint is `rigor baseline regenerate`; before
75
+ regenerating, run `rigor baseline drift` to see which buckets moved, so
76
+ a regeneration does not bury a new catch (often after an upgrade — see
77
+ `rigor-upgrade`).
78
+ - `warn` — the baseline file failed to load. Check the `baseline:` path
79
+ in the config.
80
+
81
+ ### `plugin_gap` — the stack has a plugin that is not enabled
82
+
83
+ Read from the `DEPENDENCIES` section of `Gemfile.lock`.
84
+
85
+ - `fail` — the project depends on gems that bundled plugins model, and
86
+ **none** of those plugins is enabled: framework calls will not resolve.
87
+ Add the plugins for the stack to `plugins:` (the `rigor-plugin-tune`
88
+ skill does this).
89
+ - `warn` — one per plugin that models a direct dependency but is not
90
+ enabled. Enable it, or leave it out deliberately; declining a plugin is
91
+ a legitimate choice.
92
+
93
+ ### `gemfile_install` — Rigor is a project dependency
94
+
95
+ `fail` when `rigortype` is resolved from a gem source in the project's
96
+ `Gemfile.lock`. Rigor is a tool, not a library: remove it from the
97
+ `Gemfile` and install it standalone (`rigor docs manual/01-installation`).
98
+
99
+ ### `bundle_layout` — gem-shipped signatures are not discovered
38
100
 
39
- Shows whether the live diagnostics have drifted from `.rigor-baseline.yml`
40
- — entries the baseline ignores that no longer occur (safe to prune) and
41
- new diagnostics outside the envelope. A large drift means the baseline
42
- needs regenerating (often after an upgrade — see `rigor-upgrade`).
101
+ `warn` when a `Gemfile.lock` exists but Rigor cannot locate the installed
102
+ bundle (the gems live in the active Ruby's default gem home). Gems that
103
+ ship their own `sig/` are then not loaded. Point Rigor at the install
104
+ root with `bundler.bundle_path:`, install into `vendor/bundle`, or supply
105
+ signatures with `rbs collection install` instead.
43
106
 
44
- ## 4. The analysis is actually seeing your code
107
+ ## Not covered by `rigor doctor`: is the analysis seeing your code?
45
108
 
46
109
  ```sh
47
- rigor check --format json # check the "Ruby source files" count
110
+ rigor check --no-cache --format json | jq '.stats.target_files'
48
111
  ```
49
112
 
50
- If the file count is `0` or far below your project size, `paths:` /
51
- `exclude:` are mis-scoped, or the command is running from the wrong
113
+ `--no-cache` matters: a result served from the run cache carries no
114
+ `stats`. If the file count is `0` or far below your project size, `paths:`
115
+ / `exclude:` are mis-scoped, or the command is running from the wrong
52
116
  directory. The analysis is only as good as the files it reads.
@@ -1,7 +1,9 @@
1
1
  ---
2
2
  name: rigor-editor-setup
3
- description: |
4
- Wire Rigor's bundled language server (`rigor lsp`) into the developer's editor for live diagnostics, hover-to-type, outline, and type-aware completion. The per-editor config snippets live in the manual; this skill identifies the editor, applies the right one, and verifies the server attaches. Triggers: "set up Rigor in my editor", "rigor LSP / language server", "live Rigor diagnostics in VS Code / Neovim / Helix / Emacs", "hover types in my editor". NOT for CI integration (use rigor-ci-setup) or first-time project setup (use rigor-project-init).
3
+ description: >-
4
+ Set up Rigor's bundled language server for live diagnostics, hover, outline, and completion in a
5
+ developer's editor. Use when wiring `rigor lsp` into VS Code, Neovim, Helix, Emacs, or another LSP
6
+ client; not for CI or first-time project setup.
5
7
  license: MPL-2.0
6
8
  metadata:
7
9
  version: 0.1.0
@@ -24,7 +26,7 @@ rigor docs editor-integration
24
26
  ```
25
27
 
26
28
  (Web fallback, only before Rigor is installed:
27
- **[Rigor LSP — Editor Integration](../../docs/manual/09-editor-integration.md)**.)
29
+ **[Rigor LSP — Editor Integration](https://github.com/rigortype/rigor/blob/master/docs/manual/09-editor-integration.md)**.)
28
30
  This skill is the *workflow* around it (identify the editor → apply the
29
31
  manual's snippet → verify), so it does not duplicate (and cannot
30
32
  stale-out) the config details.
@@ -62,7 +64,7 @@ Every editor snippet simply launches **`rigor lsp`** (stdio) and needs
62
64
  **`rigor` on the editor's `PATH`** — the same executable `rigor check`
63
65
  uses. For GUI editors that do not inherit your shell, the `mise` shim
64
66
  path is the most reliable channel (see `rigor docs install`, or
65
- [Installing Rigor](../../docs/install.md)
67
+ [Installing Rigor](https://github.com/rigortype/rigor/blob/master/docs/install.md)
66
68
  on the web). Do **not** add `rigortype` to the project's `Gemfile` — it
67
69
  is a tool, not a library.
68
70