rails-ai-bridge 5.1.0 → 5.2.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 (91) hide show
  1. checksums.yaml +4 -4
  2. data/.reek.yml +20 -19
  3. data/.rubocop.yml +7 -0
  4. data/AGENTS.md +4 -4
  5. data/Archspec.rb +53 -27
  6. data/CHANGELOG.md +134 -1
  7. data/CLAUDE.md +6 -5
  8. data/CONTRIBUTING.md +2 -2
  9. data/GEMINI.md +3 -4
  10. data/README.md +69 -11
  11. data/docs/COMPARISON.md +95 -0
  12. data/docs/EXAMPLES.md +260 -0
  13. data/docs/GUIDE.md +59 -5
  14. data/docs/ROADMAP.md +80 -0
  15. data/docs/{gem-general-improvements.md → archive/gem-general-improvements.md} +1 -1
  16. data/docs/{review-workflow-report.md → archive/review-workflow-report.md} +15 -15
  17. data/docs/design/dependency-graph.md +213 -0
  18. data/docs/design/multi-project-support.md +235 -0
  19. data/docs/design/prism-confidence-tags.md +214 -0
  20. data/docs/mcp-registry-submission.md +127 -0
  21. data/docs/mcp-security.md +52 -0
  22. data/docs/port-registry-resolution.md +309 -3
  23. data/docs/skill-registry-guide.md +1 -1
  24. data/lib/rails_ai_bridge/config/introspection.rb +2 -3
  25. data/lib/rails_ai_bridge/config/server.rb +7 -0
  26. data/lib/rails_ai_bridge/configuration.rb +1 -1
  27. data/lib/rails_ai_bridge/context_provider.rb +0 -1
  28. data/lib/rails_ai_bridge/database_size.rb +17 -4
  29. data/lib/rails_ai_bridge/doctor/checkers/http_structured_log_checker.rb +34 -0
  30. data/lib/rails_ai_bridge/doctor.rb +2 -1
  31. data/lib/rails_ai_bridge/http_transport_app.rb +0 -1
  32. data/lib/rails_ai_bridge/introspector/parallel_runner.rb +0 -1
  33. data/lib/rails_ai_bridge/introspector.rb +4 -7
  34. data/lib/rails_ai_bridge/introspectors/config_introspector.rb +0 -1
  35. data/lib/rails_ai_bridge/introspectors/controller_introspector.rb +0 -1
  36. data/lib/rails_ai_bridge/introspectors/model_introspector.rb +0 -1
  37. data/lib/rails_ai_bridge/introspectors/model_semantic_classifier.rb +170 -0
  38. data/lib/rails_ai_bridge/introspectors/path_resolver.rb +313 -0
  39. data/lib/rails_ai_bridge/introspectors/route_introspector.rb +0 -1
  40. data/lib/rails_ai_bridge/introspectors/schema_introspector.rb +0 -1
  41. data/lib/rails_ai_bridge/introspectors/semantic_introspector.rb +0 -1
  42. data/lib/rails_ai_bridge/registry/message_sanitizer.rb +1 -0
  43. data/lib/rails_ai_bridge/registry/pack_resolver.rb +0 -3
  44. data/lib/rails_ai_bridge/registry/rake_presenter.rb +0 -1
  45. data/lib/rails_ai_bridge/registry.rb +0 -5
  46. data/lib/rails_ai_bridge/rubydex_adapter/incremental_indexer.rb +1 -1
  47. data/lib/rails_ai_bridge/rubydex_adapter.rb +0 -4
  48. data/lib/rails_ai_bridge/serializers/anti_hallucination_rules/section_formatter.rb +21 -0
  49. data/lib/rails_ai_bridge/serializers/anti_hallucination_rules.rb +62 -0
  50. data/lib/rails_ai_bridge/serializers/context_file_serializer.rb +35 -19
  51. data/lib/rails_ai_bridge/serializers/formatters/providers/gemini_footer_formatter.rb +2 -1
  52. data/lib/rails_ai_bridge/serializers/json_serializer.rb +10 -1
  53. data/lib/rails_ai_bridge/serializers/markdown_serializer.rb +1 -0
  54. data/lib/rails_ai_bridge/{tools → serializers}/model_details/non_ar_models_appendix.rb +2 -2
  55. data/lib/rails_ai_bridge/serializers/providers/base_provider_serializer.rb +14 -3
  56. data/lib/rails_ai_bridge/serializers/providers/claude_rules_serializer.rb +23 -52
  57. data/lib/rails_ai_bridge/serializers/providers/claude_serializer.rb +0 -1
  58. data/lib/rails_ai_bridge/serializers/providers/codex_serializer.rb +0 -1
  59. data/lib/rails_ai_bridge/serializers/providers/codex_support_serializer.rb +11 -12
  60. data/lib/rails_ai_bridge/serializers/providers/copilot_instructions_serializer.rb +8 -21
  61. data/lib/rails_ai_bridge/serializers/providers/copilot_serializer.rb +0 -1
  62. data/lib/rails_ai_bridge/serializers/providers/cursor_rules_serializer.rb +1 -19
  63. data/lib/rails_ai_bridge/serializers/providers/devin_rules_serializer.rb +3 -21
  64. data/lib/rails_ai_bridge/serializers/providers/devin_serializer.rb +1 -1
  65. data/lib/rails_ai_bridge/serializers/providers/gemini_serializer.rb +0 -1
  66. data/lib/rails_ai_bridge/serializers/providers/rules_orchestrator.rb +0 -1
  67. data/lib/rails_ai_bridge/serializers/providers/rules_serializer.rb +0 -1
  68. data/lib/rails_ai_bridge/serializers/rule_file_writer.rb +44 -0
  69. data/lib/rails_ai_bridge/serializers/shared_assistant_guidance.rb +2 -16
  70. data/lib/rails_ai_bridge/server.rb +23 -1
  71. data/lib/rails_ai_bridge/services/context_generation_service.rb +12 -5
  72. data/lib/rails_ai_bridge/tools/get_model_details.rb +3 -3
  73. data/lib/rails_ai_bridge/tools/model_details/full_formatter.rb +2 -2
  74. data/lib/rails_ai_bridge/tools/model_details/standard_formatter.rb +2 -2
  75. data/lib/rails_ai_bridge/tools/model_details/summary_formatter.rb +2 -2
  76. data/lib/rails_ai_bridge/tools/query/guard.rb +46 -0
  77. data/lib/rails_ai_bridge/tools/query/payload_formatter.rb +51 -0
  78. data/lib/rails_ai_bridge/tools/query.rb +182 -0
  79. data/lib/rails_ai_bridge/tools/read_logs/log_locator.rb +101 -0
  80. data/lib/rails_ai_bridge/tools/read_logs.rb +210 -0
  81. data/lib/rails_ai_bridge/version.rb +1 -1
  82. data/lib/rails_ai_bridge/view_file_analyzer.rb +1 -1
  83. data/lib/rails_ai_bridge.rb +2 -1
  84. data/rails-ai-bridge.gemspec +1 -1
  85. data/server.json +2 -2
  86. metadata +22 -9
  87. data/docs/02-port-registry-resolution.md +0 -152
  88. data/docs/registry-resolution.md +0 -275
  89. data/lib/rails_ai_bridge/model_semantic_classifier.rb +0 -168
  90. data/lib/rails_ai_bridge/path_resolver.rb +0 -311
  91. data/test_table.md +0 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 74d2175a281a2d2b0e3efb53e3970ffbf8658724241a9fcbf4a241e8a22375c8
