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
@@ -75,12 +75,12 @@ Use the sections like this:
75
75
  | --- | --- | --- |
76
76
  | `activesupport-core-ext` | ActiveSupport core-class monkey-patches not loaded. | Go back to Phase 3/4: add `rigor-activesupport-core-ext` to `plugins:` (it is an RBS-bundle plugin), re-run triage. This is a config gap, not a bug. |
77
77
  | `gem-without-rbs` | A dependency ships no RBS. | If `rbs_collection.lock.yaml` was present and Phase 1 installed the collection, re-run `rigor triage` — the hint may shrink or disappear. Otherwise: Phase 8 escalation — `bundle exec rbs collection install`, or `dependencies.source_inference:`, or open a Rigor issue. |
78
- | `project-monkey-patch-known` | **High confidence.** The engine proved the called method *is* defined by a project file (a reopened core/stdlib/gem class) but is not applied cross-file. The hint **names the defining file(s)**. | Phase 7 escalation — copy the named file(s) straight into `pre_eval:`. No detective work needed; the diagnostic already found the source. |
79
- | `project-monkey-patch` | An in-project monkey-patch / refinement Rigor did not see, inferred from the *spread* of the same method across ≥3 files (no proven def site). | Phase 7 escalation — find the defining file (grep for `def <method>` / `class <Receiver>`), register it via `pre_eval:`, or (if it is a DSL) write a project plugin. |
80
- | `unresolved-toplevel` | Toplevel calls (outside any `def`/`class`/`module`) that resolve to nothing visible — usually a script relying on a monkey-patch or a `require`d helper Rigor did not walk (ADR-34). | Phase 7 escalation — if a project file defines these (toplevel `def`, or a patch on `Object`/`Kernel`), list it in `pre_eval:`. If nothing defines them, treat as genuine typos / missing requires (Phase 8). |
78
+ | `project-monkey-patch-known` | **High confidence.** The engine proved the called method *is* defined by a project file (a reopened core/stdlib/gem class) but is not applied cross-file. The hint **names the defining file(s)**. | Phase 6a — copy the named file(s) straight into `pre_eval:`. No detective work needed; the diagnostic already found the source. |
79
+ | `project-monkey-patch` | An in-project monkey-patch / refinement Rigor did not see, inferred from the *spread* of the same method across ≥3 files (no proven def site). | Phase 6a — find the defining file (grep for `def <method>` / `class <Receiver>`), register it via `pre_eval:`, or (if it is a DSL) write a project plugin. |
80
+ | `unresolved-toplevel` | Toplevel calls (outside any `def`/`class`/`module`) that resolve to nothing visible — usually a script relying on a monkey-patch or a `require`d helper Rigor did not walk (ADR-34). | Phase 6a — if a project file defines these (toplevel `def`, or a patch on `Object`/`Kernel`), list it in `pre_eval:`. If nothing defines them, treat as genuine typos / missing requires (Phase 8). |
81
81
  | `activerecord-relation-misinference` | An ActiveRecord relation inferred as `Array`. | Ensure `rigor-activerecord` is enabled (Phase 3). If it persists, it is an engine gap — open a Rigor issue. |
82
82
  | `systemic-file-cluster` | One file × one rule, large count. | Acknowledge mode: a clean baseline bucket. Strict mode: a single fix may clear many — review that file first. |
83
- | `genuine-bugs` | Low-count rules scattered across files. | **Phase 7** — these are the localised bugs Rigor caught. Review first, in both modes. Note: the hint groups all low-count rules regardless of severity — filter for `error` severity when prioritising actionable items. |
83
+ | `genuine-bugs` | Low-count rules scattered across files. | **Phase 8** — these are the localised bugs Rigor caught. Review first, in both modes. Note: the hint groups all low-count rules regardless of severity — filter for `error` severity when prioritising actionable items. |
84
84
 
85
85
  If triage flags `activesupport-core-ext` (or any config gap),
86
86
  **fix the config and re-run `rigor triage` before continuing**. The
@@ -170,8 +170,8 @@ bundle exec rbs collection install # if rbs is in Gemfile
170
170
  # or: rbs collection install
