Skip to main content

Task Breakdown — RFC Phase 1: Ruby 3.2.2 → 3.4.10 + Rails 7.1.3.2 → 7.2.3.1

Source RFC: phase-1-ruby-3-4-rails-7-2-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)

Paths/lines are grounded against the real chatbot tree as of 2026-07-13 — the source RFC's already-verified citations, plus a few additional greps run for this breakdown (Gemfile gem-declaration lines, lib/wit_ai/app_v2.rb, lib/pigeon_http.rb, lib/http.rb, .rubocop.yml, karafka.rb, app/models/intent.rb). Nothing invented; unverified items stay flagged [unverified — check repo].

Effort Summary

Wave / stageBE daysFE daysQA daysTotal
Wave 0 — Bundler reconciliation + acts_as_paranoid (Tasks 1–2)1.50.52
Wave 0 — ddtracedatadog migration (Task 3)314
Wave 0 — toolchain & dep housekeeping: sidekiq/rack-cors/webdrivers/rubocop/grape (Task 4)30.53.5
Wave 0 — karafka 2.2→2.5 chain (Task 5)314
CI gates before framework bump (Task 6)20.52.5
Enum modernization — 46 declarations (Task 7)314
Rails 7.2.3.1 bump + load_defaults stepping (Tasks 8–11)6.5410.5
Ruby 3.4.10 bump (Task 12)213
aegis compatibility spike (Task 13)1.50.52
Staging bake + dual-cloud canary (Task 14)21.53.5
Grand total27.511.539

Confidence: medium. Assumptions: (1) Task 3 lands on its preferred path (owner re-releases pigeon-http dropping the unused ddtrace dep); if the decided removal fallback triggers instead, add ~1 BE day to port lib/wit_ai/app_v2.rb's 5 call sites to lib/http.rb (not in this total — see Task 3); (2) the enum conversion (Task 7) is mechanical, no hidden 7.2 enum behavior beyond syntax; (3) three open questions (sidekiq-pro registry access, Datadog profiling parity, webpacker boot-on-7.2) are not assumed resolved — an unfavorable answer could add rework; (4) Task 4's grape 2.0→2.4 bump (+0.5 BE day) is assumed to be a clean, non-breaking bump per the RFC's own gem-waves table — Phase 2's gem wave explicitly depends on this having landed here.


Tasks (ordered by execution-plan dependency)

Task 1: [BE] Bundler version reconciliation

One consistent Bundler version across the lockfile, 3 Dockerfiles, and 6 CI lines.

Status: ✅ Actionable

Implementation Plan

