Module: RailsAiBridge::Serializers::SharedAssistantGuidance
- Defined in:
- lib/rails_ai_bridge/serializers/shared_assistant_guidance.rb
Overview
Shared high-signal copy for Copilot, Codex, Cursor, and legacy .cursorrules compact output.
Constant Summary collapse
- OMIT_MERGE_FIRST_LINE =
First line of
overrides.mdwhile in stub mode — file is not merged until removed. /\A<!--\s*rails-ai-bridge:omit-merge\s*-->\z/i- ANTI_HALLUCINATION_HEADING =
Shared heading used by compact assistant files.
'## Anti-hallucination'
Class Method Summary collapse
-
.anti_hallucination_rules_enabled? ⇒ Boolean
truewhen compact output should include the shared anti-hallucination block. -
.anti_hallucination_rules_lines ⇒ Array<String>
Markdown lines including heading and trailing blank line, or
[]when Config::Output#anti_hallucination_rules is off. -
.claude_full_footer_lines(context) ⇒ Array<String>
Full-mode Claude Code footer (plain-language bullets; not the compact rules list).
-
.compact_engineering_rules_footer_lines(context, rules_heading: '## Rules', include_anti_hallucination: true) ⇒ Array<String>
Closing rules and regeneration footer (shared by compact provider serializers and Providers::RulesOrchestrator).
-
.compact_engineering_rules_lines ⇒ Array<String>
Markdown lines including heading and trailing blank line.
-
.cursor_engineering_mdc_body_lines(show_overrides_pointer: false) ⇒ Array<String>
Condensed rules for always-on Cursor MDC (stay under ~35 lines of body).
-
.mergeable_override_content?(body) ⇒ Boolean
falsewhen the install stub has not been activated yet. -
.overrides_file_exists_and_nonempty? ⇒ Boolean
Whether overrides are active (merge + Cursor pointer), not placeholder-only.
-
.performance_security_and_rails_examples_lines ⇒ Array<String>
Baseline bullets plus concrete Rails patterns for large data.
-
.rails_performance_examples_lines ⇒ Array<String>
Concrete Rails patterns to complement generic performance bullets (gem cannot know your largest tables).
-
.read_assistant_overrides ⇒ String?
Raw markdown body from the host app overrides file, or
nilif missing, empty, or still in stub mode (first non-empty line is<!-- rails-ai-bridge:omit-merge -->). -
.repo_specific_guidance_section_lines ⇒ Array<String>
Section to splice after stack; empty if no overrides.
-
.resolved_assistant_overrides_path ⇒ String?
Absolute path to overrides file if Rails app is available.
Class Method Details
.anti_hallucination_rules_enabled? ⇒ Boolean
Returns true when compact output should include the shared anti-hallucination block.
237 238 239 240 |
# File 'lib/rails_ai_bridge/serializers/shared_assistant_guidance.rb', line 237 def anti_hallucination_rules_enabled? # archspec:disable-next-line dependencies.forbid -- FP: RailsAiBridge is the reopened gem namespace; .configuration accessor is not a cross-component dependency RailsAiBridge.configuration.anti_hallucination_rules end |
.anti_hallucination_rules_lines ⇒ Array<String>
Returns markdown lines including heading and trailing blank line,
or [] when Config::Output#anti_hallucination_rules is off.
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/rails_ai_bridge/serializers/shared_assistant_guidance.rb', line 21 def anti_hallucination_rules_lines return [] unless anti_hallucination_rules_enabled? [ ANTI_HALLUCINATION_HEADING, '', '- Verify before you write (column, association, route, helper, gem).', '- Mark assumptions with `[ASSUMPTION]`. Silent guesses are forbidden.', '- This app is not average Rails. Query conventions and gems before scaffolding.', '- Check the inheritance chain (filters, concerns, STI) before editing a controller or model.', '- Empty tool output is information, not permission to invent.', '- Re-query after writes. Stale tool output lies.', '' ] end |
.claude_full_footer_lines(context) ⇒ Array<String>
Full-mode Claude Code footer (plain-language bullets; not the compact rules list).
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
# File 'lib/rails_ai_bridge/serializers/shared_assistant_guidance.rb', line 182 def (context) arch = context.dig(:conventions, :architecture) arch_summary = arch&.any? ? arch.join(', ') : nil lines = [ '## Behavioral Rules', '', 'When working in this codebase:', '- Follow existing patterns and conventions detected above', '- Use the database schema as the source of truth for column names and types', '- Respect existing associations and validations when modifying models' ] lines << "- Match the project's architecture style (#{arch_summary})" if arch_summary lines << "- Run `#{ContextSummary.test_command(context)}` after making changes to verify correctness" lines.concat(RegenerationFooter.continuation_lines(command: 'rails ai:bridge', variant: :context_file)) lines end |
.compact_engineering_rules_footer_lines(context, rules_heading: '## Rules', include_anti_hallucination: true) ⇒ Array<String>
Closing rules and regeneration footer (shared by compact provider serializers and Providers::RulesOrchestrator).
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
# File 'lib/rails_ai_bridge/serializers/shared_assistant_guidance.rb', line 207 def (context, rules_heading: '## Rules', include_anti_hallucination: true) arch = context.dig(:conventions, :architecture) arch_summary = arch&.any? ? arch.join(', ') : nil lines = [] lines.concat(anti_hallucination_rules_lines) if include_anti_hallucination lines.push( rules_heading, '', '- **Adhere to Conventions:** Strictly follow the existing patterns and conventions outlined in this document.', '- **Schema as Source of Truth:** Always use the database schema as the definitive source for column names, types, and relationships.', '- **Respect Existing Logic:** Ensure all new code respects existing associations, validations, and service objects.', '- **Write Tests:** All new features and bug fixes must be accompanied by corresponding tests.' ) lines << "- **Match Architecture:** Align with the project's architectural style (#{arch_summary})." if arch_summary lines << "- **Verify Correctness:** Run `#{ContextSummary.test_command(context)}` and `bundle exec rubocop` after making changes to ensure correctness and style adherence." lines << '' lines << '---' lines << RegenerationFooter.(command: 'rails ai:bridge', variant: :context_file) lines end |
.compact_engineering_rules_lines ⇒ Array<String>
Returns markdown lines including heading and trailing blank line.
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/rails_ai_bridge/serializers/shared_assistant_guidance.rb', line 38 def compact_engineering_rules_lines anti_hallucination_rules_lines + [ '## Engineering rules (read first)', '', 'Defaults for this codebase unless existing files clearly show a different pattern.', '', '### Controllers & strong parameters', '- Permit attributes explicitly; never pass raw `params` into `Model.new`, `update`, or `assign_attributes`.', '- Extend `permit` lists deliberately when adding fields; mirror neighboring actions in the same controller.', '', '### Authentication & authorization', "- Guard mutating and sensitive reads with the app's existing auth (e.g. `before_action` filters, policies). A public route does not imply public data.", '- Use `rails_get_controllers` for filters and `rails_get_conventions` for architecture hints when unsure.', '', '### Data access & performance', '- Avoid N+1: use `includes` / `preload` / `eager_load` for associations used in views or serializers.', '- Do not load unbounded collections: paginate list endpoints, use `find_each` in jobs, stream large exports.', '- Large or hot tables: check indexes before new `WHERE`/`ORDER BY`; use `rails_get_schema` before heavy queries.', '', '### Security & inputs', '- Treat external input as untrusted; avoid `constantize` / `send` / `eval` on user-controlled strings and raw SQL string interpolation.', '- Allow-list host or path for any redirect built from user input (open-redirect risk).', '', '### Testing', '- Prefer request or system specs for HTTP flows and integration; keep model specs tight for business rules.', "- Run the project's test suite after substantive edits (often `bundle exec rspec` — confirm framework via `rails_get_test_info`).", '', '### Repo-specific constraints', '- Hot tables, tenant/auth scoping, mandatory spec types, and internal policies belong in `config/rails_ai_bridge/overrides.md`.', '- Remove or replace the first-line `<!-- rails-ai-bridge:omit-merge -->` marker before that file is merged into Copilot/Codex; ' \ 'use `overrides.md.example` as a starting outline.', '', '_Regenerated files are snapshots. Re-merge team-specific performance, security, or compliance rules at the top after `rails ai:bridge`, ' \ 'or keep them in separate committed instruction files._', '' ] end |
.cursor_engineering_mdc_body_lines(show_overrides_pointer: false) ⇒ Array<String>
Condensed rules for always-on Cursor MDC (stay under ~35 lines of body).
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/rails_ai_bridge/serializers/shared_assistant_guidance.rb', line 96 def cursor_engineering_mdc_body_lines(show_overrides_pointer: false) lines = [ '# Engineering essentials', '' ] lines.concat(anti_hallucination_rules_lines) lines.push( '- **Strong params**: permit explicitly; never mass-assign raw `params`.', '- **Auth**: protect mutations and sensitive reads; public route ≠ public data.', '- **N+1**: `includes` / `preload` / `eager_load` for associations in views and serializers.', '- **Bounds**: paginate HTTP lists; `find_each` / `in_batches` in jobs; no `Model.all` in requests.', '- **Large tables**: narrow queries; check indexes before new filters/sorts; use `rails_get_schema`.', '- **Security**: no `constantize`/`send`/`eval` on user input; no SQL string interpolation; allow-list redirects.', '- **Tests**: request/system specs for HTTP; confirm runner with `rails_get_test_info`.', '', 'Generated files are **snapshots** — prefer `rails_*` MCP tools for current structure.', 'Full engineering rules: `.github/copilot-instructions.md` or `AGENTS.md`.', 'MCP tool reference: `rails-mcp-tools.mdc`.' ) lines << 'Repo-specific performance/security: `config/rails_ai_bridge/overrides.md`.' if show_overrides_pointer lines << '' lines end |
.mergeable_override_content?(body) ⇒ Boolean
Returns false when the install stub has not been activated yet.
140 141 142 143 144 145 146 |
# File 'lib/rails_ai_bridge/serializers/shared_assistant_guidance.rb', line 140 def mergeable_override_content?(body) first = body.each_line.map(&:strip).find { |line| !line.empty? } return false if first.nil? return false if OMIT_MERGE_FIRST_LINE.match?(first) true end |
.overrides_file_exists_and_nonempty? ⇒ Boolean
Returns whether overrides are active (merge + Cursor pointer), not placeholder-only.
134 135 136 |
# File 'lib/rails_ai_bridge/serializers/shared_assistant_guidance.rb', line 134 def overrides_file_exists_and_nonempty? read_assistant_overrides != nil end |
.performance_security_and_rails_examples_lines ⇒ Array<String>
Baseline bullets plus concrete Rails patterns for large data.
232 233 234 |
# File 'lib/rails_ai_bridge/serializers/shared_assistant_guidance.rb', line 232 def performance_security_and_rails_examples_lines ContextSummary.compact_performance_security_section + rails_performance_examples_lines end |
.rails_performance_examples_lines ⇒ Array<String>
Concrete Rails patterns to complement generic performance bullets (gem cannot know your largest tables).
79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/rails_ai_bridge/serializers/shared_assistant_guidance.rb', line 79 def rails_performance_examples_lines [ '### Rails patterns (large data & hot paths)', '- Never use `Model.all` (or unscoped relations) in request cycles — use `where`, `limit`, or pagination.', '- Background jobs: iterate with `find_each` or `in_batches` instead of `each` on large relations.', '- Prefer `exists?` / `count` with care on huge tables; narrow with `where` first; avoid `length` on loaded associations for big sets.', '- Wide rows: fetch only needed columns with `select` / `pluck` when you do not need full records.', '- Enable or use `strict_loading` in development/test to catch accidental N+1s early.', '- Before adding filters or `ORDER BY` on high-volume tables, confirm indexes via `rails_get_schema` and migrations.', '' ] end |
.read_assistant_overrides ⇒ String?
Returns raw markdown body from the host app overrides file, or nil if missing,
empty, or still in stub mode (first non-empty line is <!-- rails-ai-bridge:omit-merge -->).
122 123 124 125 126 127 128 129 130 131 |
# File 'lib/rails_ai_bridge/serializers/shared_assistant_guidance.rb', line 122 def read_assistant_overrides path = resolved_assistant_overrides_path return nil unless path && File.file?(path) body = File.read(path).strip return nil if body.empty? return nil unless mergeable_override_content?(body) body end |
.repo_specific_guidance_section_lines ⇒ Array<String>
Returns section to splice after stack; empty if no overrides.
166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/rails_ai_bridge/serializers/shared_assistant_guidance.rb', line 166 def repo_specific_guidance_section_lines body = read_assistant_overrides return [] unless body [ '## Repo-specific guidance', '', body, '' ] end |
.resolved_assistant_overrides_path ⇒ String?
Returns absolute path to overrides file if Rails app is available.
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/rails_ai_bridge/serializers/shared_assistant_guidance.rb', line 149 def resolved_assistant_overrides_path app = AppScope.current_app return nil unless app base = app.root.to_s # archspec:disable-next-line dependencies.forbid -- FP: RailsAiBridge is the reopened gem namespace; .configuration accessor is not a cross-component dependency cfg = RailsAiBridge.configuration raw = cfg.assistant_overrides_path if raw.nil? || raw.to_s.empty? File.join(base, 'config/rails_ai_bridge/overrides.md') else p = raw.to_s Pathname.new(p).absolute? ? p : File.join(base, p) end end |