171
171
  ```
172
172
 
173
- Re-run `rigor triage`. If the `gem-without-rbs` count drops,
174
- re-generate the baseline against the new number.
173
+ Re-run `rigor triage`. If the `gem-without-rbs` count drops, carry
174
+ the new, smaller count into Phase 7.
175
175
 
176
176
  ## Phase 7 — Generate the baseline (acknowledge mode only)
177
177
 
@@ -215,7 +215,8 @@ So ordinary coding cannot quietly grow the diagnostic count: the
215
215
  baseline is a ceiling, not a blanket. Reducing it later is the
216
216
  `rigor-baseline-reduce` skill's job.
217
217
 
218
- Commit `.rigor-baseline.yml` — it documents project state.
218
+ Recommend committing `.rigor-baseline.yml` — it documents project
219
+ state; list it in the Final step's file inventory.
219
220
 
220
221
  Print the suppression summary for the user: "N diagnostics recorded
221
222
  as baseline; M will surface on subsequent runs."
@@ -288,18 +289,17 @@ sig issue.
288
289
 
289
290
  #### `call.argument-type-mismatch` on regex capture variables (`$1`, `$~`)
290
291
 
291
- Rigor infers `$1`, `$~`, and similar capture variables as
292
- `String | nil` everywhere, even inside `gsub`/`match` blocks where
293
- they are guaranteed non-nil by the match condition. Diagnostics of
294
- the form:
292
+ Rigor narrows `$1`, `$~`, and similar capture variables to non-nil
293
+ after a successful `=~` match and inside a `when /re/` branch. Where
294
+ the match is guaranteed by some other shape Rigor does not track, they
295
+ stay `String | nil`, and a diagnostic of the form:
295
296
 
296
297
  ```
297
298
  expected String, got String | nil (on $1 / $~)
298
299
  ```
299
300
 
300
- are **engine FPs** (ADR-24 WD3 / known limitation). Note them as
301
- noise rather than surfacing them as bugs. They belong in the
302
- baseline.
301
+ is an **engine FP** (ADR-24 WD3 / known limitation). Note it as noise rather than
302
+ surfacing it as a bug; it belongs in the baseline.
303
303
 
304
304
  ### Escalation path A — application-specific metaprogramming
305
305
 
@@ -28,7 +28,8 @@ rigor sig-gen lib # adjust path to match the paths: key
28
28
  Typical output at this point: most `new_method` candidates have
29
29
  literal or concrete return types (`"hello"`, `42`, `:done`, `nil`).
30
30
  Methods whose return type cannot be inferred show up with
31
- `skip_reason: :untyped_return` — these are the sig precision targets.
31
+ `skip_reason: "sig.skipped.untyped-return"` — these are the sig
32
+ precision targets.
32
33
 
33
34
  To get a breakdown in JSON:
34
35
 
@@ -50,6 +51,12 @@ rigor sig-gen --format json lib | ruby -e '
50
51
 
51
52
  ## Step 5-b — Write the baseline sigs
52
53
 
54
+ If the project's `Steepfile` reads inline annotations (`inline: true`
55
+ beside `signature "sig"`), first add `sig_gen:` / `inline_declared: skip`
56
+ to `.rigor.yml`. Otherwise sig-gen copies every `# @rbs` / `#:`
57
+ declaration into `sig/`, and Steep reports each copied method as
58
+ `DuplicatedMethodDefinition`.
59
+
53
60
  ```sh
54
61
  rigor sig-gen --write lib
55
62
  ```
@@ -63,12 +70,18 @@ head -40 sig/lib/your_class.rbs
63
70
 
64
71
  At this point, `attr_reader` and `attr_accessor` methods that rely on
65
72
  ivar types set from `initialize` parameters will likely still be
66
- absent (classified as `:untyped_return`). Step 5-c fixes that.
73
+ absent (skipped as `sig.skipped.untyped-return`). Step 5-c fixes that.
74
+ An `attr_writer` or `attr_accessor` stays skipped even then unless its
75
+ ivar is assigned from an `initialize` parameter: the writer stores
76
+ whatever its caller passes, so the ivar reads untyped. That covers
77
+ `@count = 0` and `@logger = Logger.new` alike, and any other method
78
+ that returns the ivar.
67
79
 
68
80
  ## Step 5-c — Precision uplift with --params=observed
69
81
 
70
82
  `--params=observed` tells sig-gen to collect observed argument types
