Upgrade Engine
Core principle: Every claimed Rails/Ruby version must be in the CI matrix. Prefer explicit support targets over accidental compatibility.
HARD-GATE
Before claiming support for a Rails/Ruby version:
1. bundle exec rake zeitwerk:check # verify autoloading on each version
2. bundle exec rspec # full suite per matrix version
3. CI matrix must pass — not just main Rails version
DO NOT ship compatibility changes without verifying both autoloading and full suite.
Core Process
- Define supported Ruby and Rails versions — state them in gemspec and README.
- Run
bundle exec rake zeitwerk:check — file paths must match constant names exactly (e.g. my_engine/widget_policy.rb → MyEngine::WidgetPolicy).
- Check initializer behavior across boot and reload — use
config.to_prepare for reload-sensitive hooks; hooks placed at load time are reload-unsafe in development.
- Verify gemspec dependency bounds match tested versions:
spec.add_dependency "rails", ">= 7.0", "< 8.0" — bounds must reflect what CI actually tests. Unbounded or overclaiming constraints (>= 5.2 without testing 5.2/6.x) are silent incompatibilities.
- Replace
Rails.version branching with feature detection — version checks are brittle across patch releases:
# ❌ Bad — brittle, wrong for patch versions
if Rails.version >= "7.0"
config.active_support.cache_format_version = 7.0
end
# ✅ Good — detect the capability directly
if ActiveSupport::Cache.respond_to?(:format_version=)
config.active_support.cache_format_version = 7.0
end
- Check optional integrations (jobs, mailers, assets, routes, install generators, dummy-app mounts) per version. State the check even if an integration is absent.
- CI matrix must run against each claimed Rails/Ruby combination:
strategy:
matrix:
include:
- { ruby: "3.2", rails: "7.1" }
- { ruby: "3.3", rails: "7.2" }
Extended Resources
- assets/compatibility_matrix.md
- assets/zeitwerk_notes.md
- EXAMPLES.md
Output Style
- State the support matrix being targeted.
- List the most likely breakpoints.
- Make compatibility changes in isolated, testable seams.
- Recommend matrix coverage if it does not exist.
- Include an Optional integration matrix with rows for jobs, mailers, assets, routes, generators, and dummy app mount. For each row, state
present/absent, the file path checked, and the per-version verification command.
- Language — Must be in English unless explicitly requested otherwise.
Integration
| Skill |
When to chain |
| test-engine |
Test matrix setup, CI configuration, multi-version tests |
| create-engine |
Engine structure, host contract, namespace design |
| release-engine |
Versioning, changelog, upgrade notes for compatibility changes |
1---2name: upgrade-engine3description: Use when checking a Rails engine across Rails versions (Zeitwerk, compatibility). Trigger words: Zeitwerk, Rails upgrade, cross-version, engine compatibility.4license: MIT5---67# Upgrade Engine89**Core principle:** Every claimed Rails/Ruby version must be in the CI matrix. Prefer explicit support targets over accidental compatibility.1011## HARD-GATE1213```text14Before claiming support for a Rails/Ruby version:15 1. bundle exec rake zeitwerk:check # verify autoloading on each version16 2. bundle exec rspec # full suite per matrix version17 3. CI matrix must pass — not just main Rails version1819DO NOT ship compatibility changes without verifying both autoloading and full suite.20```2122## Core Process23241. Define supported Ruby and Rails versions — state them in gemspec and README.252. Run `bundle exec rake zeitwerk:check` — file paths must match constant names exactly (e.g. `my_engine/widget_policy.rb` → `MyEngine::WidgetPolicy`).263. Check initializer behavior across boot and reload — use `config.to_prepare` for reload-sensitive hooks; hooks placed at load time are reload-unsafe in development.274. Verify gemspec dependency bounds match tested versions: `spec.add_dependency "rails", ">= 7.0", "< 8.0"` — bounds must reflect what CI actually tests. Unbounded or overclaiming constraints (`>= 5.2` without testing 5.2/6.x) are silent incompatibilities.285. Replace `Rails.version` branching with feature detection — version checks are brittle across patch releases:29```ruby30# ❌ Bad — brittle, wrong for patch versions31if Rails.version >= "7.0"32 config.active_support.cache_format_version = 7.033end3435# ✅ Good — detect the capability directly36if ActiveSupport::Cache.respond_to?(:format_version=)37 config.active_support.cache_format_version = 7.038end39```406. Check optional integrations (jobs, mailers, assets, routes, install generators, dummy-app mounts) per version. State the check even if an integration is absent.417. CI matrix must run against each claimed Rails/Ruby combination:42```yaml43strategy:44 matrix:45 include:46 - { ruby: "3.2", rails: "7.1" }47 - { ruby: "3.3", rails: "7.2" }48```4950## Extended Resources5152- [assets/compatibility_matrix.md](assets/compatibility_matrix.md)53- [assets/zeitwerk_notes.md](assets/zeitwerk_notes.md)54- [EXAMPLES.md](EXAMPLES.md)5556## Output Style57581. State the support matrix being targeted.592. List the most likely breakpoints.603. Make compatibility changes in isolated, testable seams.614. Recommend matrix coverage if it does not exist.625. Include an **Optional integration matrix** with rows for jobs, mailers, assets, routes, generators, and dummy app mount. For each row, state `present/absent`, the file path checked, and the per-version verification command.636. Language — Must be in English unless explicitly requested otherwise.6465## Integration6667| Skill | When to chain |68|-------|----------------|69| test-engine | Test matrix setup, CI configuration, multi-version tests |70| create-engine | Engine structure, host contract, namespace design |71| release-engine | Versioning, changelog, upgrade notes for compatibility changes |