From 558a053e5477fe43a7641b467b13de6a6ac298a8 Mon Sep 17 00:00:00 2001 From: maebeale Date: Tue, 10 Mar 2026 06:23:37 -0400 Subject: [PATCH 01/20] Audit Stimulus controllers for conventions and update AI docs - Remove dead controllers (nav, search_box) - Convert querySelector/getElementById to static targets - Convert instance variables to static values - Replace addEventListener with data-action attributes - Replace style.display with hidden class toggling - Fix CSS injection leak in remote_select - Remove console.log statements - Add comprehensive Stimulus conventions to AI instruction files - Add AI Instruction Files reference table to CLAUDE.md - Update PR instruction wording to "content" (covers checklists) Co-Authored-By: Claude Opus 4.6 --- .github/copilot-instructions.md | 231 ++++++------------ AGENTS.md | 156 +++++------- CLAUDE.md | 138 +++++++---- .../controllers/asset_picker_controller.js | 4 + .../controllers/collection_controller.js | 46 ++-- .../controllers/column_toggle_controller.js | 6 +- .../comment_edit_toggle_controller.js | 29 +-- .../controllers/dirty_form_controller.js | 29 +-- .../controllers/dropdown_controller.js | 10 +- app/frontend/javascript/controllers/index.js | 3 - .../javascript/controllers/nav_controller.js | 24 -- .../paginated_fields_controller.js | 30 +-- .../controllers/password_toggle_controller.js | 14 +- .../controllers/print_options_controller.js | 24 +- .../controllers/remote_select_controller.js | 54 ++-- .../controllers/search_box_controller.js | 14 -- .../javascript/controllers/tabs_controller.js | 52 ++-- .../tags_combination_highlight_controller.js | 18 +- .../controllers/timeframe_controller.js | 38 ++- .../controllers/toggle_lock_controller.js | 4 +- .../toggle_user_icon_controller.js | 4 +- app/helpers/analytics_helper.rb | 8 +- app/views/comments/_comment_fields.html.erb | 4 +- app/views/devise/passwords/edit.html.erb | 4 +- app/views/devise/sessions/new.html.erb | 2 +- app/views/event_registrations/_form.html.erb | 2 +- app/views/events/_manage_results.html.erb | 4 +- app/views/organizations/_form.html.erb | 2 +- app/views/people/_form.html.erb | 5 +- .../taggings/_explore_by_combination.html.erb | 4 + app/views/users/_form.html.erb | 11 +- app/views/users/change_password.html.erb | 6 +- app/views/users/edit.html.erb | 6 +- .../video_recordings/_search_boxes.html.erb | 4 +- app/views/welcome/show.html.erb | 4 +- 35 files changed, 421 insertions(+), 573 deletions(-) delete mode 100644 app/frontend/javascript/controllers/nav_controller.js delete mode 100644 app/frontend/javascript/controllers/search_box_controller.js diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index d9751921d..14aa7aefc 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,48 +1,31 @@ -# This is a Ruby on Rails application. +# This project is a Ruby on Rails application. -For project overview, tech stack, architecture reference (models, controllers, services, testing), and more, read `AGENTS.md`. - -## Setup - -Full setup (bundle, npm, database create/migrate/seed): -``` -bin/setup -``` - -If you just need frontend dependencies: -``` -npm ci -``` - -## AI Instruction Files - -When the user says "AI files", "AI instructions", "tell AI to", or "remember to always", these are the files. -If you notice the user repeatedly correcting the same pattern, suggest adding it to the AI files with a concrete proposal. - -| File | Purpose | -|---|---| -| `CLAUDE.md` | Coding rules and conventions (this file) | -| `AGENTS.md` | Architecture reference + project details | -| `.github/copilot-instructions.md` | Coding rules for Copilot (duplicated from CLAUDE.md — keep in sync) | -| `ai/` | Shell script shortcuts for common dev tasks | - -## Related Files - -When changing a model or controller, check whether these related files need updates: - -| If you change... | Also check... | -|---|---| -| Model | Decorator, policy, factory, model spec | -| Controller | Policy, request spec, routing spec, views | -| View | System spec, Stimulus controller (if interactive) | -| Service | Service spec | -| Decorator | Decorator spec | -| Mailer (add/remove) | Mailer spec, mailer preview (follow existing patterns) | -| Add/remove model, concern, service, or gem | AGENTS.md | - -## Code Style - +# Frontend requirements: +- Strongly prefer Stimulus for JavaScript behavior — do not write raw/inline JS or jQuery +- Always use Tailwind CSS utility classes for styling — do not write custom CSS unless absolutely necessary +- Prefer Turbo for navigation and form submissions before reaching for Stimulus +- ES6+ syntax, ESM imports/exports +- Stimulus controller naming: `[name]_controller.js` + +# Stimulus conventions: +- Use `static targets` and `data-[controller]-target` — never `querySelector` or `getElementById` for elements that could be targets +- Use `static values = { name: Type }` for state — not instance variables. Use `[name]ValueChanged()` for reactive updates +- Use `data-action` attributes — not `addEventListener` in `connect()`. Omit default events (`click` for buttons, `input` for inputs, `submit` for forms, `change` for selects) +- Use `@window`/`@document` suffixes for global events in data-action +- Use action options (`:prevent`, `:stop`) instead of `event.preventDefault()` in methods +- Use `static classes` when CSS classes should be configurable from HTML +- Use `static outlets` for cross-controller communication instead of `getElementById` +- Always clean up in `disconnect()` anything created in `connect()` (listeners, timers, observers) +- Use `[name]TargetConnected`/`TargetDisconnected` for dynamic DOM (cocoon, Turbo) +- Toggle `hidden` class instead of `style.display`. Use `class="hidden"` not `style="display:none"` in HTML + +# PRs +- After completing work, create a pull request using `gh pr create` +- Once the PR is created, prepend the PR number to the branch name (e.g., rename `maebeale/fix-login` to `maebeale/1234-fix-login`) using `git branch -m` and `git push origin -u` with the new name, then delete the old remote branch +- On every push, update the PR title and content to reflect the current diff + +# Code style requirements: - Use modern Ruby syntax - Prefer early returns and guard clauses - Avoid unnecessary and/or complex conditionals @@ -51,59 +34,56 @@ When changing a model or controller, check whether these related files need upda - Use `presence` over blank checks - Use `Arel.sql` for raw SQL in order clauses - Avoid `update_all` unless explicitly intended -- Prefer service objects under app/services/ +- Prefer service objects under app/services - Prefer POROs over concerns when possible - Use `after_commit` instead of `after_save` for side effects -## RuboCop (rubocop-rails-omakase) - +# RuboCop (rubocop-rails-omakase) This project uses rubocop-rails-omakase. All code MUST follow these rules: -### Strings -- **Always use double quotes** for strings: `"foo"` not `'foo'` - -### Spacing -- **Spaces inside array brackets:** `[ a, b, c ]` not `[a, b, c]` (empty arrays: `[]`) -- **Spaces inside hash braces:** `{ a: 1, b: 2 }` not `{a: 1}` (empty hashes: `{}`) -- **Spaces inside block braces:** `foo { bar }` not `foo {bar}` (empty blocks: `foo { }`) -- **No spaces inside parens:** `foo(bar)` not `foo( bar )` -- **No spaces inside reference brackets:** `hash[:key]` not `hash[ :key ]` -- **Space before block braces:** `foo { }` not `foo{ }` - -### Commas -- **No trailing commas** in arrays, hashes, or method arguments - -### Indentation -- **2-space indentation**, no tabs -- **Consistent indentation** at normal level — do NOT indent methods under `private`/`protected` -- **Align `end` with the variable** in assignments: - ```ruby - result = if condition - value - end - ``` -- **Align `when` with `end`**, not with `case` - -### Whitespace -- **No trailing whitespace** on any line -- **No trailing blank lines** at end of file -- **No empty lines** inside class, module, method, or block bodies - -### Syntax -- **Use `%w[]` and `%i[]`** with square bracket delimiters (not parens) -- **Use modern hash syntax:** `{ key: value }` not `{ :key => value }` -- **No redundant returns** — omit `return` on last expression -- **Use `flat_map`** instead of `.map { }.flatten` -- **No redundant `.to_s`** inside string interpolation -- **Use `Foo.method`** not `Foo::method` for method calls -- **No parentheses around conditions:** `if foo` not `if (foo)` -- **No semicolons** to separate statements - -## HTML/ERB Formatting - -### Tag Attributes -- **Closing `>` on same line as last attribute** — do not put `>` on its own line -- When attributes span multiple lines, keep the closing `>` with the last attribute +## Strings +- Always use double quotes: `"foo"` not `'foo'` + +## Spacing +- Spaces inside array brackets: `[ a, b, c ]` not `[a, b, c]` (empty arrays: `[]`) +- Spaces inside hash braces: `{ a: 1, b: 2 }` not `{a: 1}` (empty hashes: `{}`) +- Spaces inside block braces: `foo { bar }` not `foo {bar}` (empty blocks: `foo { }`) +- No spaces inside parens: `foo(bar)` not `foo( bar )` +- No spaces inside reference brackets: `hash[:key]` not `hash[ :key ]` +- Space before block braces: `foo { }` not `foo{ }` + +## Commas +- No trailing commas in arrays, hashes, or method arguments + +## Indentation +- 2-space indentation, no tabs +- Consistent indentation at normal level — do NOT indent methods under `private`/`protected` +- Align `end` with the variable in assignments +- Align `when` with `end`, not with `case` + +## Whitespace +- No trailing whitespace on any line +- No trailing blank lines at end of file +- No empty lines inside class, module, method, or block bodies + +## Syntax +- Use `%w[]` and `%i[]` with square bracket delimiters (not parens) +- Use modern hash syntax: `{ key: value }` not `{ :key => value }` +- No redundant returns — omit `return` on last expression +- Use `flat_map` instead of `.map { }.flatten` +- No redundant `.to_s` inside string interpolation +- Use `Foo.method` not `Foo::method` for method calls +- No parentheses around conditions: `if foo` not `if (foo)` +- No semicolons to separate statements + +# Git +- When rebasing onto main, review incoming changes for their intent and flag any oversights — missing tests, incomplete migrations, broken assumptions, or conflicts between the two branches. Check both directions: schema/model changes on either branch that affect views, partials, or layouts on the other (e.g., main redesigned a table's CSS but your branch adds new columns to it, or vice versa) + +# HTML/ERB Formatting + +## Tag attributes +- When a tag has long attributes, place the closing `>` on the same line as the last attribute +- Do NOT put the closing `>` on its own line - Example (GOOD): ```erb @@ -53,7 +53,7 @@ data: { password_toggle_target: "input" } %>