4
- data.tar.gz: e674ed5c5bf81c08d1b0c918c414ddafb518b48ac3f4843f6d25c8a173fdecfc
3
+ metadata.gz: d3503fc11c0a368a580e78f2309387f7b9d69ce11477be8ef339f4956841a383
4
+ data.tar.gz: f0db3c3efba79000a95f6f0191d031132329d7aeb788cdc0179cb218efb70a8e
5
5
  SHA512:
6
- metadata.gz: 9e5cc4ff68c3d003b228231504169c4dfab1b0baf2b8bbf4d057a97fd3a3d14ea8e689bec29056bb57a5c140f43017f3a07737c08469ecfe7b17d34d6c002641
7
- data.tar.gz: d0b72a96954862bf6bde9b9e64945481ac4352a74f0403edebd3d0b1600445152f0d6b061fa177c9912276b571883da404347ad25d0f20e114b1a8d6bdf268ed
6
+ metadata.gz: '048e2092ab40e4d6f5ba63651adfd8d5501f28d75d1ce3c5f5c28d669834c62235471ce9cf3247ecb570be460a7f8113cb74ba80277ba4488b5475ea96657173'
7
+ data.tar.gz: 28dd1a9ac48e6367700aac135e8043d2f31580d4e4290ed39a8220f966dc84d8ac83a8f1da53f0a6619c993358ff867abca352f9ce213ac982c7b5a4d0aac85e
data/.reek.yml CHANGED
@@ -99,8 +99,8 @@ detectors:
99
99
  - RailsAiBridge::FreshnessHeader#extract_metadata_for
100
100
  - RailsAiBridge::Introspectors::MiddlewareIntrospector#categorize_middleware
101
101
  - RailsAiBridge::Mcp::HttpRateLimiter#initialize
102
- - RailsAiBridge::ModelSemanticClassifier#classify_with_payload
103
- - RailsAiBridge::ModelSemanticClassifier#classify_without_payload
102
+ - RailsAiBridge::Introspectors::ModelSemanticClassifier#classify_with_payload
103
+ - RailsAiBridge::Introspectors::ModelSemanticClassifier#classify_without_payload
104
104
  - RailsAiBridge::Registry::ContextAggregator#aggregate_status
105
105
  - RailsAiBridge::Registry::ContextProviderClient#find_tool
106
106
  - RailsAiBridge::Registry::PackResolver#initialize
@@ -197,7 +197,7 @@ detectors:
197
197
  - RailsAiBridge::Mcp::CacheRateLimiter#increment
198
198
  - RailsAiBridge::Mcp::HttpRateLimiter#allow?
199
199
  - RailsAiBridge::Mcp::HttpStructuredLog#target_logger
200
- - RailsAiBridge::ModelSemanticClassifier#call
200
+ - RailsAiBridge::Introspectors::ModelSemanticClassifier#call
201
201
  - RailsAiBridge::Registry::ContextAggregator#fetch_all
202
202
  - RailsAiBridge::Registry::ContextAggregator#fetch_provider
203
203
  - RailsAiBridge::Registry::ContextAggregator#fetch_tool
@@ -390,7 +390,7 @@ detectors:
390
390
  - RailsAiBridge::Introspectors::TurboIntrospector#extract_model_broadcasts
391
391
  - RailsAiBridge::Introspectors::ViewIntrospector#detect_template_engines
392
392
  - RailsAiBridge::Mcp::CacheRateLimiter#fallback_increment
393
- - RailsAiBridge::PathResolver#path_inside_real_root?
393
+ - RailsAiBridge::Introspectors::PathResolver#path_inside_real_root?
394
394
  - RailsAiBridge::Registry::Lockfile#to_json
395
395
  - RailsAiBridge::Registry::PackResolver#gather_active_packs
396
396
  - RailsAiBridge::Registry::PackResolver#trace_dependency_cycle
@@ -476,7 +476,7 @@ detectors:
476
476
  exclude:
477
477
  - RailsAiBridge::Generators::InstallGenerator
478
478
  - RailsAiBridge::Fingerprinter::CachedSnapshot
479
- - RailsAiBridge::PathResolver
479
+ - RailsAiBridge::Introspectors::PathResolver
480
480
  - RailsAiBridge::RubydexAdapter
481
481
  - RailsAiBridge::Serializers::ContextFileSerializer::ManagedRegionLayout
482
482
  - RailsAiBridge::Serializers::Providers::ClaudeSerializer
@@ -592,8 +592,8 @@ detectors:
592
592
  - RailsAiBridge::Introspectors::SeedsIntrospector#detect_seeded_models
593
593
  - RailsAiBridge::Introspectors::TestIntrospector#detect_test_helpers
594
594
  - RailsAiBridge::Introspectors::TurboIntrospector#extract_turbo_frames
