Class: RailsAiContext::Tools::ValidateSemantics
- Defined in:
- lib/rails_ai_context/tools/validate_semantics.rb
Overview
Semantic (Rails-aware) half of the rails_validate tool: the Prism visitor and the per-rule checks it feeds. Split from Validate, which keeps syntax validation and orchestration, so a new rule lands here without touching the tool entry point.
Inherits BaseTool for cached_context only; abstract! keeps it out of the MCP tool registry.
Defined Under Namespace
Classes: RailsSemanticVisitor
Constant Summary collapse
- ASSET_HELPER_PREFIXES =
── CHECK 2: Route helpers (AST) ─────────────────────────────────
%w[image asset font stylesheet javascript audio video file compute_asset auto_discovery_link favicon].freeze
- DEVISE_HELPER_NAMES =
%w[session registration password confirmation unlock omniauth_callback user_session user_registration user_password user_confirmation user_unlock].freeze
- MEMORY_LOAD_METHODS =
── CHECK: Memory-loading anti-pattern ───────────────────────────
%w[map filter_map flat_map select reject collect reduce inject each_with_object].freeze
Constants inherited from BaseTool
BaseTool::DEFAULT_SESSION, BaseTool::MAX_SESSIONS, BaseTool::MAX_SESSION_ID_LENGTH, BaseTool::SESSION_CONTEXT, BaseTool::SHARED_CACHE
Class Method Summary collapse
-
.check_brakeman_security(files) ⇒ Object
── Brakeman security scan (runs once for all files) ───────────.
-
.check_rails_semantics(file, full_path) ⇒ Object
── Semantic check dispatcher ────────────────────────────────────.
Methods inherited from BaseTool
abstract!, abstract?, api_only_app?, api_only_note, cache_key, cached_context, config, current_session, #dedupe_put_patch_routes, detail_param?, error_response, evict_oldest_sessions, extract_method_source_from_file, extract_method_source_from_string, find_closest_match, fuzzy_find_key, guide_row, inherited, introspection_warnings_note, invalid_detail_note, normalize_detail, not_found_response, paginate, rails_app, rails_env_name, registered_tools, reset_all_caches!, reset_cache!, session_from, session_params, session_queries, session_record, session_reset!, static_tier_banner, static_tier_refusal, text_response, touch_session, unavailable_note, with_session, with_session_for
Methods included from SectionFetch
Methods included from CountPhrase
Class Method Details
.check_brakeman_security(files) ⇒ Object
── Brakeman security scan (runs once for all files) ───────────
857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 |
# File 'lib/rails_ai_context/tools/validate_semantics.rb', line 857 def self.check_brakeman_security(files) return [] unless brakeman_available? tracker = Brakeman.run( app_path: rails_app.root.to_s, quiet: true, report_progress: false, print_report: false ) warnings = tracker.filtered_warnings return [] if warnings.empty? # Filter to only warnings in the validated files normalized = files.map { |f| f.delete_prefix("/") } relevant = warnings.select do |w| path = w.file.relative normalized.any? { |f| path == f || path.start_with?(f) } end return [] if relevant.empty? relevant.sort_by(&:confidence).first(5).map do |w| loc = w.line ? "#{w.file.relative}:#{w.line}" : w.file.relative "[#{w.confidence_name}] #{w.warning_type} - #{loc}: #{w.}" end rescue => e $stderr.puts "[rails-ai-context] check_brakeman_security failed: #{e.}" if ENV["DEBUG"] [] end |
.check_rails_semantics(file, full_path) ⇒ Object
── Semantic check dispatcher ────────────────────────────────────
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
# File 'lib/rails_ai_context/tools/validate_semantics.rb', line 191 def self.check_rails_semantics(file, full_path) warnings = [] context = begin; cached_context; rescue; return warnings; end return warnings unless context content = RailsAiContext::SafeFile.read(full_path) return warnings unless content # Parse with Prism AST visitor (single pass for all checks) visitor = parse_and_visit(file, content) if file.end_with?(".html.erb", ".erb") if visitor warnings.concat(check_partial_existence_ast(file, visitor)) warnings.concat(check_route_helpers_ast(file, visitor, context)) else warnings.concat(check_partial_existence_regex(file, content)) warnings.concat(check_route_helpers_regex(file, content, context)) end warnings.concat(check_stimulus_controllers(content, context)) warnings.concat(check_instance_variable_usage(file, content, context)) warnings.concat(check_respond_to_template_existence(file, content)) elsif file.end_with?(".rb") if visitor warnings.concat(check_route_helpers_ast(file, visitor, context)) warnings.concat(check_partial_existence_ast(file, visitor, qualified_only: true)) warnings.concat(check_column_references_ast(file, visitor, context)) warnings.concat(check_strong_params_ast(file, visitor, context)) warnings.concat(check_callback_existence_ast(file, visitor, context)) else warnings.concat(check_route_helpers_regex(file, content, context)) warnings.concat(check_column_references_regex(file, content, context)) end # Cache-only checks (no AST needed) warnings.concat(check_has_many_dependent(file, context)) warnings.concat(check_missing_fk_index(file, context)) warnings.concat(check_route_action_consistency(file, context)) warnings.concat(check_turbo_stream_channels(file, content, context)) warnings.concat(check_memory_loading(file, content)) if file.start_with?("app/controllers/") end # Performance checks from performance introspector warnings.concat(check_performance_warnings(file, context)) warnings end |