Password must be at least 5 characters long

@@ -75,7 +75,7 @@ data: { password_toggle_target: "input" } %> diff --git a/app/views/users/edit.html.erb b/app/views/users/edit.html.erb index 8fa1ccb2b..463278149 100644 --- a/app/views/users/edit.html.erb +++ b/app/views/users/edit.html.erb @@ -43,10 +43,8 @@

<%= @user.email %> - - + +

<% if @user.person %>

diff --git a/app/views/video_recordings/_search_boxes.html.erb b/app/views/video_recordings/_search_boxes.html.erb index 6118e0bbf..50eb218f1 100644 --- a/app/views/video_recordings/_search_boxes.html.erb +++ b/app/views/video_recordings/_search_boxes.html.erb @@ -1,5 +1,7 @@ -

+
<%= form_with url: video_recordings_path, method: :get, data: { turbo_frame: "video_recordings_results", controller: "searchable-checkbox" }, diff --git a/app/views/welcome/show.html.erb b/app/views/welcome/show.html.erb index b9e52ff7e..c129a4729 100644 --- a/app/views/welcome/show.html.erb +++ b/app/views/welcome/show.html.erb @@ -35,7 +35,7 @@ data: { password_toggle_target: "input" } %>
@@ -57,7 +57,7 @@ data: { password_toggle_target: "input" } %>
From 049eb0e6f5f4a3877f91e27b922ec8dff1396e8b Mon Sep 17 00:00:00 2001 From: maebeale Date: Tue, 10 Mar 2026 06:30:23 -0400 Subject: [PATCH 02/20] Remove stale tag_deduping.rake reference, add AI files update rule - tag_deduping.rake no longer exists, remove from AGENTS.md - Add instruction to update AI files on every push when conventions, architecture, or file lists change Co-Authored-By: Claude Opus 4.6 --- .github/copilot-instructions.md | 1 + AGENTS.md | 2 +- CLAUDE.md | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 14aa7aefc..980f5610b 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -24,6 +24,7 @@ - After completing work, create a pull request using `gh pr create` - Once the PR is created, prepend the PR number to the branch name (e.g., rename `maebeale/fix-login` to `maebeale/1234-fix-login`) using `git branch -m` and `git push origin -u` with the new name, then delete the old remote branch - On every push, update the PR title and content to reflect the current diff +- On every push, update AI instruction files if the diff introduces changes that affect conventions, architecture, or file lists documented there # Code style requirements: - Use modern Ruby syntax diff --git a/AGENTS.md b/AGENTS.md index 9607473a7..fb52f27d5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -331,6 +331,7 @@ RuboCop linting on PRs and pushes to main. ## PRs - On every push, update the PR title and content to reflect the current diff +- On every push, update AI instruction files if the diff introduces changes that affect conventions, architecture, or file lists documented there ## Git @@ -342,4 +343,3 @@ Located in `lib/tasks/` (~17 files). Notable: - `dev.rake` — Development database seeding from XML/CSV - `paperclip_to_active_storage.rake` — File upload migration - `rhino_migrator.rake` — Rich text editor migration -- `tag_deduping.rake` — Tag deduplication diff --git a/CLAUDE.md b/CLAUDE.md index 9cfe92577..dbd8f809b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -216,6 +216,7 @@ Follow the [Stimulus Handbook](https://stimulus.hotwired.dev/handbook/introducti - Description must explain why the change was made, not just what - Include screenshots for UI changes - **On every push**, update the PR title and content to reflect the current diff +- **On every push**, update AI instruction files if the diff introduces changes that affect conventions, architecture, or file lists documented there ## Quick Commands From 72209b2ab745b81c5cba9e55b906c5691bbf75f0 Mon Sep 17 00:00:00 2001 From: maebeale Date: Tue, 10 Mar 2026 06:33:31 -0400 Subject: [PATCH 03/20] =?UTF-8?q?Deduplicate=20AI=20instruction=20files=20?= =?UTF-8?q?=E2=80=94=20CLAUDE.md=20is=20single=20source=20of=20truth?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - copilot-instructions.md now just points to CLAUDE.md and AGENTS.md - AGENTS.md removes duplicated PR, Git, and frontend preference sections - CLAUDE.md updated to reflect the new structure Co-Authored-By: Claude Opus 4.6 --- .github/copilot-instructions.md | 99 +-------------------------------- AGENTS.md | 22 +------- CLAUDE.md | 9 ++- 3 files changed, 8 insertions(+), 122 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 980f5610b..4278d3f73 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,98 +1,5 @@ -# This project is a Ruby on Rails application. - +# Copilot Instructions -# Frontend requirements: -- Strongly prefer Stimulus for JavaScript behavior — do not write raw/inline JS or jQuery -- Always use Tailwind CSS utility classes for styling — do not write custom CSS unless absolutely necessary -- Prefer Turbo for navigation and form submissions before reaching for Stimulus -- ES6+ syntax, ESM imports/exports -- Stimulus controller naming: `[name]_controller.js` +Read and follow all rules in `CLAUDE.md` at the project root — it is the single source of truth for coding conventions, style rules, Stimulus conventions, HTML/ERB formatting, Git workflow, and PR process. -# Stimulus conventions: -- Use `static targets` and `data-[controller]-target` — never `querySelector` or `getElementById` for elements that could be targets -- Use `static values = { name: Type }` for state — not instance variables. Use `[name]ValueChanged()` for reactive updates -- Use `data-action` attributes — not `addEventListener` in `connect()`. Omit default events (`click` for buttons, `input` for inputs, `submit` for forms, `change` for selects) -- Use `@window`/`@document` suffixes for global events in data-action -- Use action options (`:prevent`, `:stop`) instead of `event.preventDefault()` in methods -- Use `static classes` when CSS classes should be configurable from HTML -- Use `static outlets` for cross-controller communication instead of `getElementById` -- Always clean up in `disconnect()` anything created in `connect()` (listeners, timers, observers) -- Use `[name]TargetConnected`/`TargetDisconnected` for dynamic DOM (cocoon, Turbo) -- Toggle `hidden` class instead of `style.display`. Use `class="hidden"` not `style="display:none"` in HTML - -# PRs -- After completing work, create a pull request using `gh pr create` -- Once the PR is created, prepend the PR number to the branch name (e.g., rename `maebeale/fix-login` to `maebeale/1234-fix-login`) using `git branch -m` and `git push origin -u` with the new name, then delete the old remote branch -- On every push, update the PR title and content to reflect the current diff -- On every push, update AI instruction files if the diff introduces changes that affect conventions, architecture, or file lists documented there - -# Code style requirements: -- Use modern Ruby syntax -- Prefer early returns and guard clauses -- Avoid unnecessary and/or complex conditionals -- Prefer constants and scopes over magic strings -- Use safe navigation (`&.`) where appropriate -- Use `presence` over blank checks -- Use `Arel.sql` for raw SQL in order clauses -- Avoid `update_all` unless explicitly intended -- Prefer service objects under app/services -- Prefer POROs over concerns when possible -- Use `after_commit` instead of `after_save` for side effects - -# RuboCop (rubocop-rails-omakase) -This project uses rubocop-rails-omakase. All code MUST follow these rules: - -## Strings -- Always use double quotes: `"foo"` not `'foo'` - -## Spacing -- Spaces inside array brackets: `[ a, b, c ]` not `[a, b, c]` (empty arrays: `[]`) -- Spaces inside hash braces: `{ a: 1, b: 2 }` not `{a: 1}` (empty hashes: `{}`) -- Spaces inside block braces: `foo { bar }` not `foo {bar}` (empty blocks: `foo { }`) -- No spaces inside parens: `foo(bar)` not `foo( bar )` -- No spaces inside reference brackets: `hash[:key]` not `hash[ :key ]` -- Space before block braces: `foo { }` not `foo{ }` - -## Commas -- No trailing commas in arrays, hashes, or method arguments - -## Indentation -- 2-space indentation, no tabs -- Consistent indentation at normal level — do NOT indent methods under `private`/`protected` -- Align `end` with the variable in assignments -- Align `when` with `end`, not with `case` - -## Whitespace -- No trailing whitespace on any line -- No trailing blank lines at end of file -- No empty lines inside class, module, method, or block bodies - -## Syntax -- Use `%w[]` and `%i[]` with square bracket delimiters (not parens) -- Use modern hash syntax: `{ key: value }` not `{ :key => value }` -- No redundant returns — omit `return` on last expression -- Use `flat_map` instead of `.map { }.flatten` -- No redundant `.to_s` inside string interpolation -- Use `Foo.method` not `Foo::method` for method calls -- No parentheses around conditions: `if foo` not `if (foo)` -- No semicolons to separate statements - -# Git -- When rebasing onto main, review incoming changes for their intent and flag any oversights — missing tests, incomplete migrations, broken assumptions, or conflicts between the two branches. Check both directions: schema/model changes on either branch that affect views, partials, or layouts on the other (e.g., main redesigned a table's CSS but your branch adds new columns to it, or vice versa) - -# HTML/ERB Formatting - -## Tag attributes -- When a tag has long attributes, place the closing `>` on the same line as the last attribute -- Do NOT put the closing `>` on its own line -- Example (GOOD): - ```erb -