595
- - RailsAiBridge::ModelSemanticClassifier#self.through_join_model_names
596
- - RailsAiBridge::PathResolver#glob_for
595
+ - RailsAiBridge::Introspectors::ModelSemanticClassifier#self.through_join_model_names
596
+ - RailsAiBridge::Introspectors::PathResolver#glob_for
597
597
  - RailsAiBridge::Registry::Resolver#build_deprecated_index
598
598
  - RailsAiBridge::Registry::Resolver#build_summary_map
599
599
  - RailsAiBridge::Registry::Resolver#validate_dependencies
@@ -644,7 +644,7 @@ detectors:
644
644
  - RailsAiBridge::Mcp::Auth::Strategies::Jwt#initialize
645
645
  - RailsAiBridge::Mcp::Authenticator#call
646
646
  - RailsAiBridge::Mcp::HttpStructuredLog#emit
647
- - RailsAiBridge::PathResolver#max_files_per_path
647
+ - RailsAiBridge::Introspectors::PathResolver#max_files_per_path
648
648
  - RailsAiBridge::Registry::Lockfile#load
649
649
  - RailsAiBridge::Registry::RakePresenter#initialize
650
650
  - RailsAiBridge::Registry::SkillSourceResolver#pull_stale?
@@ -729,7 +729,7 @@ detectors:
729
729
  - RailsAiBridge::Introspectors::ModelIntrospector::SourceMacroExtractor
730
730
  - RailsAiBridge::Introspectors::ModelIntrospector
731
731
  - RailsAiBridge::Introspectors::Schema::StaticStructureSqlParser
732
- - RailsAiBridge::PathResolver
732
+ - RailsAiBridge::Introspectors::PathResolver
733
733
  - RailsAiBridge::RubydexAdapter::IncrementalIndexer
734
734
  - RailsAiBridge::RubydexAdapter
735
735
  - RailsAiBridge::Serializers::Providers::BaseProviderSerializer
@@ -869,10 +869,10 @@ detectors:
869
869
  - RailsAiBridge::Mcp::Authenticator#resolve_strategy
870
870
  - RailsAiBridge::Mcp::HttpRateLimiter#allow?
871
871
  - RailsAiBridge::Mcp::HttpStructuredLog#emit
872
- - RailsAiBridge::ModelSemanticClassifier#call
873
- - RailsAiBridge::ModelSemanticClassifier#metadata_column_names
874
- - RailsAiBridge::ModelSemanticClassifier#self.through_join_model_names
875
- - RailsAiBridge::PathResolver#glob_for
872
+ - RailsAiBridge::Introspectors::ModelSemanticClassifier#call
873
+ - RailsAiBridge::Introspectors::ModelSemanticClassifier#metadata_column_names
874
+ - RailsAiBridge::Introspectors::ModelSemanticClassifier#self.through_join_model_names
875
+ - RailsAiBridge::Introspectors::PathResolver#glob_for
876
876
  - RailsAiBridge::Registry::FrontmatterParser#self.extract_frontmatter_lines
877
877
  - RailsAiBridge::Registry::Lockfile#load
878
878
  - RailsAiBridge::Registry::PackResolver#expand_transitive_dependencies
@@ -963,6 +963,7 @@ detectors:
963
963
  - RailsAiBridge::Serializers::Providers::CursorRulesSerializer#render_models_rule
964
964
  - RailsAiBridge::Serializers::Providers::DevinRulesSerializer#call
965
965
  - RailsAiBridge::Serializers::Providers::DevinSerializer#render
966
+ - RailsAiBridge::Serializers::RuleFileWriter#call
966
967
  - RailsAiBridge::Serializers::SharedAssistantGuidance#claude_full_footer_lines
967
968
  - RailsAiBridge::Serializers::SharedAssistantGuidance#compact_engineering_rules_footer_lines
968
969
  - RailsAiBridge::Serializers::SharedAssistantGuidance#cursor_engineering_mdc_body_lines
@@ -1033,7 +1034,7 @@ detectors:
1033
1034
  - RailsAiBridge::Tools::ListRegistry::RegistryCatalogFormatter#format_catalog
1034
1035
  - RailsAiBridge::Tools::ListRegistry::RegistryCatalogFormatter#format_packs
1035
1036
  - RailsAiBridge::Tools::ModelDetails::FullFormatter#call
1036
- - RailsAiBridge::Tools::ModelDetails::NonArModelsAppendix#append_markdown
1037
+ - RailsAiBridge::Serializers::ModelDetails::NonArModelsAppendix#append_markdown
1037
1038
  - RailsAiBridge::Tools::ModelDetails::SingleModelFormatter#append_source_macros
1038
1039
  - RailsAiBridge::Tools::ModelDetails::SingleModelFormatter#call
1039
1040
  - RailsAiBridge::Tools::ModelDetails::StandardFormatter#call
@@ -1094,8 +1095,8 @@ detectors:
1094
1095
  - RailsAiBridge::Mcp::HttpRateLimiter#allow?
1095
1096
  - RailsAiBridge::Mcp::HttpRateLimiter#initialize
1096
1097
  - RailsAiBridge::Mcp::HttpStructuredLog#emit
1097
- - RailsAiBridge::ModelSemanticClassifier#call
1098
- - RailsAiBridge::ModelSemanticClassifier#metadata_column_names
1098
+ - RailsAiBridge::Introspectors::ModelSemanticClassifier#call
1099
+ - RailsAiBridge::Introspectors::ModelSemanticClassifier#metadata_column_names
1099
1100
  - RailsAiBridge::Registry::PackResolver#gather_active_packs
1100
1101
  - RailsAiBridge::Registry::PackResolver#warn_missing_dependencies
1101
1102
  - RailsAiBridge::RubydexAdapter#codebase_stats
@@ -1244,9 +1245,9 @@ detectors:
1244
1245
  - RailsAiBridge::Introspectors::StimulusIntrospector#extract_values
1245
1246
  - RailsAiBridge::Mcp::Auth::BaseStrategy#extract_bearer
1246
1247
  - RailsAiBridge::Mcp::Auth::Strategies::BearerToken#secure_compare