ActionFileWhat changes
editGemfile.lock:942-943BUNDLED WITH → target version (e.g. 2.5.x)
editDockerfile:32, Dockerfile.develop:6, Dockerfile.nonroot:42ENV BUNDLE_VERSION → target (keep nonroot's = form)
editbitbucket-pipelines.yml:26,50,67,296,344,359gem install bundler -v → target, all 6 occurrences

Implementation steps

  1. Pick a target version; confirm Gemfile.lock resolves under it locally.
  2. Edit all 3 Dockerfiles + all 6 CI lines + the lockfile footer.
  3. bundle install locally, push, confirm CI green.

Acceptance criteria

  • All 3 Dockerfiles, the lockfile, and all 6 CI lines agree on one Bundler version.
  • bundle check passes locally and in CI.

Test strategy: Green full CI run (build+lint+rspec); no app-level spec needed.

Effort estimate

DisciplineDays
Backend/Infra0.5
QA0
Total0.5

Pure toolchain edit, no user behavior — QA 0.

Run to verify

bundle install && bundle check

Depends on: None. First task.


Task 2: [BE] acts_as_paranoid 0.9.0 → 0.10.3

Lifts the hard activerecord < 7.2 ceiling blocking the Rails 7.2 bump.

Status: ✅ Actionable

Implementation Plan

ActionFileWhat changes
editGemfile:109pin ~> 0.10.3
n/aGemfile.lock:105-107ceiling relaxes to >= 6.1, < 8.1

Implementation steps

  1. Bump the pin, bundle update acts_as_paranoid, confirm the ceiling relaxes.
  2. Re-run every soft-delete model spec (with_deleted, only_deleted, paranoia_destroy).
  3. Check the 0.9.0→0.10.3 changelog for a renamed scope/config.

Acceptance criteria

  • acts_as_paranoid 0.10.3 resolves with no AR/AS ceiling conflict.
  • All soft-delete model specs pass unchanged.

Test strategy: RSpec model specs asserting soft-delete/restore scopes unchanged.

Effort estimate

DisciplineDays
Backend1
QA0.5
Total1.5

QA 0.5 — soft delete affects data visibility, not a pure refactor.

Run to verify

bundle exec rspec spec/models/ && bundle exec rubocop

Depends on: None. Unblocks Task 8 (Rails 7.2 bump — hard resolution blocker).


Task 3: [BE] ddtracedatadog 2.x migration + google-protobuf unpin

Datadog APM/profiling keeps working on a gem line that actually runs on Ruby 3.4 (ddtrace 1.x caps at Ruby 3.3).

Status: ⚠️ Partially blocked — the migration itself is actionable now. Only pigeon.gemspec:38 (unconstrained, unused ddtrace dep) is externally gated. Preferred: owner re-releases pigeon-http dropping it. Decided fallback (2026-07-13): remove pigeon-http, port its 5 lib/wit_ai/app_v2.rb call sites to lib/http.rb (Step 4 below).

Implementation Plan

ActionFileWhat changes
editGemfile:200ddtracegem 'datadog', '~> 2.37'
editGemfile:204drop google-protobuf ~>3.19 pin once no longer needed
editconfig/initializers/datadog.rbrewrite Datadog.configure to the 2.x namespaced API
edit (fallback only)lib/wit_ai/app_v2.rbswap PigeonHttpHttp at lines 22/31/36/42/47; append get_all's query params to the URL string (Http#call has no query: kwarg)

Implementation steps

  1. Bump to datadog ~> 2.37; rewrite config/initializers/datadog.rb's configure block.
  2. Drop the google-protobuf pin; confirm nothing else needs it.
  3. If the re-release lands: bump pigeon-http, confirm ddtrace is gone from Gemfile.lock.
  4. If the fallback triggers: replace PigeonHttp with Http in lib/wit_ai/app_v2.rb (5 call sites), write new specs (zero existing coverage today), delete lib/pigeon_http.rb.
  5. Validate Datadog trace/profiling parity in staging.

Acceptance criteria

  • Gemfile.lock has no ddtrace, resolves cleanly.
  • Datadog traces/APM appear in staging with equivalent tags.
  • (if fallback) All 5 WitAi::AppV2 methods pass new specs against Http.

Test strategy: Boot spec for the Datadog initializer; (fallback only) new request specs for WitAi::AppV2 against a stubbed Net::HTTP.

Effort estimate

DisciplineDays
Backend3
QA1
Total4

Assumes the preferred path lands. If the fallback triggers, add ~1 BE day (not in the Effort Summary grand total — track separately).

Run to verify

bundle exec rspec spec/lib/wit_ai/ && bundle exec rubocop

Depends on: None to start. Blocks Task 12 (Ruby 3.4 bump).


Task 4: [BE] Wave-0 toolchain & dependency housekeeping (sidekiq, rack-cors, webdrivers, rubocop, grape)

Five small, independent wave-0 items land as mechanical Gemfile/config bumps before the framework moves.

Status: ✅ Actionable

Implementation Plan

ActionFileWhat changes
editGemfile:168sidekiq~> 7.3.10 (Ruby 3.4 forward-compat fixes; sidekiq-pro's <8 ceiling already satisfied)
editGemfile:190rack-cors~> 2.0 (Rack-3-safe header casing)
edit/deleteGemfile:32, Gemfile:38bump selenium-webdriver past 4.11; delete webdrivers (archived)
editGemfile:83,85, .rubocop.yml:6rubocop>= 1.88, drop rubocop-performance 1.9.2 ceiling, TargetRubyVersion3.4
editGemfile:180gem 'grape', '~> 2.0.0''~> 2.4' (Rack 3 / Ruby 3.4 currency); grape-swagger/grape-entity stay at their currently-resolved versions this wave — no compatibility issue flagged for them

Implementation steps

  1. Bump sidekiq; boot Sidekiq locally, re-run spec/workers/.
  2. Bump rack-cors; re-run CORS request specs, confirm header casing.
  3. Remove webdrivers, bump selenium-webdriver; confirm system specs launch via Selenium Manager.
  4. Bump rubocop/drop the performance-gem ceiling, fix .rubocop.yml:6; triage the new-offense delta from raising TargetRubyVersion (no blanket cop disables).
  5. Bump grape to ~> 2.4, bundle update grape, and run the API specs under spec/api/ covering the Grape surfaces (frontend_service, internal_service, etc.) to confirm no route/serializer regression from the 2.0→2.4 jump.

Acceptance criteria

  • sidekiq 7.3.10 + sidekiq-pro 7.2.1 resolve together; worker specs pass.
  • CORS headers correctly cased; webdrivers removed; system specs still launch a browser.
  • rubocop parses Ruby 3.4 syntax; .rubocop.yml:6 reads 3.4; CI lint step green.
  • grape 2.4.x resolves cleanly alongside grape-swagger/grape-entity unchanged; all spec/api/ specs pass.

Test strategy: Worker specs + CORS request specs + a manual Selenium boot + the full spec/api/ suite (Grape route/serializer coverage) + bundle exec rubocop as its own gate.

Effort estimate

DisciplineDays
Backend3
QA0.5
Total3.5

QA 0.5 covers only the CORS behavioral check; the other four (incl. grape) are mechanical version bumps validated by existing specs. +0.5 BE day added for the grape 2.0→2.4 bump (bundle update + running the spec/api/ surface) versus the original four-item estimate.

Run to verify

bundle exec rspec spec/workers/ spec/requests/ spec/api/ && bundle exec rubocop

Depends on: None. Should land before Task 12 (rubocop must parse the new syntax at the Ruby bump); grape 2.4.x is also assumed already landed by Phase 2's Task 2 (its grape line explicitly depends on this bump having happened here).


Task 5: [BE] karafka 2.2 → 2.5 sequential chain + karafka-web → 0.11

The Kafka consumer runs on a supported Karafka line, stepped through each mandated minor.

Status: ✅ Actionable — must run as its own multi-step sub-sequence, not one combined bump.

Implementation Plan

ActionFileWhat changes
editGemfile:215karafka steps ~>2.2~>2.3~>2.4~>2.5, one deploy each
editGemfile:217karafka-web~> 0.11 (last, after the chain)
n/akarafka.rbre-check `setup do

Implementation steps

  1. Bump to ~>2.3 first (rebuilds karafka-rdkafka's native ext); boot the consumer, re-run specs.
  2. Repeat 2.3→2.4→2.5 as separate deploys, per Karafka's own per-minor upgrade docs.
  3. Bump karafka-web to 0.11 last; confirm the dashboard boots against the final Karafka version.

Acceptance criteria

  • Each of the 3 minor steps lands as its own deploy with a clean consumer boot.
  • karafka-web 0.11 dashboard loads; chatbot_incoming_message topic consumes correctly.

Test strategy: Manual consumer boot smoke per step (no existing CI coverage — Task 6 starts closing that gap) + any consumer specs under spec/.

Effort estimate

DisciplineDays
Backend3
QA1
Total4

Assumes no librdkafka ABI issue surfaces mid-chain (would add time if one does).

Run to verify

bundle exec karafka console

Depends on: None. Should land before Task 6's Karafka boot-smoke CI gate targets the final (2.5.x) consumer.


Task 6: [BE/Infra] CI gates before the framework bump

The pipeline catches an asset-compile break, a Karafka boot failure, or a per-process boot regression before the Rails/Ruby bump PRs land — today it catches none of these.

Status: ✅ Actionable

Implementation Plan

ActionFileWhat changes
editbitbucket-pipelines.ymlnew step: webpacker:compile && assets:precompile
editbitbucket-pipelines.ymlnew step: Karafka boot smoke against a test topic
editbitbucket-pipelines.ymlnew step(s): boot Puma/Sidekiq/console + assert the config/application.rb:41-79 Vault-unreachable fail-open path doesn't crash any process

Implementation steps

  1. Add the asset-precompile step; sanity-check it fails on a deliberately-broken webpacker config.
  2. Add a Karafka boot-smoke step (process starts, exits 0, against a disposable test topic).
  3. Add per-process boot checks (Puma, Sidekiq, console, sidekiq-cron schedule load) plus a Vault-unreachable assertion (point Vault config at an unreachable host, confirm fail-open boot).
  4. Document whether update_automation_result.rb's bare-ruby CI invocation loads the Rails env (currently unverified).

Acceptance criteria

  • CI fails when asset compilation is deliberately broken (gate is real).
  • CI boots the Karafka consumer + every process type and asserts the Vault-unreachable path doesn't crash any of them.
  • update_automation_result.rb's Rails-env-loading status is documented.

Test strategy: Pipeline steps verified red→green by deliberately breaking then fixing each gate.

Effort estimate

DisciplineDays
Backend/Infra2
QA0.5
Total2.5

Assumes Bitbucket Pipelines' existing service containers (Kafka/Redis/Postgres) suffice.

Run to verify

git push # inspect the new bitbucket-pipelines.yml steps

Depends on: None. Should land before Task 8 (Rails 7.2 bump PR).


Task 7: [BE] Enum-syntax modernization — 46 declarations

Every app/models/ enum uses the Rails 7.0+ positional syntax, checked against the Rails 7.2 changelog before the framework bump.

Status: ✅ Actionable

Implementation Plan

ActionFileWhat changes
editapp/models/intent.rb:73-764 declarations → positional form
editapp/models/path.rb:58,63, app/models/response.rb:53-55, app/models/attachment.rb:52-537 more declarations
editremaining app/models/*.rbremaining ~35 (full list: grep -rnE '^\s*enum\b' app/models/)

Implementation steps

  1. Run the grep for the full current 46-line list.
  2. Convert each to enum :column, {...}, suffix:, prefix: positional form, one file at a time, running that model's spec after each.
  3. Cross-check the Rails 7.2 enum changelog for any semantic (not just syntax) change.

Acceptance criteria

  • Zero remaining legacy hash-argument enum declarations.
  • All model specs pass unchanged (values/scopes/predicates identical).

Test strategy: RSpec model specs asserting enum scopes/predicates resolve to the same values.

Effort estimate

DisciplineDays
Backend3
QA1
Total4

QA 1 — a missed case fails silently as a wrong enum mapping (data-correctness risk), not a boot error; warrants a manual spot-check pass.

Run to verify

bundle exec rspec spec/models/ && bundle exec rubocop app/models/

Depends on: None. Should land before Task 8 (re-verified against the 7.2 changelog at bump time).


Task 8: [BE] Rails 7.2.3.1 bump PR + app:update review

The app boots on Rails 7.2.3.1 with load_defaults still at 6.1 — isolating "does it boot" from "does it behave under new defaults."

Status: ✅ Actionable, gated on Tasks 2, 6, 7.

Implementation Plan

ActionFileWhat changes
editGemfile:9~> 7.1.3.2~> 7.2.3.1
n/aconfig/application.rb:13unchanged this task — stays 6.1
n/a (generated)review every bin/rails app:update diff explicitly

Implementation steps

  1. Bump Gemfile:9, bundle update rails (requires Task 2 landed first).
  2. Run bin/rails app:update; review every generated/changed file — no blanket-accept.
  3. Boot every process type with load_defaults unchanged; re-verify the 46 enums; run full rspec.

Acceptance criteria

  • App boots on 7.2.3.1 with load_defaults unchanged at 6.1.
  • Every app:update diff explicitly reviewed (accepted or rejected, not blanket).
  • Full rspec suite green.

Test strategy: Full existing rspec suite + a manual boot smoke per process type.

Effort estimate

DisciplineDays
Backend2
QA1
Total3

Framework bumps carry regression risk even with defaults unchanged, hence QA 1.

Run to verify

bundle exec rspec && bin/rails app:update --dry-run

Depends on: Task 2, Task 6, Task 7. Unblocks Tasks 9–11.


Task 9: [BE] load_defaults step 1 — Rails 7.0 defaults

The app runs under the full Rails 7.0 default set (not the partial hand-applied hybrid it has today), as its own revertible deploy.

Status: ✅ Actionable

Implementation Plan

ActionFileWhat changes
editconfig/initializers/new_framework_defaults_7_0.rbuncomment the remaining 6 of 19 settings
editconfig/application.rb:136.17.0

Implementation steps

  1. Uncomment the remaining settings; deploy with load_defaults still 6.1 to check the file loads.
  2. Flip to 7.0; deploy; monitor the SHA-256 key generator (encrypted cookies/message verifiers) and cache_format_version moving to the 7.0 format through the rolling-deploy window.

Acceptance criteria

  • All 19 settings active; load_defaults 7.0 deploys cleanly, no cookie/session error spike.
  • Full rspec suite green at this defaults level.

Test strategy: Full rspec suite + a staging soak watching cookie/session error rates during the rolling deploy (mixed-version pods).

Effort estimate

DisciplineDays
Backend1.5
QA1
Total2.5

cookies_serializer is already :json — lower risk than a fresh app.

Run to verify

bundle exec rspec

Depends on: Task 8. Blocks Task 10.


Task 10: [BE] load_defaults step 2 — Rails 7.1 defaults

The app runs under the full Rails 7.1 default set — currently 100% dead/commented documentation.

Status: ✅ Actionable

Implementation Plan

ActionFileWhat changes
editconfig/initializers/new_framework_defaults_7_1.rbuncomment all 284 lines' settings
editconfig/application.rb:137.07.1

Implementation steps

  1. Uncomment all settings; confirm active_record.encryption.hash_digest_class is a no-op (no Rails-native encrypts usage anywhere — encryption here is via lockbox).
  2. Flip to 7.1; deploy; monitor to_time_preserves_timezone, the message-serializer default move, and the cache serializer default through the rollout.

Acceptance criteria

  • All settings active; load_defaults 7.1 deploys cleanly.
  • Full rspec suite green at this defaults level.

Test strategy: Full rspec suite + staging soak watching for to_time/serializer regressions.

Effort estimate

DisciplineDays
Backend1.5
QA1
Total2.5

hash_digest_class no-op already grep-confirmed.

Run to verify

bundle exec rspec

Depends on: Task 9. Blocks Task 11.


Task 11: [BE] load_defaults step 3 — Rails 7.2 defaults (generated)

The app runs under the full Rails 7.2 default set — the final defaults-stepping deploy, matching Phase 2's stated starting point.

Status: ✅ Actionable

Implementation Plan

ActionFileWhat changes
create (generated)config/initializers/new_framework_defaults_7_2.rbvia bin/rails app:update
editconfig/application.rb:137.17.2

Implementation steps

  1. Generate the file via app:update; review its settings (not exhaustively published upstream).
  2. Uncomment, deploy with defaults still 7.1 to check load, then flip to 7.2; deploy.

Acceptance criteria

  • File generated, reviewed, fully active; load_defaults 7.2 deploys cleanly.
  • Full rspec suite green — app now matches Phase 2's starting point.

Test strategy: Full rspec suite + the same rolling-deploy monitoring as Tasks 9–10.

Effort estimate

DisciplineDays
Backend1.5
QA1
Total2.5

Assumes no surprise breaking default in the generated file.

Run to verify

bundle exec rspec

Depends on: Task 10.


Task 12: [BE/Infra] Ruby 3.2.2 → 3.4.10 bump PR

The app runs on Ruby 3.4.10 across every pin — including fixing Dockerfile.develop's pre-existing stale-minor defect.

Status: ✅ Actionable, gated on Task 3 (ddtracedatadog complete) and Task 4 (lint toolchain ready).

Implementation Plan

ActionFileWhat changes
edit.ruby-version:1, Gemfile:63.2.23.4.10
editDockerfile:1-2,21, Dockerfile.nonroot:1-2,23,42ruby:3.2.2-alpineruby:3.4.10-alpine
editDockerfile.develop:1,52ruby:3.1.0-alpineruby:3.4.10-alpinefixes the pre-existing defect, not just re-pins it
editbitbucket-pipelines.yml:1ruby:3.2.2ruby:3.4.10

Implementation steps

  1. Confirm Task 3 has fully landed (no ddtrace in Gemfile.lock).
  2. Bump .ruby-version/Gemfile:6; bundle install under Ruby 3.4.10 locally.
  3. Re-run the bundled-gem require grep (base64/csv/mutex_m/drb/observer/getoptlong/ rinda/syslog/abbrev) as a post-bump check — confirm no LoadError.
  4. Bump all 3 Dockerfiles + CI image in the same PR; re-pin debase-ruby_core_source if still needed.

Acceptance criteria

  • All 7 Ruby-version locations agree on 3.4.10, including Dockerfile.develop.
  • Post-bump bundled-gem grep shows zero LoadError risk; full rspec + boot checks green.

Test strategy: Full rspec suite under Ruby 3.4.10 + Task 6's new CI gates, exercised for the first time against the new Ruby version.

Effort estimate

DisciplineDays
Backend/Infra2
QA1
Total3

Assumes no native-ext gem (pg/nokogiri/ffi/msgpack/sassc/karafka-rdkafka) fails to compile against Ruby 3.4's ABI.

Run to verify

bundle exec rspec && bundle exec rubocop

Depends on: Task 3, Task 4, Task 11 (per the RFC's own execution-plan order — Ruby moves after defaults settle, not alongside).


Task 13: [BE] aegis Rails-7.2/Ruby-3.4 boot spike (with detach fallback)

Confirms the source-audited "compatible-as-is" assessment on a real running branch, with a decided fallback if either residual check fails.

Status: ✅ Actionable as a spike (source-audited compatible-as-is, medium-high confidence). This is a decision gate, not a code change: if either check fails, the decided fallback (2026-07-13) is to temporarily detach aegis.

Implementation Plan

ActionFileWhat changes
verifyconfig/initializers/aegis.rb:21Aegis.replace_rails_logger! boots; #tagged stays a no-op (not a raise) against config.log_tags = [:request_id]
verifyconfig/initializers/sidekiq.rb:34-37,50-53client/server middleware chain still wraps jobs
edit (fallback only)config/initializers/aegis.rb, config/initializers/sidekiq.rb, config/application.rb:17comment out aegis requires/wiring

Implementation steps

  1. Boot the app on Ruby 3.4/Rails 7.2; confirm Rails.logger is Aegis::Logger, no crash.
  2. Send a tagged request; confirm the tag is silently absent (expected today) — not an exception.
  3. Boot Sidekiq, enqueue a test job, confirm both patch classes fire without error.
  4. If either check fails: comment out aegis's requires/wiring — but first confirm no other log path (lograge, Rails' default logger, filter_parameter_logging.rb) is relied on for PII masking, since that's a data-protection control, not pure observability.

Acceptance criteria

  • App boots with Aegis::Logger active, no crash; #tagged behavior observed and documented.
  • Sidekiq middleware chain confirmed still wrapping jobs.
  • (if fallback) No other log path relied on for PII masking before detaching.

Test strategy: Manual boot + request/job smoke on the real upgrade branch — not settleable by static reading alone.

Effort estimate

DisciplineDays
Backend1.5
QA0.5
Total2

Assumes the spike passes on the attached path; the detach itself is a small config change if not.

Run to verify

bundle exec rails runner "Rails.logger.tagged('req-1') { Rails.logger.info('test') }"

Depends on: Task 12. Feeds Task 14.


Task 14: [BE/Infra] Staging bake + dual-cloud canary rollout

Phase 1 is validated end-to-end and rolled out gradually across both deployment targets, closing the phase.

Status: ✅ Actionable, gated on all prior tasks.

Implementation Plan

ActionFileWhat changes
n/adeploy/, deploy-alicloud/staged canary, one target first, then the other — not simultaneous

Implementation steps

  1. Run the full rspec suite on the complete Phase 1 branch (Ruby 3.4.10 + Rails 7.2.3.1 + load_defaults 7.2); boot-smoke every process type.
  2. Staging soak: Karafka consumer on real traffic, sidekiq-cron schedules (config/initializers/sidekiq.rb:46), Datadog traces, asset-compile parity, the Vault-unreachable assertion (Task 6), and Task 13's aegis check.
  3. Canary one deployment target, monitor, then the second; confirm each prior task's change is independently revertible (no accidental squash into one irreversible deploy).

Acceptance criteria

  • Full rspec suite green on the complete branch; every process type boots cleanly.
  • 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

DisciplineDays
Backend/Infra2
QA1.5
Total3.5

QA weighted above the standard 25% guidance — this is the single point where all 14 tasks' outputs are validated together for the first time.

Run to verify

bundle exec rspec && bundle exec karafka console

Depends on: All prior tasks (1–13).


Ordering rationale

  • Critical path: Task 3 (ddtracedatadog) gates Task 12 (Ruby 3.4 bump) — ddtrace 1.x cannot run on Ruby 3.4. Push the pigeon-http owner's re-release in parallel with the rest of wave 0 so the preferred path is ready when Task 12 needs it.
  • Task 2 (acts_as_paranoid) gates Task 8 (Rails 7.2 bump) — the hardest wave-0 blocker.
  • Tasks 6 (CI gates) and 7 (enum modernization) land before Task 8 so the bump PR has both a safety net and a clean enum surface to verify against the 7.2 changelog at bump time.
  • Tasks 9→10→11 (load_defaults stepping) are strictly sequential, each its own deploy — never compressed into one PR (cache-format/cookie-serializer changes are only cleanly revertible per-step).
  • Task 12 (Ruby bump) is deliberately last framework-adjacent change, matching the RFC's own numbered execution plan (Ruby moves after Rails settles, not alongside).
  • Tasks 4 and 5 are independent wave-0 items, parallelizable across engineers.
  • Task 13 (aegis spike) can run any time once Ruby 3.4 boots (Task 12) — a verification spike, not a code-dependency gate — but should close before Task 14's staging bake.

Skipped / blocked items

No tasks were fully blocked or excluded — every RFC execution-plan step is covered by an actionable or partially-blocked task above (Task 3 and Task 13 are the two ⚠️/decision-gated items, both included inline with their fallback paths). Track-level scope exclusion (Ruby 4.0.5) applies only in the Phase 2 breakdown.

Residual open questions not gating any task above — tracked via the RFC's own Open Questions section, not repeated here as tasks: OQ-4 (does sidekiq-pro registry access cover 7.3.10?), OQ-5 (Datadog profiling parity post-migration), OQ-6 (does webpacker actually boot/compile under Rails 7.2? — answered by Task 6's new CI gate, not assumed).