71
- from every call site it processes during the analysis pass. The most
83
+ from the call sites in the project's test roots — the `test_paths:`
84
+ Phase 4 wrote (`--observe=PATH` overrides them for one run). The most
72
85
  important use case: **`attr_reader` / `attr_writer` / `attr_accessor`
73
86
  methods whose `@ivar` is assigned from an `initialize` parameter**.
74
87
 
@@ -88,7 +101,8 @@ Person.new("Alice", 30)
88
101
  Person.new("Bob", 25)
89
102
  ```
90
103
 
91
- Without observations: `attr_reader :name` → skipped as `:untyped_return`
104
+ Without observations: `attr_reader :name` → skipped as
105
+ `sig.skipped.untyped-return`
92
106
  (the ivar's type is unknown because the blank inference scope never
93
107
  sees the parameter values).
94
108
 
@@ -129,9 +143,9 @@ there are a few options depending on the cause:
129
143
  | Pattern | Cause | Fix |
130
144
  |---|---|---|
131
145
  | `attr_reader :x` with `@x` never set in `initialize` | ivar set from a DB query, config read, or side effect | Add a hand-written sig: create (or edit) `sig/your_class.rbs` with `attr_reader x: String` |
132
- | Deep method chains on untyped receivers | Cascade from a gem with no RBS | `rbs collection install`; Phase 7 escalation path B |
146
+ | Deep method chains on untyped receivers | Cascade from a gem with no RBS | `rbs collection install`; Phase 8 escalation path B |
133
147
  | Recursive or mutually recursive methods | Return type not inferrable without a base case | Add a `# @rbs return: YourType` inline annotation, or a hand-written sig |
134
- | Dynamic methods (`define_method`, DSL) | Metaprogramming Rigor cannot follow | Phase 7 escalation path A (project plugin) |
148
+ | Dynamic methods (`define_method`, DSL) | Metaprogramming Rigor cannot follow | Phase 8 escalation path A (project plugin) |
135
149
 
136
150
  Do not spend long on residual `untyped` methods at this stage — a
137
151
  handful of `untyped` returns in `sig/` does not block adoption. The
@@ -140,12 +154,10 @@ reach perfect sig coverage.
140
154
 
141
155
  ## Step 5-e — Commit the sig/ directory
142
156
 
143
- Once you are satisfied with the initial sig quality:
144
-
145
- ```sh
146
- git add sig/
147
- git commit -m "Add initial RBS sigs from rigor sig-gen (--params=observed)"
148
- ```
157
+ Once you are satisfied with the initial sig quality, recommend
158
+ committing `sig/`: list it in the Final step's file inventory
159
+ (`SKILL.md` § "Final step") rather than committing it here — the user
160
+ confirms every commit.
149
161
 
150
162
  A committed `sig/` is a first-class project artefact: it improves
151
163
  inference quality on every subsequent run and is maintained alongside