1247
- - RailsAiBridge::ModelSemanticClassifier#metadata_column_names
1248
- - RailsAiBridge::ModelSemanticClassifier#safe_column_names
1249
- - RailsAiBridge::ModelSemanticClassifier#tier
1248
+ - RailsAiBridge::Introspectors::ModelSemanticClassifier#metadata_column_names
1249
+ - RailsAiBridge::Introspectors::ModelSemanticClassifier#safe_column_names
1250
+ - RailsAiBridge::Introspectors::ModelSemanticClassifier#tier
1250
1251
  - RailsAiBridge::Registry::PackResolver#auto_load_dependencies?
1251
1252
  - RailsAiBridge::Registry::PackResolver#compute_priority
1252
1253
  - RailsAiBridge::Registry::PackResolver#default_lockfile
data/.rubocop.yml CHANGED
@@ -11,6 +11,13 @@ AllCops:
11
11
  - "spec/internal/**/*"
12
12
  - "gemfiles/**/*"
13
13
  - ".mutant.yml"
14
+ # Generated/rails-boilerplate demo files (rails new, db/schema.rb, bin/,
15
+ # config boot files) — rails generators emit double-quoted strings and
16
+ # long blocks by design; keeping them excluded means `rubocop -A` never
17
+ # rewrites files the demo intentionally shows as generated output.
18
+ - "examples/demo_app/bin/**/*"
19
+ - "examples/demo_app/config/**/*"
20
+ - "examples/demo_app/db/**/*"
14
21
  Naming/FileName:
15
22
  Exclude:
16
23
  - "lib/rails-ai-bridge.rb"
data/AGENTS.md CHANGED
@@ -8,8 +8,8 @@ committed context files. It does not write to the host database.
8
8
  - `lib/rails_ai_bridge.rb` — Main entry point, public API (Zeitwerk autoloaded)
9
9
  - `lib/rails_ai_bridge/configuration.rb` — User-facing config with presets (:standard, :full)
10
10
  - `lib/rails_ai_bridge/introspector.rb` — Orchestrates sub-introspectors
11
- - `lib/rails_ai_bridge/introspectors/` — Built-in introspector classes; `:standard` preset runs **9**, `:full` runs **27** (see `Configuration::PRESETS`). Registry: `Introspector::BUILTIN_INTROSPECTORS` (includes opt-in symbols such as `database_stats`, `non_ar_models` not listed in those presets).
12
- - `lib/rails_ai_bridge/tools/` — 20 built-in MCP tools using the official mcp SDK (hosts can add more via `additional_tools`)
11
+ - `lib/rails_ai_bridge/introspectors/` — Built-in introspector classes; `:standard` preset runs **9**, `:full` runs **27** (see `Configuration::PRESETS`). Registry: `Introspector::BUILTIN_INTROSPECTORS` (`:full` already includes `non_ar_models`; opt-in-only symbols not in any preset: `database_stats`, `semantic`).
12
+ - `lib/rails_ai_bridge/tools/` — 22 built-in MCP tools using the official mcp SDK (hosts can add more via `additional_tools`)
13
13
  - `lib/rails_ai_bridge/serializers/` — Output formatters (claude, claude_rules, codex, cursor_rules, devin, devin_rules, copilot, copilot_instructions, gemini, rules, markdown, JSON)
14
14
  - `lib/rails_ai_bridge/resources.rb` — MCP resources (static data AI clients read directly)
15
15
  - `lib/rails_ai_bridge/server.rb` — MCP server configuration (stdio + HTTP transports)
@@ -32,7 +32,7 @@ committed context files. It does not write to the host database.
32
32
  6. **Diff-aware** — context regeneration skips unchanged files
33
33
  7. **Per-assistant serializers** — each AI tool gets tailored output format
34
34
  8. **Zeitwerk autoloading** — files loaded on-demand, not all upfront
35
- 9. **Introspector presets** — `:standard` (9 core) default, `:full` (27 introspectors; optional extras such as `database_stats`, `non_ar_models`) for power users
35
+ 9. **Introspector presets** — `:standard` (9 core) default, `:full` (27 introspectors, includes `non_ar_models`) with opt-in extras such as `database_stats` and `semantic` for power users
36
36
  10. **MCP auto-discovery** — `.mcp.json` generated by install generator
37
37
  11. **Outbound context providers (v5)** — `rails_get_provider_context` fetches from declared external MCP services. Disabled by default, exact host allowlist, read-only tool enforcement, `ToolResultCache::NON_CACHEABLE` exclusion. Separate from local `rails_get_context`.
38
38
  12. **Compact by default** — context files ≤150 lines, MCP tools use `detail` parameter (summary/standard/full)
@@ -50,7 +50,7 @@ Uses combustion gem for testing Rails engine behavior in isolation.
50
50
  ## Conventions
51
51
 
52
52
  - Ruby 3.2+ features OK (pattern matching, etc.)
53
- - Follow rubocop-rails-omakase style
53
+ - Follow RuboCop with the project's custom limits (see `.rubocop.yml` — plugins performance/rails/rspec; method length, ABC size and class length limits are deliberately more permissive than the omakase defaults)
54
54
  - Every introspector returns a Hash, never raises (wraps errors in `{ error: msg }`)
55
55
  - MCP tools return `MCP::Tool::Response` objects per SDK convention
56
56
  - All tools prefixed with `rails_` per MCP naming best practices
data/Archspec.rb CHANGED
@@ -2,10 +2,10 @@
2
2
 
3
3
  # ArchSpec architecture specification for rails-ai-bridge.
4
4
  #
5
- # Defines eight components and the dependency directions the gem is expected to
6
- # follow. Lower layers (config, introspectors, registry, rubydex, serializers)
7
- # must not reach up into transport or tooling layers. Cross-component cycles are
8
- # forbidden.
5
+ # Defines ten components and the dependency directions the gem is expected to
6
+ # follow. Lower layers (core, config, introspectors, registry, rubydex,
7
+ # serializers) must not reach up into transport or tooling layers.
8
+ # Cross-component cycles are forbidden.
9
9
  #
10
10
  # Run locally with:
11
11
  #
@@ -15,6 +15,17 @@
15
15
 
16
16
  source 'lib/rails_ai_bridge/**/*.rb'
17
17
 
