Task Breakdown — RFC Phase 2: Rails 7.2.3.1 → 8.1.3 (Track 2a); Ruby 4.0.5 deferred (Track 2b)
Source RFC: phase-2-rails-8-1-ruby-4-0-upgrade.md
Slicing: Vertical (work-item) — horizontal UI/API phases n/a for an infra upgrade · Blocked
tasks: included inline · Repos: chatbot only (BE/Infra; the asset-pipeline tasks are
FE-flavored work inside the same repo, tagged [FE])
Paths/lines are grounded against the real
chatbottree as of 2026-07-13 — the source RFC's and Phase 1 RFC's already-verified citations, plus a few additional greps run for this breakdown (config/initializers/rails_admin.rb:12,Dockerfile:1/Dockerfile.nonroot:1node image,app/javascript/packs/application.js:7,12,app/views/layouts/{application,login}.html.erb). Nothing invented; unverified items stay flagged[unverified — check repo]. Track 2b (Ruby 4.0.5) is scope-excluded from actionable tasks per the RFC's own "recommend DEFER" stance — see Skipped / deferred below.
Effort Summary
| Wave / stage | BE days | FE days | QA days | Total |
|---|---|---|---|---|
Rails 8.0.5 bump + app:update review (Task 1) | 2 | — | 1 | 3 |
| Gem wave — devise/paper_trail/rspec-rails/searchkick/acts_as_paranoid/grape (Task 2) | 2.5 | — | 1 | 3.5 |
| Sidekiq 8 + Sidekiq Pro 8 (Task 3) | 2 | — | 1 | 3 |
load_defaults 7.2→8.0 stepping (Task 4) | 1.5 | — | 1 | 2.5 |
| 8.0 checkpoint validation (Task 5) | 1 | — | 1.5 | 2.5 |
Rails 8.1.3 bump + load_defaults 8.0→8.1 (Task 6) | 2.5 | — | 1.5 | 4 |
rails_admin-on-8.1 verification spike (Task 7) | 1.5 | — | 0.5 | 2 |
| Asset-pipeline workstream (Tasks 8–9) | — | 6.5 | 2.5 | 9 |
| Final validation, staging bake, canary (Task 10) | 2 | — | 1.5 | 3.5 |
| Grand total | 15 | 6.5 | 11.5 | 33 |
Confidence: medium. Assumptions: (1)
rails_admin(Task 7) passes its Rails 8.1 spike without needing a fork/patch — if it does, add rework; (2) Sidekiq Pro 8 registry/license access resolves favorably (Task 3 is ⚠️ partially blocked on this, not assumed); (3) the asset-pipeline workstream (Tasks 8–9) starts in parallel with/soon after Phase 1 per the RFC's own recommendation, so its effort here assumes that head start, not a cold start mid-Track-2a. Track 2b (Ruby 4.0.5) is fully deferred — no effort estimated this cycle; see Skipped / deferred below.
Tasks (Track 2a, ordered by execution-plan dependency)
Task 1: [BE] Rails 8.0.5 bump PR + app:update review
The app boots on Rails 8.0.5 with
load_defaultsstill at7.2— the same "boot first, flip defaults later" discipline as Phase 1.
Status: ✅ Actionable once Phase 1 lands (Ruby 3.4.10 / Rails 7.2.3.1 / load_defaults 7.2).
Implementation Plan
| Action | File | What changes |
|---|---|---|
| edit | Gemfile:9 | ~> 7.2.3.1 → ~> 8.0.5 |
| n/a (generated) | — | review every app:update diff; consciously decline Propshaft scaffolding if staying on Sprockets |
Implementation steps
- Bump
Gemfile:9,bundle update rails; confirmacts_as_paranoid 0.10.3(from Phase 1) still resolves — its< 8.1ceiling already covers 8.0. - Run
bin/rails app:update; review every generated/changed file, explicitly declining any Propshaft/Solid Queue/Kamal scaffolding (new-app defaults, not forced on this app). - Boot every process type with
load_defaultsunchanged at7.2; run full rspec.
Acceptance criteria
- App boots on Rails 8.0.5 with
load_defaultsunchanged at7.2. -
app:updatediff explicitly reviewed; Propshaft/Solid Queue scaffolding declined, not silently kept. - Full rspec suite green.
Test strategy: Full existing rspec suite + a manual boot smoke per process type.
Effort estimate
| Discipline | Days |
|---|---|
| Backend | 2 |
| QA | 1 |
| Total | 3 |
Sprockets stays supported (no upper Rails cap) — no forced asset-pipeline change in this task.
Run to verify
bundle exec rspec && bin/rails app:update --dry-run
Depends on: Phase 1 complete. Unblocks Tasks 2–4.
Task 2: [BE] Gem wave — devise, paper_trail, rspec-rails, searchkick, acts_as_paranoid, grape check
The remaining Rails-8-line gem blockers land as their own small deploys, same wave-0 discipline as Phase 1.
Status: ✅ Actionable
Implementation Plan
| Action | File | What changes |
|---|---|---|
| edit | Gemfile:130 | devise → ~> 5.0.4 (4.9.x has route-registration failures on 8.1) |
| edit | Gemfile:146 | paper_trail → ~> 17 |
| edit | Gemfile:65 | rspec-rails → ~> 8.0.4 (requires railties >= 7.2) |
| edit | Gemfile:164 | searchkick → ~> 6.1.2 (requires activemodel >= 7.2) |
| edit | Gemfile:109 | acts_as_paranoid → ~> 0.11.0 (ceiling → < 8.2) |
| verify | Gemfile:180 | grape ~> 2.0.0 — confirm 2.4.x (from Phase 1 wave-0) still resolves on Rails 8.1; no bump forced |
Implementation steps
- Bump
devise; re-run Devise routing/controller specs (route-registration is the known 4.9.x failure mode on 8.1). - Bump
paper_trail,rspec-rails,searchkick; re-run their respective spec suites. - Bump
acts_as_paranoidto 0.11.0; confirm the ceiling now covers 8.1 (< 8.2). - Confirm
grape(2.4.x from Phase 1) resolves against Rails 8.1 with no forced 2.x→3.x jump.
Acceptance criteria
- All 5 gems bump cleanly;
grapeconfirmed resolving with no bump needed. - Devise routing specs pass (the specific 4.9.x→8.1 failure mode is closed).
Test strategy: RSpec across spec/models (paper_trail/acts_as_paranoid), Devise
controller/routing specs, searchkick model specs, plus bundle exec rspec (rspec-rails itself).
Effort estimate
| Discipline | Days |
|---|---|
| Backend | 2.5 |
| QA | 1 |
| Total | 3.5 |
QA 1 — devise route/auth behavior is the highest-risk item in this wave.
Run to verify
bundle exec rspec spec/models/ spec/controllers/
Depends on: Task 1 (Rails 8.0.5 booted).
Task 3: [BE] Sidekiq 8 + Sidekiq Pro 8
Background job processing runs on the Sidekiq 8 line required alongside Rails 8.1.
Status: ⚠️ Partially blocked — the sidekiq 8.x bump itself is actionable now; Sidekiq Pro 8's
registry/license access is unconfirmed (open question). Redis server ≥ 7.0 prerequisite is
already met (Sidekiq's Redis is 7.x, stakeholder-confirmed 2026-07-13) — no infra upgrade
needed, only a re-confirm of exact patch version at execution time.
Implementation Plan
| Action | File | What changes |
|---|---|---|
| edit | Gemfile:168 | sidekiq → ~> 8.x |
| edit | Gemfile:172 | sidekiq-pro → 8.x (pending registry/license confirmation) |
| n/a | config/initializers/sidekiq.rb | check Sidekiq::ActiveJob::Wrapper class rename affecting any dashboard/queue query |
Implementation steps
- Confirm
sidekiq-pro8 is available on the team'sgems.contribsys.comregistry access before starting (blocking sub-item — see Depends on). - Bump
sidekiq/sidekiq-pro; re-confirm Redis server patch version + any managed-service constraint (prerequisite itself already satisfied). - Grep for any code/dashboard query referencing the old
Sidekiq::ActiveJob::Wrapperclass name; update for the 8.x rename. - Boot Sidekiq; re-run worker specs; enqueue/process a test job end-to-end.
Acceptance criteria
-
sidekiq 8.x+sidekiq-pro 8.xresolve and boot cleanly. - No dashboard/query breaks on the
Sidekiq::ActiveJob::Wrapperrename. - Worker specs pass; a test job enqueues and processes successfully.
Test strategy: Worker specs + a manual end-to-end job enqueue/process smoke test.
Effort estimate
| Discipline | Days |
|---|---|
| Backend | 2 |
| QA | 1 |
| Total | 3 |
Blocked sub-item (Pro-8 registry access) is a licensing question, not engineering effort — this estimate covers the code-side bump only.
Run to verify
bundle exec rspec spec/workers/
Depends on: Task 1. Blocked on: Sidekiq Pro 8 registry/license confirmation (Open Question 1).
Task 4: [BE] load_defaults stepping — Rails 7.2 → 8.0
The app runs under the full Rails 8.0 default set, generated and reviewed the same way as Phase 1's stepping (the 8.0/8.1 defaults diff isn't centrally published — rely on the generated file).
Status: ✅ Actionable
Implementation Plan
| Action | File | What changes |
|---|---|---|
| create (generated) | config/initializers/new_framework_defaults_8_0.rb | via bin/rails app:update |
| edit | config/application.rb:13 | 7.2 → 8.0 |
Implementation steps
- Generate the file via
app:update; review its settings (no centrally-published diff to compare against — the file itself is the source of truth). - Uncomment, deploy with defaults still
7.2to check load, then flip to8.0; deploy. - Monitor the same class of mixed-version-pod cache/cookie risk as every prior defaults step.
Acceptance criteria
- File generated, reviewed, fully active;
load_defaults 8.0deploys cleanly. - Full rspec suite green.
Test strategy: Full rspec suite + rolling-deploy monitoring, same discipline as Phase 1.
Effort estimate
| Discipline | Days |
|---|---|
| Backend | 1.5 |
| QA | 1 |
| Total | 2.5 |
Assumes no surprise breaking default in the generated file.
Run to verify
bundle exec rspec
Depends on: Task 1. Blocks Task 5.
Task 5: [BE] 8.0 checkpoint validation
Rails 8.0.5 is fully validated as a short, deliberate checkpoint before proceeding to 8.1 — the "compress the gap" step from the RFC's direct-jump assessment, not a resting stop.
Status: ✅ Actionable
Implementation Plan
| Action | File | What changes |
|---|---|---|
| n/a | — | validation only — full rspec, boot smoke, staging soak on Rails 8.0.5 |
Implementation steps
- Run the full rspec suite on the Rails 8.0.5 /
load_defaults 8.0branch. - Boot-smoke every process type (Puma, Sidekiq, Karafka, console, cron, migration job).
- Brief staging soak — confirm no regression before starting the 8.1 bump (Task 6).
Acceptance criteria
- Full rspec suite green; every process type boots cleanly on 8.0.5.
- Staging soak passes with no open regression before Task 6 starts.
Test strategy: Full rspec suite + staging soak checklist, deliberately brief (checkpoint, not a resting stop).
Effort estimate
| Discipline | Days |
|---|---|
| Backend | 1 |
| QA | 1.5 |
| Total | 2.5 |
QA-heavy relative to BE — this task is pure validation, no code change.
Run to verify
bundle exec rspec && bundle exec karafka console
Depends on: Tasks 2, 3, 4 landed. Blocks Task 6.
Task 6: [BE] Rails 8.1.3 bump PR + load_defaults 8.0 → 8.1 stepping
The app boots on Rails 8.1.3 with defaults fully stepped to
8.1— the stable landing point with security runway to 2027-10-10.
Status: ✅ Actionable
Implementation Plan
| Action | File | What changes |
|---|---|---|
| edit | Gemfile:9 | ~> 8.0.5 → ~> 8.1.3 |
| n/a (generated) | — | review app:update diff again |
| create (generated) | config/initializers/new_framework_defaults_8_1.rb | via app:update |
| edit | config/application.rb:13 | 8.0 → 8.1 |
Implementation steps
- Bump
Gemfile:9,bundle update rails; runapp:update, review the diff. - Note:
schema.rbcolumns are now dumped alphabetically as of 8.1 — expect a large, purely cosmetic one-time diff; review it explicitly so a real change isn't hidden inside the noise. - Generate/review/uncomment
new_framework_defaults_8_1.rb; deploy with defaults at8.0first, then flip to8.1. - Full rspec + per-process boot checks.
Acceptance criteria
- App boots on Rails 8.1.3 with
load_defaultsfully at8.1. - The
schema.rbalphabetical-column diff is reviewed and confirmed cosmetic-only. - Full rspec suite green.
Test strategy: Full rspec suite + a manual schema-diff review + per-process boot checks.
Effort estimate
| Discipline | Days |
|---|---|
| Backend | 2.5 |
| QA | 1.5 |
| Total | 4 |
The largest single-task effort in Track 2a — two framework bumps' worth of review compressed together (version + defaults).
Run to verify
bundle exec rspec && bin/rails app:update --dry-run
Depends on: Task 5 (8.0 checkpoint passed). Unblocks Task 7, Task 10.
Task 7: [BE] rails_admin-on-8.1 verification spike
Confirms
rails_admin3.3.0 (gemspec allowsrails >= 6.0, < 9, but Rails 8.1 is not blessed upstream) actually works on Rails 8.1 before relying on it in production.
Status: ✅ Actionable as a spike — not blessed upstream, so treat as a verification task, not an assumption.
Implementation Plan
| Action | File | What changes |
|---|---|---|
| verify | config/initializers/rails_admin.rb:12 | admin UI boots/functions on Rails 8.1 with config.asset_source = :webpacker (or its Task 8/9 successor) |
Implementation steps
- Boot the admin UI on the Rails 8.1.3 branch; exercise CRUD on a representative model.
- Confirm
config.asset_source(currently:webpacker,config/initializers/rails_admin.rb:12) still resolves assets correctly — coordinate timing with Tasks 8–9's asset-pipeline migration. - If it fails: assess whether a fork/patch is needed, or whether the asset-pipeline migration (Tasks 8–9) must land first to unblock it.
Acceptance criteria
-
rails_adminboots and CRUDs correctly on Rails 8.1.3. - Outcome documented: works as-is, needs a fork/patch, or is blocked on the asset-pipeline migration.
Test strategy: Manual functional spike against a representative model in the admin UI — no
existing automated coverage for rails_admin itself.
Effort estimate
| Discipline | Days |
|---|---|
| Backend | 1.5 |
| QA | 0.5 |
| Total | 2 |
Spike, not a full build — effort covers the investigation, not a fix if one turns out needed.
Run to verify
bundle exec rails server # manually exercise /admin
Depends on: Task 6. Coordinate with Tasks 8–9 (asset_source coupling).
Task 8: [FE] Webpacker → shakapacker migration + Node 16 image bump
The JS build pipeline runs on a maintained successor to the retired Webpacker 5, on a supported Node line.
Status: ✅ Actionable — the highest-effort item of Track 2a; should start during/right after Phase 1, not be squeezed into this phase's tail.
Implementation Plan
| Action | File | What changes |
|---|---|---|
| edit | Gemfile (webpacker line) | webpacker ~> 5.0 → shakapacker (latest) |
| edit | config/webpacker.yml | migrate to config/shakapacker.yml per shakapacker's config-rename guide |
| edit | Dockerfile:1, Dockerfile.nonroot:1 | node:16-alpine → a maintained Node LTS (Node 16 is itself EOL) |
| edit | Dockerfile:68-69, Dockerfile.nonroot:95-96 | webpacker:compile → shakapacker:compile in the build stages |
Implementation steps
- Add
shakapacker, run its install generator, migrateconfig/webpacker.yml→shakapacker.ymlper the official webpacker→shakapacker guide. - Bump the Node base image in both
DockerfileandDockerfile.nonroot(andDockerfile.develop, already Phase-1-fixed for Ruby) past Node 16's EOL. - Update both Dockerfiles' asset-compile build steps from
webpacker:compiletoshakapacker:compile. - Confirm Task 1 (Phase 1)'s CI asset-precompile gate still passes against the new pipeline.
Acceptance criteria
-
shakapackerreplaceswebpacker; asset compile succeeds in both Dockerfiles. - Node base image is on a maintained LTS line, not Node 16.
- Visual/functional parity confirmed on the main app layouts.
Test strategy: CI asset-precompile gate (from Phase 1) + a manual visual regression pass on the main app's rendered pages.
Effort estimate
| Discipline | Days |
|---|---|
| Frontend | 4 |
| QA | 1.5 |
| Total | 5.5 |
Highest-effort single item in Track 2a per the RFC's own framing; assumes shakapacker's official migration guide covers this app's webpacker config without a custom escape hatch.
Run to verify
bin/shakapacker:compile
Depends on: Phase 1's asset-precompile CI gate. Can start in parallel with/after Phase 1.
Task 9: [FE] Turbolinks → turbo-rails consolidation + rails_admin asset_source switch
One Hotwire/Turbo stack across the app instead of two competing systems (legacy Turbolinks in the main layouts,
turbo-railsalready pulled in transitively byrails_admin).
Status: ✅ Actionable
Implementation Plan
| Action | File | What changes |
|---|---|---|
| edit | app/javascript/packs/application.js:7,12 | remove import Turbolinks / Turbolinks.start(), wire Turbo instead |
| edit | app/views/layouts/application.html.erb:9-10, app/views/layouts/login.html.erb:10-12 | data-turbolinks-track → data-turbo-track |
| edit | config/initializers/rails_admin.rb:12 | config.asset_source = :webpacker → the shakapacker-compatible value from Task 8 |
Implementation steps
- Remove the Turbolinks import/start calls in
application.js; addturbo-rails's JS entry point. - Update both layout ERBs'
data-turbolinks-trackattributes todata-turbo-track. - Switch
rails_admin.rb:12'sasset_sourceto match whatever Task 8 lands (shakapacker), so the admin UI doesn't break independently of the main app. - Manually regression-test navigation (page-transition behavior) across both the main app and
rails_admin.
Acceptance criteria
-
turbolinksis removed from the app's own JS entry point; onlyturbo-railsremains. - Both layout ERBs use
data-turbo-track. -
rails_admin'sasset_sourcematches the Task 8 pipeline; admin UI still renders correctly.
Test strategy: Manual navigation/page-transition regression pass on the main app and the admin UI; no existing automated FE test coverage for this path.
Effort estimate
| Discipline | Days |
|---|---|
| Frontend | 2.5 |
| QA | 1 |
| Total | 3.5 |
Assumes
turbo-rails's already-resolved version (2.0.16, pulled in viarails_admin) is sufficient — no separate gem bump needed, just wiring.
Run to verify
bin/shakapacker:compile && bundle exec rails server # manual navigation check
Depends on: Task 8 (asset pipeline must be shakapacker before rewiring asset_source).
Coordinate with Task 7 (rails_admin spike).
Task 10: [BE/Infra] Final validation, staging bake, canary rollout (Track 2a)
Track 2a is validated end-to-end on Rails 8.1.3 and rolled out gradually across both deployment targets, closing the promptly-scheduled part of Phase 2.
Status: ✅ Actionable, gated on all prior Track 2a tasks.
Implementation Plan
| Action | File | What changes |
|---|---|---|
| n/a | deploy/, deploy-alicloud/ | staged canary, one target first, then the other |
Implementation steps
- Full rspec suite on the complete Track 2a branch (Rails 8.1.3,
load_defaults 8.1, shakapacker, turbo-rails); boot-smoke every process type. - Staging soak: Karafka consumer,
sidekiq-cronschedules, Datadog traces, confirmed Sidekiq-8 Redis connectivity, asset-pipeline visual/functional parity (main app +rails_admin), and therails_admin-on-8.1 spike result (Task 7) recorded. - Canary one deployment target, monitor, then the second.
Acceptance criteria
- Full rspec suite green; every process type boots cleanly on the complete Track 2a branch.
- Staging soak passes on all items in Step 2; canary succeeds on both AWS and Alicloud, staged.
Test strategy: Full rspec suite + manual staging soak checklist + a staged production canary with monitoring before full rollout.
Effort estimate
| Discipline | Days |
|---|---|
| Backend/Infra | 2 |
| QA | 1.5 |
| Total | 3.5 |
Single point validating all 9 prior tasks' outputs together for the first time.
Run to verify
bundle exec rspec && bundle exec karafka console
Depends on: All prior tasks (1–9).
Ordering rationale
- Track 2a follows the RFC's own numbered execution plan: Rails 8.0.5 bumps first (Task 1,
compatible with Phase 1's
acts_as_paranoid 0.10.3ceiling), then the gem wave (Task 2) and Sidekiq 8 (Task 3) land on the 8.0 base, then defaults step to 8.0 (Task 4), then the 8.0 checkpoint (Task 5) gates the 8.1 bump (Task 6) — this is the "compress the gap, don't skip the checkpoint" structure from the RFC's direct-jump assessment. - The asset-pipeline workstream (Tasks 8–9) is the one item that should start early, in parallel with Phase 1's tail, despite appearing later in the RFC's own execution-plan numbering — it's independent of the pure Rails version bumps and is explicitly called out as the highest-effort, FE-touching item that shouldn't be squeezed into this phase's end.
- Task 3 (Sidekiq 8) is ⚠️ partially blocked on Sidekiq Pro 8 registry/license access — push on that confirmation in parallel with Tasks 1–2 so it doesn't stall Task 4's defaults stepping.
- Task 7 (
rails_adminspike) and Tasks 8–9 (asset pipeline) are coupled viaasset_source— sequence Task 7's final confirmation after Task 8 lands, not before. - Task 10 (final validation/canary) depends on everything — nothing in Track 2a skips its own per-step validation on the way there.
Skipped / deferred
Track 2b (Ruby 3.4.10 → 4.0.5) is fully deferred per the RFC's own "recommend DEFER" stance — Ruby 3.4 has runway to 2028-03-31, and Rails 8.1 must land before Ruby 4.0 is viable regardless of sequencing. No Track 2b items are actionable tasks in this breakdown; they are summarized below and revisited as their own bucket story around 2027-Q1 (RFC Open Question 5).
| Item | Status | Unblocking condition |
|---|---|---|
Spike: dry-rails, seed_migration, amoeba, gon, clean-architecture, aliyun-sdk, rest-client, wit, byebug against Ruby 4.0 | Deferred | Track 2b scheduling decision (RFC Open Question 4/5) |
Re-run bundled-gem require grep for the 4.0-specific list (ostruct, pstore, benchmark, logger, rdoc, win32ole, irb) | Deferred | Track 2b scheduling; note lib/http.rb:153,155,157's missing require 'ostruct' is a known latent hazard already — fix no later than Track 2b, earlier if Task 3/Phase-1's pigeon-http fallback makes lib/http.rb the WitAi::AppV2 replacement |
Native-extension recompile surface (pg, nokogiri, google-protobuf, ffi, msgpack, sassc, karafka-rdkafka, bcrypt_pbkdf, ed25519, Datadog native libs) | Deferred | Track 2b scheduling |
Set core-class change vs. config/initializers/system.rb's clean-architecture/athens monkey-patches | Deferred | Track 2b scheduling |
Ruby .ruby-version/Gemfile/Dockerfiles/CI image bump to 4.0.5 | Deferred | Track 2b scheduling |
| Full validation + staging bake + canary for Ruby 4.0.5 | Deferred | Track 2b scheduling |
Note: Redis server ≥ 7.0 (Task 3 prerequisite) is not a deferred item — it is already met, stakeholder-confirmed 2026-07-13. The app's separate cache/app Redis (6.0, itself an EOL line) is also out of scope for both Phase 1 and Phase 2 — flagged as a candidate for its own future bucket story, not a Track 2a/2b task.