@@ -164,8 +176,9 @@ the source (add new sig files when adding classes; update sigs with
164
176
 
165
177
  ## Output of this module
166
178
 
167
- A committed `sig/` directory with RBS skeletons for all statically
168
- inferrable methods. Remaining `:untyped_return` methods are noted for
179
+ A `sig/` directory, ready to commit, with RBS skeletons for all
180
+ statically inferrable methods. Remaining `sig.skipped.untyped-return`
181
+ methods are noted for
169
182
  potential manual annotation; they do not block Phase 6.
170
183
 
171
184
  Proceed to Phase 6 ([`03-baseline-and-bugs.md`](03-baseline-and-bugs.md)).
@@ -0,0 +1,67 @@
1
+ # 06 — Install the agent type-contract into AGENTS.md / CLAUDE.md
2
+
3
+ Covers **Phase 8a**. Input: an onboarded project (config written, sigs
4
+ generated, baseline decided). Output: one section in the file the
5
+ project's coding agents read at startup.
6
+
7
+ ## Why this is part of onboarding
8
+
9
+ Everything the earlier phases produced — `sig/`, the baseline, the
10
+ severity profile — is a record of what Rigor *proved*. The moment an AI
11
+ agent starts contributing to the project, it can write types that Rigor
12
+ never proved: a `@param currency [String]` in a doc comment, an
13
+ rbs-inline `#:` that Rigor then ingests as a live contract. Those enter
14
+ the same files, look identical to derived types, and are believed.
15
+
16
+ The fix is not a tool. It is one paragraph in the project's agent
17
+ contract, so the rule is in context every session rather than only when
18
+ a skill happens to trigger: **a type not obtained from Rigor is a guess,
19
+ and a guessed type is never written.**
20
+
21
+ ## The text
22
+
23
+ The canonical fragment is served by the installed Rigor, so it stays
24
+ current with the CLI it names:
25
+
26
+ ```sh
27
+ rigor skill --full rigor-type-oracle
28
+ ```
29
+
30
+ Its `references/02-agents-md-fragment.md` section carries the paragraph
31
+ and the five bullets. Copy that block **verbatim** — including its
32
+ single-long-line shape, which is deliberate (some renderers turn a
33
+ newline inside a paragraph into a line break).
34
+
35
+ Do not paraphrase it from memory, and do not shorten it: the five bullets
36
+ are the load-bearing part — expression, method signature, parameter,
37
+ the gap rule, and provenance.
38
+
39
+ ## Where it goes
40
+
41
+ | Project state | What to do |
42
+ | --- | --- |
43
+ | `AGENTS.md` exists | **Append** the section at the end. Do not reorganise the file. |
44
+ | Only `CLAUDE.md` exists | Append it there. |
45
+ | Both exist | Put it in `AGENTS.md`. Add `@AGENTS.md` to `CLAUDE.md` only if it is not already pulled in. |
46
+ | Neither exists | **Create `AGENTS.md`** with this as its first section. |
47
+ | A types / type-checking section already exists | Merge into it; keep the five bullets intact. Never write a second, competing rule. |
48
+
49
+ Never overwrite unrelated content. If the project already states a rule
50
+ about type authorship that contradicts this one, stop and show the user
51
+ the conflict — the project's own rule wins until they say otherwise.
52
+
53
+ ## Report it in the final step
54
+
55
+ This is a change to the file that governs every future agent session in
56
+ the repo, so it belongs in Phase 9's file inventory, not in a silent
57
+ diff. Recommend committing it: the point is that every contributor's
58
+ agent reads the same rule.
59
+
60
+ ## When to skip
61
+
62
+ - The project has no coding-agent contract file **and** the user has said
63
+ they do not use AI agents on it. Offer once, accept "no".
64
+ - The user declined it earlier in this session.
65
+
66
+ Otherwise install it — an unonboarded agent is the one contributor that
67
+ cannot be trained by review.
@@ -1,7 +1,9 @@
1
1
  ---
2
2
  name: rigor-protection-uplift
3
- description: |
4
- Close the type-protection holes `rigor coverage --protection` surfaces: for each unprotected dispatch site, run `rigor sig-gen` first, hand-author only the minimal residual annotation, then verify with a double gate — the site becomes protected AND `rigor check` gains no new diagnostic. Triggers: "raise type protection", "add types where Rigor can't catch bugs", "act on coverage --protection / --mutation output", "make more of this code bug-catchable". NOT for Rigor's own `lib/` or the bundled plugins (use `rigor sig-gen` directly there and treat gaps as engine signal), and NOT for first-time setup (use rigor-project-init).
3
+ description: >-
4
+ Close the protection gaps reported by `rigor coverage --protection`, using generated signatures before
5
+ minimal residual annotations and a no-new-diagnostics gate. Use when increasing bug-catching coverage
6
+ in an adopting project; not for Rigor's own tree, bundled plugins, or first-time setup.
5
7
  license: MPL-2.0
6
8
  metadata:
7
9
  version: 0.1.0
@@ -40,10 +42,6 @@ copy — just proceed. If `rigor` is not on `PATH`, this task needs it: run
40
42
 
41
43
  ## When NOT to use
42
44
 
43
- - **Rigor's own `lib/`, or the bundled `plugins/` / `examples/`** — the
44
- self-check tree. Hand-authoring types there collides with the
45
- sig-gen-first ethos; run `rigor sig-gen` directly and treat residual
46
- gaps as engine signal to report, not a private fix.
47
45
  - **"Make my code more precise" with no protection goal** — that is
48
46
  `rigor coverage` (precision), not `--protection`.
49
47
  - **A project with no Rigor config yet** — onboard first with
@@ -1,7 +1,9 @@
1
1
  ---
2
2
  name: rigor-rbs-setup
3
- description: |
4
- Install community RBS for the project's gems with `rbs collection install`, so Rigor stops typing calls into RBS-less dependencies as `Dynamic` and gains real coverage (and real bug-catching) on them. Rigor auto-detects the resulting `rbs_collection.lock.yaml` — no Rigor config change needed. Triggers: "set up rbs collection", "my gems type as Dynamic", "rigor check says N gems have no RBS available", "reduce false positives from untyped gems". NOT for first-time Rigor setup (use rigor-project-init first) and NOT for a gem that has no entry in the community collection (that needs rigor-plugin-author or a Rigor issue).
3
+ description: >-
4
+ Install community RBS for a project's gems so Rigor can type dependencies that currently become
5
+ `Dynamic`. Use when `rbs collection` is missing or untyped gems limit coverage; not for first-time
6
+ Rigor setup or a gem with no community RBS entry.
5
7
  license: MPL-2.0
6
8
  metadata:
7
9
  version: 0.1.0
@@ -0,0 +1,226 @@
1
+ ---
2
+ name: rigor-type-oracle
3
+ description: >-
4
+ Obtain a Ruby type from Rigor before writing or asserting it, using `type-of`, `annotate`, or `sig-gen`
5
+ as appropriate. Use when adding RBS, inline annotations, Sorbet/YARD types, type-shaped docs, or
6
+ type-justified guards; not for Rigor setup or baseline reduction.
7
+ license: MPL-2.0
8
+ metadata:
9
+ version: 0.1.0
10
+ homepage: https://github.com/rigortype/rigor
11
+ ---
12
+
13
+ # Rigor Type Oracle
14
+
15
+ You are about to write a type. Stop and ask Rigor first.
16
+
17
+ This project has a deterministic type oracle installed. Reading the
18
+ source and concluding "`currency` is a String, `pattern` is a Regexp" is
19
+ *plausible-guess* behaviour: it is right often enough to feel safe and
20
+ wrong often enough to poison a signature file, a doc comment, or a
21
+ reviewer's mental model. Rigor already knows the answer — for every
22
+ expression, at every line, from the same engine that will check the code
23
+ tomorrow. Asking it costs one command.
24
+
25
+ **The rule: a type you did not obtain from Rigor is a guess, and a
26
+ guessed type is never written anywhere.** Not in `sig/`, not in an inline
27
+ annotation (`#:`, `# @rbs`), not in a Sorbet `sig`, not in a YARD tag,
28
+ not in a doc sentence, not in a review comment, and not as the stated
29
+ reason for a nil check or an `is_a?` guard.
30
+
31
+ ## First: load the version-current copy
32
+
33
+ This skill's exact commands, flags, output spellings, and skip-reason ids
34
+ drift between Rigor releases, so follow the copy that ships with the
35
+ **installed** Rigor rather than any vendored or frozen copy of this file.
36
+ Get the complete current procedure in one call:
37
+
38
+ ```sh
39
+ rigor skill --full rigor-type-oracle # this body + all its references/, inline
40
+ ```
41
+
42
+ If you already loaded this skill *via* `rigor skill` you have the current
43
+ copy — just proceed (read any `references/NN-*.md` from the directory the
44
+ header names). If `rigor` is not on `PATH`, this task needs it: run
45
+ **`rigor-next-steps`** to install Rigor first, then come back.
46
+
47
+ ## When to use
48
+
49
+ Trigger on the *act*, not on the user saying the word "type". You are in
50
+ scope the moment you are about to write or assert one:
51
+
52
+ - Writing or editing RBS under `sig/`.
53
+ - Writing an inline annotation — rbs-inline `#:`, `# @rbs`, a
54
+ `%a{rigor:v1:…}` override.
55
+ - Writing a Sorbet `sig do … end`, or any other type DSL.
56
+ - Writing a YARD / RDoc `@param` / `@return` / `@raise`, or any doc
57
+ sentence that names a type ("returns an Array of entries").
58
+ - Stating a type in a review comment, a PR description, or a chat answer.
59
+ - Justifying a nil check, an `is_a?` / `respond_to?` guard, or a
60
+ defensive `to_s` with "this should be an X".
61
+ - Being asked "what type is this?", "what does this method return?",
62
+ "add types to this class", "document this file".
63
+
64
+ ## When NOT to use
65
+
66
+ - **Setting Rigor up on a project that has none** → `rigor-next-steps`
67
+ (which routes to `rigor-project-init`). You cannot ask an oracle that
68
+ is not installed.
69
+ - **Working an existing `.rigor-baseline.yml` down** →
70
+ `rigor-baseline-reduce`. That is fixing diagnostics, not sourcing a
71
+ type.
72
+ - **Raising type protection from a `coverage --protection` list** →
73
+ `rigor-protection-uplift`. It owns the "where should a type go, and how
74
+ do I verify it" loop; this skill owns "where does the type itself come
75
+ from".
76
+
77
+ ## The three allowed sources
78
+
79
+ Every type you write comes from exactly one of these. There is no fourth.
80
+
81
+ | What you need | Ask Rigor with | What you write |
82
+ | --- | --- | --- |
83
+ | The type of an **expression** at a point | `rigor type-of FILE:LINE:COL` — or `rigor annotate FILE` for every line at once | the `type:` it prints, verbatim |
84
+ | The **signature of a method** | `rigor sig-gen --print FILE` | the RBS it prints, verbatim — never what you expected it to print |
85
+ | A **parameter's intended type** | `rigor sig-gen --observe PATH --params=observed` (call-site derivation) | the observed type, *reviewed and widened*, kept only while `rigor check` stays green |
86
+
87
+ The parameter row is the one genuine gap. Inference reads a method
88
+ *body*, and a body does not state what its callers are allowed to pass —
89
+ so Rigor spells parameters `untyped` by design ([ADR-5](https://github.com/rigortype/rigor/blob/master/docs/adr/5-robustness-principle.md):
90
+ strict on returns, lenient on parameters). `--params=observed` derives
91
+ them from the call sites instead, which is evidence rather than
92
+ invention — but it is *narrow* evidence (it can emit literal types such
93
+ as `("JPY")`), so it is the one place you review and widen before
94
+ adopting, under the gate that `rigor check` gains no new diagnostic.
95
+
96
+ Exact command forms, flags, position syntax, JSON shapes, and how to read
97
+ each output: [`references/01-oracle-commands.md`](references/01-oracle-commands.md).
98
+
99
+ ## The gap protocol — a gap is a finding, not a blank to fill
100
+
101
+ `Dynamic[top]`, `untyped`, and a `sig.skipped.*` classification are
102
+ **answers**. They mean "Rigor cannot prove a type here", which is
103
+ information about the project or about the engine. Filling that hole with
104
+ your own reading converts a known unknown into a confident falsehood, and
105
+ it does so in a file the next reader will trust.
106
+
107
+ So when the oracle comes back empty:
108
+
109
+ 1. **Report it.** Give the exact command and its exact output.
110
+ 2. **Find out why**, when it matters: `rigor trace --format=json --line=N FILE`
111
+ replays how the type was built; `rigor explain <rule>` documents a
112
+ diagnostic that fired nearby.
113
+ 3. **Route it.** A project-side gap has a sibling skill that closes it
114
+ (missing gem RBS → `rigor-rbs-setup`; an unconfigured framework →
115
+ `rigor-plugin-tune`; the project's own monkey-patches →
116
+ `rigor-monkeypatch-resolve`; a project DSL → `rigor-plugin-author`).
117
+ An engine-side gap is a Rigor issue.
118
+
119
+ Which output means which gap, the full routing table, and how to word the
120
+ issue: [`references/03-gap-protocol.md`](references/03-gap-protocol.md).
121
+
122
+ ## Provenance — every type you state carries its command
123
+
124
+ When you tell a human a type, tell them how to re-derive it. One line is
125
+ enough:
126
+
127
+ > `entries_matching` returns `Array[untyped] | []`
128
+ > (`rigor sig-gen --print lib/demo/budget_ledger.rb`).
129
+
130
+ This is not ceremony. It is the difference between an assertion the
131
+ reader must trust and a claim they can re-run in three seconds — and it
132
+ is what makes a wrong answer *findable* instead of permanent.
133
+
134
+ ## With the MCP server connected, use the tools
135
+
136
+ If the Rigor MCP server is wired up (`rigor-mcp-setup`), `rigor_type_of`,
137
+ `rigor_annotate`, `rigor_sig_gen`, `rigor_check`, and `rigor_explain` are
138
+ the same oracle as tool calls — prefer them over shelling out, and treat
139
+ their results exactly as this skill treats CLI output. Argument shapes:
140
+ [`references/01-oracle-commands.md`](references/01-oracle-commands.md)
141
+ § "The MCP tools".
142
+
143
+ ## Worked example
144
+
145
+ Asked to document `Demo::BudgetLedger`, the guessing path writes
146
+ `@param currency [String]`, `@return [Numeric]`, `@param pattern
147
+ [Regexp]`. Here is the oracle path.
148
+
149
+ ```sh
150
+ rigor annotate lib/demo/budget_ledger.rb
151
+ ```
152
+
153
+ ```ruby
154
+ def initialize(currency, opening_balance: 0) #=> Dynamic[top]
155
+ @currency = currency #=> Dynamic[top]
156
+ @entries = [] #=> []
157
+ def balance(as_of: nil) #=> Dynamic[top]
158
+ def entries_matching(pattern) #=> Array[Dynamic[top]] | []
159
+ ```
160
+
161
+ ```sh
162
+ rigor sig-gen --print lib/demo/budget_ledger.rb
163
+ ```
164
+
165
+ ```
166
+ rigor sig-gen: skipped 2 method(s) it could not type or would not overwrite
167
+ (sig.skipped.untyped-return: 2). Run with --format=json to see each one with
168
+ its skip_reason.
169
+ class Demo::BudgetLedger
170
+ def initialize: (untyped, ?opening_balance: untyped) -> void
171
+ def record: (untyped, ?memo: untyped, ?at: untyped) -> Demo::BudgetLedger
172
+ def entries_matching: (untyped) -> (Array[untyped] | [])
173
+ end
174
+ ```
175
+
176
+ What you now know, and may write: `record` returns
177
+ `Demo::BudgetLedger`; `entries_matching` returns `Array[untyped] | []`.
178
+ What you must **report rather than write**: `balance` and `overdrawn?`
179
+ were skipped as `sig.skipped.untyped-return` — `@opening_balance` is
180
+ `Dynamic[top]`, so the arithmetic proves nothing. `currency` is not
181
+ `String` on any evidence Rigor has; it is `untyped`, and the YARD tag is
182
+ `@param currency — the ledger's currency` with no type at all.
183
+
184
+ Call-site derivation closes the parameter half where specs exist:
185
+
186
+ ```sh
187
+ rigor sig-gen --print --params=observed --observe spec lib/demo/budget_ledger.rb
188
+ # def initialize: ("JPY", ?opening_balance: 100) -> void
189
+ # def entries_matching: (Regexp) -> (Array[untyped] | [])
190
+ ```
191
+
192
+ `entries_matching: (Regexp)` is now *derived*, and adoptable. The
193
+ `("JPY")` / `100` literals are the narrowness warned about above — widen
194
+ them to `String` / `Integer` before adopting, and keep the change only
195
+ while `rigor check` stays green.
196
+
197
+ ## When the user insists on a hand-written type anyway
198
+
199
+ They may. It is their code, and a human can know an intended contract
200
+ that no static reading can prove. Do not argue past one exchange:
201
+
202
+ 1. Say once what Rigor actually reports for that site, with the command.
203
+ 2. Write what they asked for.
204
+ 3. Run `rigor check` on the touched paths and report the result.
205
+ 4. **Say which lines the check covers.** A green `rigor check` proves
206
+ that the annotation contradicts nothing Rigor can currently see — it
207
+ does not prove the contract. Where the surrounding types are
208
+ `untyped`, there is nothing to contradict, and you must say so rather
209
+ than let a green run read as confirmation.
210
+
211
+ If the check *does* go red, the annotation modeled the wrong contract:
212
+ report it and revert, never suppress the diagnostic.
213
+
214
+ The same holds for an inline annotation a human wrote as documentation —
215
+ `#: void`, `#: :asc | :desc`, a parameter contract. It is their intent,
216
+ checked by `rigor check`, not a guess for you to "correct" to what inference
217
+ shows. Leave it; if the check finds a contradiction, report that.
218
+
219
+ ## Installing the rule in the project
220
+
221
+ An agent that never loads this skill still guesses. The durable fix is
222
+ one paragraph in the project's `AGENTS.md` / `CLAUDE.md`, so the rule is
223
+ in context every session rather than only when a skill happens to
224
+ trigger. The text to paste:
225
+ [`references/02-agents-md-fragment.md`](references/02-agents-md-fragment.md).
226
+ `rigor-project-init` installs it during onboarding.