18
+ # Core primitives — dependency-free value types and pure helpers (Service,
19
+ # Service::Result, ExclusionHelper, DatabaseSize) that every layer may use.
20
+ # Extracted per the #250 diagnosis "durable alternative".
21
+ component :core, in: %w[
22
+ lib/rails_ai_bridge/service.rb
23
+ lib/rails_ai_bridge/service/**/*.rb
24
+ lib/rails_ai_bridge/exclusion_helper.rb
25
+ lib/rails_ai_bridge/database_size.rb
26
+ lib/rails_ai_bridge/service_errors.rb
27
+ ]
28
+
18
29
  # Configuration layer — user-facing settings and presets.
19
30
  # Must stay free of upper-layer dependencies so it can be loaded in isolation.
20
31
  component :config, in: %w[
@@ -31,27 +42,15 @@ component :introspectors, in: %w[
31
42
  ]
32
43
 
33
44
  # Runtime context — supporting infrastructure shared by tools and serializers
34
- # (context providers, fingerprinting, doctor checks, watchers, services, etc.).
45
+ # (context providers, fingerprinting, watcher, tasks, errors).
35
46
  component :runtime_context, in: %w[
36
47
  lib/rails_ai_bridge/assistant_formats_preference.rb
37
48
  lib/rails_ai_bridge/cache_warmer.rb
38
49
  lib/rails_ai_bridge/context_provider.rb
39
- lib/rails_ai_bridge/database_size.rb
40
- lib/rails_ai_bridge/doctor.rb
41
- lib/rails_ai_bridge/doctor/**/*.rb
42
- lib/rails_ai_bridge/engine.rb
43
- lib/rails_ai_bridge/exclusion_helper.rb
44
50
  lib/rails_ai_bridge/fingerprinter.rb
45
51
  lib/rails_ai_bridge/fingerprinter/**/*.rb
46
52
  lib/rails_ai_bridge/freshness_header.rb
47
53
  lib/rails_ai_bridge/instrumentation.rb
48
- lib/rails_ai_bridge/model_semantic_classifier.rb
49
- lib/rails_ai_bridge/path_resolver.rb
50
- lib/rails_ai_bridge/resources.rb
51
- lib/rails_ai_bridge/service.rb
52
- lib/rails_ai_bridge/service/**/*.rb
53
- lib/rails_ai_bridge/service_errors.rb
54
- lib/rails_ai_bridge/services/**/*.rb
55
54
  lib/rails_ai_bridge/tasks/**/*.rb
56
55
  lib/rails_ai_bridge/tool_result_cache.rb
57
56
  lib/rails_ai_bridge/view_file_analyzer.rb
@@ -59,7 +58,20 @@ component :runtime_context, in: %w[
59
58
  lib/rails_ai_bridge/watcher/**/*.rb
60
59
  ]
61
60
 
62
- # MCP tools — the 19 built-in tools exposed over the MCP protocol.
61
+ # Host integration — Rails engine wiring, diagnostics, MCP resources that
62
+ # AI clients read directly, plus service orchestrators that sit above the
63
+ # formatting and transport layers. Entry-point glue: it may use every other
64
+ # component (engine wires middleware, doctor checkers reach downward, service
65
+ # orchestrators call serializers); nothing may depend on it. The gem entry
66
+ # point (lib/rails_ai_bridge.rb) sits outside all components.
67
+ component :host_integration, in: %w[
68
+ lib/rails_ai_bridge/engine.rb
69
+ lib/rails_ai_bridge/doctor.rb
70
+ lib/rails_ai_bridge/doctor/**/*.rb
71
+ lib/rails_ai_bridge/services/**/*.rb
72
+ ]
73
+
74
+ # MCP tools — the 20 built-in tools exposed over the MCP protocol.
63
75
  component :tools, in: 'lib/rails_ai_bridge/tools/**/*.rb'
64
76
 
65
77
  # Output formatters — serialize introspection payloads to per-assistant files.
@@ -73,12 +85,15 @@ component :registry, in: %w[
73
85
  lib/rails_ai_bridge/registry/**/*.rb
74
86
  ]
75
87
 
76
- # MCP transport — the server, Rack middleware, HTTP app, and auth/rate-limiting.
88
+ # MCP transport — the server, Rack middleware, HTTP app, auth/rate-limiting, and
89
+ # the MCP resources registry (resources are part of the MCP protocol surface;
90
+ # Server wires Resources at construction).
77
91
  component :mcp_transport, in: %w[
78
92
  lib/rails_ai_bridge/server.rb
79
93
  lib/rails_ai_bridge/middleware.rb
80
94
  lib/rails_ai_bridge/http_transport_app.rb
81
95
  lib/rails_ai_bridge/mcp/**/*.rb
96
+ lib/rails_ai_bridge/resources.rb
82
97
  ]
83
98
 
84
99
  # Rubydex integration — optional semantic code analysis adapter.
@@ -90,22 +105,33 @@ component :rubydex, in: %w[
90
105
 
91
106
  # --- Dependency direction rules ---
92
107
 
93
- # Config is the lowest layer; it must not reach up into any upper layer.
94
- config.cannot_use :tools, :serializers, :mcp_transport, :introspectors
108
+ # Core is the bottom of the stack; every layer may use it, it uses nothing.
109
+ core.cannot_use :config, :introspectors, :runtime_context, :tools, :serializers,
110
+ :registry, :mcp_transport, :rubydex, :host_integration
111
+
112
+ # Config sits directly above core; it must not reach up into any upper layer.
113
+ config.cannot_use :runtime_context, :tools, :serializers, :mcp_transport, :introspectors,
114
+ :host_integration
115
+
116
+ # Runtime context, tools, and transport sit below host integration wiring;
117
+ # they must not reach up into it.
118
+ runtime_context.cannot_use :host_integration
119
+ tools.cannot_use :host_integration
120
+ mcp_transport.cannot_use :host_integration
95
121
 
96
122
  # Registry and rubydex are leaf adapters; they must not depend on the
97
123
  # tooling, formatting, or transport layers.
98
- registry.cannot_use :tools, :serializers, :mcp_transport
99
- rubydex.cannot_use :tools, :serializers, :mcp_transport
124
+ registry.cannot_use :tools, :serializers, :mcp_transport, :host_integration
125
+ rubydex.cannot_use :tools, :serializers, :mcp_transport, :host_integration
100
126
 
101
127
  # Introspectors produce plain data and must not depend on tools, formatters,
102
128
  # or transport.
103
- introspectors.cannot_use :tools, :serializers, :mcp_transport
129
+ introspectors.cannot_use :tools, :serializers, :mcp_transport, :host_integration
104
130
 
105
131
  # Serializers format data handed to them; they must not invoke introspection
106
132
  # or reach into the transport layer.
107
- serializers.cannot_use :introspectors, :mcp_transport
133
+ serializers.cannot_use :introspectors, :mcp_transport, :host_integration
108
134
 
109
135
  # Cross-component cycles are forbidden across all defined components.
110
- no_cycles among: %i[config introspectors runtime_context tools serializers
111
- registry mcp_transport rubydex]
136
+ no_cycles among: %i[core config introspectors runtime_context tools serializers
137
+ registry mcp_transport rubydex host_integration]
data/CHANGELOG.md CHANGED
@@ -5,7 +5,140 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## [Unreleased]
8
+ ## [5.2.0] - 2026-09-14
9
+
10
+ ### Added
11
+
12
+ - `rails ai:doctor` warns when HTTP MCP is auto-mounted (`config.auto_mount`)
13
+ but `config.mcp.http_log_json` is still false, so 401/403/429/handled
14
+ outcomes from `HttpTransportApp` would not emit structured JSON lines.
15
+ - **Anti-hallucination rules in every generated context file (#252/#253/#254).** All
16
+ generated outputs now carry a shared verify-before-write block (heading
17
+ `## Anti-hallucination rules`, rendered by the single
18
+ `RailsAiBridge::Serializers::AntiHallucinationRules` collaborator and controlled by
19
+ `config.output.anti_hallucination_rules`, default `true`): the 7 main context files
20
+ (`CLAUDE.md`, `AGENTS.md`, `.cursorrules`, `.devinrules`, `.github/copilot-instructions.md`,
21
+ `GEMINI.md`, and `.ai-context.json`, which gains an `anti_hallucination_rules` array
22
+ key) plus the 5 split-rules serializers (`.claude/rules/`, `.cursor/rules/`,
23
+ `.devin/rules/`, `.codex/`, `.github/instructions/`). The block sits near the top —
24
+ after the freshness header / document intro — so compact-mode trimming and Devin's
25
+ character cap cannot drop it, and it is always inside the managed region when
26
+ `config.output.managed_region` is enabled.
27
+ - **`rails_query` MCP tool** — runs a single read-only SELECT statement on the app's established ActiveRecord connection. SELECT-only allowlist (CTEs rejected in v1), single-statement enforcement, hard 100-row cap, 5-second statement timeout, and credential-like column redaction via `MessageSanitizer`. Errors follow the `{ error }` contract.
28
+ - **`rails_read_logs` MCP tool** — returns a redacted tail of a log file under `Rails.root/log`. Traversal-safe path allowlist (expanded-path prefix check), 400-line and 2000-byte-per-line caps, `summary`/`standard`/`full` detail levels, and `MessageSanitizer` redaction on every line.
29
+ - Built-in MCP tools: 20 → 22. Both data-access tools are documented in `docs/mcp-security.md`.
30
+ - MCP Registry submission readiness: `server.json` passes
31
+ `mcp-publisher validate` (verification steps and captured output in
32
+ `docs/mcp-registry-submission.md`), plus that guide's exact maintainer
33
+ publish steps (fixes #261).
34
+ - Hosted YARD API documentation: a `docs` workflow publishes generated
35
+ YARD docs to GitHub Pages on every `v*` tag push (same checkout/setup-ruby
36
+ pinning style as the existing workflows, reuses the `docs:yard` coverage
37
+ gate); README gains an "API Documentation" link (fixes #262).
38
+ - Positioning page `docs/COMPARISON.md` comparing rails-ai-bridge with
39
+ rails-ai-context, rails-mcp-server, woods, and rails-hyperdrive
40
+ (feature table, download counts, when-to-choose-which), plus a short
41
+ "How it compares" section in the README (fixes #263).
42
+ - Runnable example app under `examples/demo_app` — a minimal Rails 8 app
43
+ (3 models, 3 controllers, 3 tables) that boots without a database and
44
+ demonstrates install, context generation for all 7 assistant targets, and
45
+ MCP tool calls against the static schema parser. `docs/EXAMPLES.md` walks
46
+ through it with real captured output (fixes #260).
47
+
48
+ ### Changed
49
+
50
+ - **`rails_query` and `rails_read_logs` are now opt-in and disabled by default**
51
+ via `config.enable_data_tools` (default `false`). Both tools read live
52
+ application data — `rails_query` runs on the app's database connection and can
53
+ read tables excluded from MCP introspection, and `rails_read_logs` returns raw
54
+ log contents — so an upgrade no longer registers them silently. To keep using
55
+ them after upgrading, set `config.enable_data_tools = true` in the
56
+ `rails_ai_bridge` initializer. See `docs/mcp-security.md` for the residual
57
+ risks (best-effort keyword guard on non-PostgreSQL adapters, best-effort
58
+ redaction that column aliases can bypass).
59
+ - `rails_query` redaction: values under credential-like columns (including
60
+ `password_digest`, `encrypted_password`, `secret_access_key`) are now replaced
61
+ with `[redacted]` unconditionally instead of only when the value itself looks
62
+ secret-like. Non-credential author-metadata columns (`author`, `author_id`)
63
+ keep their values; `authorization`-style columns are redacted.
64
+ - `rails_query` keyword guard now also rejects MySQL `LOCK IN SHARE MODE`
65
+ (alongside the existing `FOR UPDATE`/`FOR SHARE` and `SELECT ... INTO`
66
+ rejections). On PostgreSQL, execution runs inside `SET TRANSACTION READ ONLY`
67
+ with `SET LOCAL statement_timeout`; on other adapters the Ruby
68
+ `Timeout.timeout` fallback remains a documented residual risk.
69
+ - `rails_read_logs` streams the log file in a single bounded pass instead of
70
+ materializing the whole file into memory (tail buffer stays capped at
71
+ `MAX_LINES`), scrubs invalid UTF-8 at the per-line byte cap (replacement
72
+ characters instead of `invalid byte sequence in UTF-8` errors), and returns
73
+ sanitized error responses without writing to the application log. The
74
+ internal-only `ReadLogs.respond`, `error_response`, and `execution_failure`
75
+ helpers are private class methods.
76
+ - `rails_query` now requires the statement to start with `SELECT` (leading
77
+ whitespace only). `EXPLAIN`, `SHOW`, `VALUES`, comment-prefixed SQL, and
78
+ other non-SELECT verbs are rejected. On PostgreSQL the tool uses
79
+ `SET LOCAL statement_timeout` plus `SET TRANSACTION READ ONLY` instead of
80
+ Ruby `Timeout.timeout`. Other adapters keep the Ruby timeout.
81
+ - Compact Claude and Gemini output previously placed the anti-hallucination block in the
82
+ footer under the heading `## Anti-hallucination`; it now uses the consistent named
83
+ section (`## Anti-hallucination rules`) at the top of the file. The rule lines are
84
+ unchanged.
85
+ - **Architecture: broke the 6-component dependency cycle (#250).** Extracted a
86
+ dependency-free `:core` component (`Service`, `Service::Result`,
87
+ `ServiceErrors`, `ExclusionHelper`, `DatabaseSize`); introduced a
88
+ `host_integration` component for `engine.rb`, `doctor/**`, and the service
89
+ orchestrators (`services/**`); grouped `resources.rb` under `mcp_transport`
90
+ (resources are part of the MCP protocol surface that `Server` wires at
91
+ construction). Moved `NonArModelsAppendix` to
92
+ `RailsAiBridge::Serializers::ModelDetails::NonArModelsAppendix`,
93
+ `PathResolver` and `ModelSemanticClassifier` to
94
+ `RailsAiBridge::Introspectors::` (`PathResolver` is now
95
+ `RailsAiBridge::Introspectors::PathResolver`), and `ModelSemanticClassifier`
96
+ to `RailsAiBridge::Introspectors::ModelSemanticClassifier`. Removed the
97
+ `RailsAiBridge::Service` superclass from
98
+ `RubydexAdapter::IncrementalIndexer` (duck-types the Result contract) and
99
+ gave `ContextFileSerializer` a caller-supplied required `fingerprint:` kwarg
100
+ (`ContextGenerationService` computes and passes it; custom serializer
101
+ classes must now accept `fingerprint:`; the remaining write options
102
+ (`format:`, `split_rules:`, `on_conflict:`, `managed_region:`) are accepted
103
+ as a `**write_options` group). `ContextGenerationService.call` no longer
104
+ takes a `fingerprint:` override — the fingerprint is always computed at
105
+ call time; inject one via `.new`. Unknown serializer write options now
106
+ raise `ArgumentError` (matching the previous explicit-keyword behavior).
107
+ The archspec todo baseline and all
108
+ 36 inline `archspec:disable` suppressions are gone;
109
+ `bundle exec archspec check` reports zero violations.
110
+ - **Docs cleanup (#246).** README quick start no longer says the gem is
111
+ "once published" (it ships on RubyGems as 5.1.0). The three registry/port
112
+ planning docs are consolidated into the canonical
113
+ `docs/port-registry-resolution.md` (as-built record + user-facing
114
+ "Registry Resolution Reference"); `docs/02-port-registry-resolution.md` and
115
+ `docs/registry-resolution.md` are deleted. Completed planning docs
116
+ `docs/gem-general-improvements.md` and `docs/review-workflow-report.md`
117
+ moved to `docs/archive/`. Junk file `test_table.md` removed.
118
+ - **Docs truth (#247).** AGENTS.md, CLAUDE.md, and CONTRIBUTING.md no longer
119
+ claim the project follows the `rubocop-rails-omakase` style — `.rubocop.yml`
120
+ uses its own custom limits (performance/rails/rspec plugins; method length,
121
+ ABC size and class length limits deliberately more permissive). AGENTS.md
122
+ and CLAUDE.md no longer describe `non_ar_models` as opt-in-only — it ships
123
+ in the `:full` preset; only `database_stats` and `semantic` are opt-in-only
124
+ (fixed the same claim in the `Introspector::BUILTIN_INTROSPECTORS` YARD
125
+ comment). `doc_parity_spec.rb` gains guard examples for both claims.
126
+
127
+ ### Fixed
128
+
129
+ - `DatabaseSize.bucket` and `DatabaseSize.bucket_for_table` no longer classify
130
+ invalid row counts as the `hot` bucket. Negative counts, including negative
131
+ fractional counts (e.g. stale or unanalyzed PostgreSQL statistics sentinels),
132
+ and non-numeric values now return `nil` instead of being bucketed as `hot`
133
+ (fallback) or `small` (`to_i` truncation/coercion). Callers already treat
134
+ `nil` as "no size data".
135
+ - `server.json` no longer drifts from the released gem: its `version` now
136
+ matches `RailsAiBridge::VERSION` (was stale at `3.0.0`) and the description
137
+ reports the real 20 read-only tools (was 13). `CONTRIBUTING.md`, `GEMINI.md`,
138
+ and `docs/GUIDE.md` tool counts corrected from 19 to 20; `GEMINI.md` also
139
+ documents the `:full` preset as 27 introspectors (was a corrupted 26/27
140
+ mix). Parity and release-consistency specs now guard the `server.json`
141
+ version and tool counts (fixes #245).
9
142
 
10
143
  ## [5.1.0] - 2026-09-11
11
144
 
data/CLAUDE.md CHANGED
@@ -10,9 +10,10 @@ committed context files. It does not write to the host database.
10
10
  - `lib/rails_ai_bridge/introspector.rb` — Orchestrates sub-introspectors
11
11
  - `lib/rails_ai_bridge/introspectors/` — Built-in introspector classes; `:standard` preset
12
12
  runs **9**, `:full` runs **27** (see `Configuration::PRESETS`). Registry:
13
- `Introspector::BUILTIN_INTROSPECTORS` (includes opt-in symbols such as
14
- `database_stats`, `non_ar_models` not listed in those presets).
15
- - `lib/rails_ai_bridge/tools/` — 20 built-in MCP tools using the official mcp SDK
13
+ `Introspector::BUILTIN_INTROSPECTORS` (`:full` already includes
14
+ `non_ar_models`; opt-in-only symbols not in any preset: `database_stats`,
15
+ `semantic`).
16
+ - `lib/rails_ai_bridge/tools/` — 22 built-in MCP tools using the official mcp SDK
16
17
  (hosts can add more via `additional_tools`)
17
18
  - `lib/rails_ai_bridge/serializers/` — Output formatters (claude, claude_rules,
18
19
  codex, cursor_rules, devin, devin_rules, copilot, copilot_instructions,
@@ -38,7 +39,7 @@ committed context files. It does not write to the host database.
38
39
  6. **Diff-aware** — context regeneration skips unchanged files
39
40
  7. **Per-assistant serializers** — each AI tool gets tailored output format
40
41
  8. **Zeitwerk autoloading** — files loaded on-demand, not all upfront
41
- 9. **Introspector presets** — `:standard` (9 core) default, `:full` (27 introspectors; optional extras such as `database_stats`, `non_ar_models`) for power users
42
+ 9. **Introspector presets** — `:standard` (9 core) default, `:full` (27 introspectors, includes `non_ar_models`) with opt-in extras such as `database_stats` and `semantic` for power users
42
43
  10. **MCP auto-discovery** — `.mcp.json` generated by install generator
43
44
  11. **Outbound context providers (v5)** — `rails_get_provider_context` fetches from declared external MCP services. Disabled by default, exact host allowlist, read-only tool enforcement, `ToolResultCache::NON_CACHEABLE` exclusion. Separate from local `rails_get_context`.
44
45
  12. **Compact by default** — context files ≤150 lines, MCP tools use `detail` parameter (summary/standard/full)
@@ -56,7 +57,7 @@ Uses combustion gem for testing Rails engine behavior in isolation.
56
57
  ## Conventions
57
58
 
58
59
  - Ruby 3.2+ features OK (pattern matching, etc.)
59
- - Follow rubocop-rails-omakase style
60
+ - Follow RuboCop with the project's custom limits (see `.rubocop.yml` — plugins performance/rails/rspec; method length, ABC size and class length limits are deliberately more permissive than the omakase defaults)
60
61
  - Every introspector returns a Hash, never raises (wraps errors in `{ error: msg }`)
61
62
  - MCP tools return `MCP::Tool::Response` objects per SDK convention
62
63
  - All tools prefixed with `rails_` per MCP naming best practices
data/CONTRIBUTING.md CHANGED
@@ -19,7 +19,7 @@ The test suite uses [Combustion](https://github.com/pat/combustion) to boot a mi
19
19
  ```
20
20
  lib/rails_ai_bridge/
21
21
  ├── introspectors/ # Built-in introspectors (schema, models, non_ar_models, routes, …)
22
- ├── tools/ # 19 built-in MCP tools (detail levels, pagination, extensible)
22
+ ├── tools/ # 22 built-in MCP tools (detail levels, pagination, extensible)
23
23
  ├── rubydex_adapter.rb # Rubydex API wrapper (singleton + query interface + stats)
24
24
  ├── rubydex_adapter/ # Extracted collaborators (one concern each)
25
25
  │ ├── serializer.rb # Hash serialization (declaration_to_hash, definition_to_hash, …)
@@ -49,7 +49,7 @@ lib/rails_ai_bridge/
49
49
 
50
50
  ## Code Style
51
51
 
52
- - Follow `rubocop-rails-omakase` style (run `bundle exec rubocop`)
52
+ - Follow RuboCop with the project's custom limits (see `.rubocop.yml` — plugins performance/rails/rspec; method length, ABC size and class length limits are deliberately more permissive than the omakase defaults); run `bundle exec rubocop`
53
53
  - Optional complexity check: `bundle exec skunk lib/rails_ai_bridge/…` (gem in `:development`/`:test`) — keep new or refactored files lean (project goal: Skunk score around **≤ 25** where practical).
54
54
 
55
55
  - Ruby 3.2+ features welcome (pattern matching, etc.)
data/GEMINI.md CHANGED
@@ -8,10 +8,9 @@ committed context files. It does not write to the host database.
8
8
  - `lib/rails_ai_bridge.rb` — Main entry point, public API (Zeitwerk autoloaded)
9
9
  - `lib/rails_ai_bridge/configuration.rb` — User-facing config with presets (:standard, :full)
10
10
  - `lib/rails_ai_bridge/introspector.rb` — Orchestrates sub-introspectors
11
- - `lib/rails_ai_bridge/introspectors/` — Built-in introspector classes; `:standard` preset runs **9**, `:full` runs **26** (see `Configuration::PRESETS`). Registry: `Introspector::BUILTIN_INTROSPECTORS` (includes opt-in symbols such as `database_stats`, `non_ar_models` not listed in those presets).
12
- - `lib/rails_ai_bridge/tools/` — 19 built-in MCP tools using the official mcp SDK (hosts can add more via `additional_tools`)
13
- - `lib/rails_ai_bridge/serializers/` — Output formatters (claude, claude_rules, cursor_rules, windsurf, windsurf_rules, copilot, copilot_instructions, rules, markdown, JSON, gemini)
14
- runs **9**, `:full` runs **27** (see `Configuration::PRESETS`). Registry:
11
+ - `lib/rails_ai_bridge/introspectors/` — Built-in introspector classes; `:standard` preset runs **9**, `:full` runs **27** (see `Configuration::PRESETS`). Registry: `Introspector::BUILTIN_INTROSPECTORS` (includes opt-in symbols such as `database_stats`, `non_ar_models` not listed in those presets).
12
+ - `lib/rails_ai_bridge/tools/` — 22 built-in MCP tools using the official mcp SDK (hosts can add more via `additional_tools`)
13
+ - `lib/rails_ai_bridge/serializers/` — Output formatters (claude, claude_rules, codex, cursor_rules, devin, devin_rules, copilot, copilot_instructions, gemini, rules, markdown, JSON)
15
14
  - `lib/rails_ai_bridge/resources.rb` — MCP resources (static data AI clients read directly)
16
15
  - `lib/rails_ai_bridge/server.rb` — MCP server configuration (stdio + HTTP transports)
17
16
  - `lib/rails_ai_bridge/middleware.rb` — Rack middleware for auto-mounting MCP HTTP endpoint