RFC — Phase 1: Upgrade Ruby 3.2.2 → 3.4.10 and Rails 7.1.3.2 → 7.2.3.1
Bucket item: A1 · Class: 🔴 Expedite · Jira Story: BOT-4621 · Epic: BOT-4620
Context / Problem
The chatbot app's runtime and framework are both out of support:
- Ruby 3.2 reached end-of-life on 2026-03-31 and receives no further security fixes. The app runs 3.2.2, which is additionally ~9 patch releases behind the last 3.2.x (3.2.11, 2026-03-27) — it has been unpatched since before the series even went EOL.
- Rails 7.1 security support ended 2025-10-01 (7.1.6, 2025-10-29, was announced as the final 7.1 release). The app runs 7.1.3.2 — it has missed every security release from 7.1.3.3 through 7.1.6.
Missed security releases (Rails 7.1 track)
| Release | Date | Issue | CVE status |
|---|---|---|---|
| 7.1.3.3 / 7.1.3.4 | 2024-05–06 | Security releases | IDs not individually re-verified in research — UNVERIFIED detail |
| 7.1.4.1 | 2024-10-15 | 4 possible ReDoS attacks (Action Dispatch / Action Mailer) | CVE-2024-47887/47888/47889 family — exact ID mapping UNVERIFIED |
| 7.1.5.1 | 2024-12-10 | XSS via content_security_policy helper with untrusted input | CVE-2024-54133 — UNVERIFIED (recalled from memory, not re-checked against NVD) |
| 7.1.5.2 | 2025-08-13 | Two Active Storage security issues | CVE-2025-24293 family — partially verified |
| 7.1.6 | 2025-10-29 | Final 7.1 release; Rails core announced no further security/bug fixes for the series | — |
| 2026-03-23 patch day (7.2.3.1 / 8.0.4.1 / 8.1.2.1) | 2026-03-23 | 10 security issues: XSS in Action Pack/Action View/Active Support (incl. debug-exceptions XSS), DoS via Active Storage range requests, Active Support number-helper DoS, path traversal/glob injection in Active Storage DiskService, insufficient direct-upload metadata filtering | CVE-2026-33167 (debug-exceptions XSS) and CVE-2026-33176 (AS number-helper DoS) are the two IDs research.md confirmed; the remaining 8 issues in that batch are not individually ID-mapped here — UNVERIFIED count/IDs beyond these two |
Rails 7.1.3.2 (past its own EOL since 2025-10-01) received no fix for the entire 2026-03-23 batch. This is the strongest concrete security argument for this RFC: every day on 7.1.3.2 is a day against ten confirmed unpatched framework-level issues, two of them with identified CVE numbers.
Current-state evidence (version pins and framework-defaults gap)
| Location | Current value | Note |
|---|---|---|
.ruby-version:1 | ruby-3.2.2 | |
Gemfile:6 | ruby '3.2.2' | |
Gemfile.lock:939-940 | RUBY VERSION ruby 3.2.2p53 | |
Dockerfile:1-2,21 | ruby:3.2.2-alpine (both build stages) | |
Dockerfile.nonroot:1-2,23,42 | ruby:3.2.2-alpine (both build stages) | |
Dockerfile.develop:1,52 | ruby:3.1.0-alpine (both stages) | Pre-existing defect: one full Ruby minor behind the other 6 Ruby-version-bearing locations. Must be corrected in this RFC's execution, not left further behind. |
bitbucket-pipelines.yml:1 | image: ruby:3.2.2 | |
Gemfile.lock:942-943 | BUNDLED WITH 2.4.10 | |
Dockerfile:32, Dockerfile.develop:6, Dockerfile.nonroot:42 | ENV BUNDLE_VERSION 2.3.8 (Dockerfile, Dockerfile.develop); ENV BUNDLE_VERSION=2.3.8 with = (Dockerfile.nonroot) | |
bitbucket-pipelines.yml:26,50,67,296,344,359 (bundlerCache, rspecSetup, code-coverage/rspec, vulnerabilitiesCheckDDMetric, rubocop/Lint, reviewdog blocks — 6 occurrences) | gem install bundler -v 2.2.3 | 3-way Bundler mismatch: lock 2.4.10 / Dockerfiles 2.3.8 / CI 2.2.3 — must be reconciled to one version before the Ruby bump, since old Bundler can fail against newer RubyGems. |
Gemfile:9 | gem 'rails', '~> 7.1.3.2' | |
config/application.rb:13 | config.load_defaults 6.1 | |
config/initializers/new_framework_defaults_7_0.rb | 13 of 19 settings live/uncommented (e.g. active_record.partial_inserts, active_storage.variant_processor = :vips, action_controller.wrap_parameters_by_default) | The app already runs a hand-applied hybrid of some Rails 7.0 defaults while load_defaults itself still says 6.1, with no record of why each setting was chosen. |
config/initializers/new_framework_defaults_7_1.rb | 100% commented out (284 lines) | Dead documentation — no 7.1 default has ever been applied. |
7 Ruby-version-bearing locations exist in total (.ruby-version, Gemfile, Gemfile.lock, 3
Dockerfiles, 1 CI image); 6 agree at 3.2.2, Dockerfile.develop is stale at 3.1.0.
Target & sequencing decision
Rails 7.2.3.1 first (on Ruby 3.2.2), then Ruby 3.4.10.
- Rails 7.2's gemspec requires Ruby ≥ 3.1.0, which the current 3.2.2 already satisfies — Rails can move first with zero Ruby change.
- Ruby 3.4 is fine on Rails 7.2 (7.2.2+ ships the relevant compatibility fixes; community compatibility guidance lists 3.4 as recommended for 7.1/7.2/8.0/8.1), so Ruby moves second onto an already-current framework.
- The rejected order (Ruby 3.4 first, on Rails 7.1.3.2) leaves the app on a Ruby version paired with a framework release that will never receive fixes for it — Rails 7.1 is past all support and was never patched for Ruby 3.4-era changes. Every hop in this plan keeps the other component in a version that supports it; only the Rails-first order does that throughout.
7.2 is a transit station, not a resting state. Rails 7.2's security support ends 2026-08-09
— under a month from today (2026-07-13). Landing here buys a supported base to upgrade from,
not a stable long-term target. Phase 2 (Rails 8.1) must be scheduled immediately after this
phase stabilizes — see
phase-2-rails-8-1-ruby-4-0-upgrade.md, which treats the
gap between phases as the thing to compress, not a reason to skip this phase.
Security advisory: this phase's own scope may outrun the 2026-08-09 date. The wave-0 gem
sequence (in particular the sequential Karafka 2.2→2.5 chain and the ddtrace→datadog
migration), the 46-declaration enum modernization, and the three-step load_defaults stepping
(7.0 → 7.1 → 7.2) are realistically weeks of sequenced, individually-validated deploys — it is
plausible the app lands on Rails 7.2 already at or near its own security-support cliff rather than
comfortably inside it. This is not a reason to pick a farther endpoint: Rails 7.2 (not 8.0.5) is
still the correct Phase-1 target because it is the only single-minor hop from 7.1 that preserves
the deprecation-warning safety net the upgrade guide relies on (see the Phase 2 RFC's direct-jump
assessment) — moving the Phase-1 endpoint to 8.0.5 would simply relocate the skip-a-minor risk this
two-phase structure exists to avoid. The correct mitigation is compressing the Phase 1 → Phase 2
gap, not choosing a farther Phase-1 target; see the Phase 2 RFC's "big-bang vs. phased with
compressed gap" comparison.
Dependency blockers & gem waves
| Gem (current) | Target | Why / wave |
|---|---|---|
acts_as_paranoid 0.9.0 | 0.10.3 | Hard Rails-7.2 resolution blocker: Gemfile.lock:105-107 pins activerecord/activesupport >= 6.1, < 7.2. Bundler cannot resolve Rails 7.2.3.1 until this ceiling is lifted. 0.10.3 allows AR/AS >= 6.1, < 8.1. Wave 0 (bump on current Ruby 3.2.2/Rails 7.1.3.2 stack, separate small deploy, before the Rails PR). |
ddtrace 1.19.0 | Migrate to datadog 2.x (e.g. 2.37.0) | ddtrace 1.x supports MRI max Ruby 3.3 — a hard blocker before the Ruby 3.4 bump. Also carries debase-ruby_core_source (= 3.3.1) (native, vendors Ruby's C source tied to a specific minor — must be re-pinned to match whichever Ruby patch is deployed) and libdatadog/libddwaf native binaries. Migration is a real API change (Datadog.configure namespacing, profiler flags), not a version bump — budget it as its own wave-0 deploy, done well before the Ruby PR. |
google-protobuf ~>3.19 (3.25.2) | Bump to a Ruby-3.4-compatible release, then remove the pin | 3.25.x fails to install on Ruby 3.4 (upstream issue). It was only added to support Datadog profiling; once migrated to datadog 2.x (which uses libdatadog, not protobuf), the pin can likely be deleted entirely. Sequence with the ddtrace migration. |
pigeon-http 0.1.5 (private gem) | Preferred: owner re-releases dropping the unused ddtrace gemspec dependency (one-line fix). Decided fallback (2026-07-13): remove pigeon-http entirely. | Source-audited 2026-07-13 against the pinned v0.1.5 tag content (owner's clone HEAD is 10 non-merge commits ahead, 11 total incl. merge, touching lib/pigeon/core.rb/lib/pigeon/http.rb — not yet released, so not relied on here). pigeon.gemspec:38 declares an unconstrained ddtrace dependency that pigeon-http's own lib/ code never requires or calls anywhere — it only uses datadog/statsd via the separate dogstatsd-ruby gem, so the ddtrace dep is dead weight. Today's resolved ddtrace 1.19.0 is governed entirely by chatbot's own Gemfile:200 pin (~> 1.12, >= 1.12.1), not by pigeon-http. It nonetheless remains a Ruby-3.4 blocker at bundle-resolution time: even after chatbot migrates to datadog 2.x, pigeon-http's unconstrained dependency still forces Bundler to resolve some ddtrace, whose 1.x line caps at Ruby 3.3. The fix is verified-trivial (a gemspec-only change), but if the owning team can't turn it around in time, the decided fallback is removal: blast radius verified small — exactly one wrapper (lib/pigeon_http.rb) and one consumer (lib/wit_ai/app_v2.rb, 5 call sites: create/get_all/get/update/delete against Wit.ai); circuit-breaker/retry options are not actually exercised in production (already known-broken/unused per the wrapper's own code comment); zero existing test coverage to preserve; and the in-house lib/http.rb wrapper (already used by 5 other service clients, near-identical Entities::APIResponse response shape) is the natural drop-in replacement. Wave 0 either way. |
sidekiq 7.2.1 (+ sidekiq-pro 7.2.1) | sidekiq 7.3.10 | 7.3.6+ ships forward-compatibility fixes for Ruby 3.4. sidekiq-pro's existing sidekiq < 8 constraint is already satisfied — stays 7.x this phase. Wave 0. |
karafka 2.2.14 + karafka-web 0.7.10 | karafka 2.5.x, karafka-web 0.11.x | Karafka is already past its own EOL at 2.2 and mandates sequential minor upgrades (2.2→2.3→2.4→2.5, each with its own upstream upgrade doc) plus karafka-rdkafka native-ext rebuilds at each step. Wave 0, but treat as its own multi-step sub-sequence, not one PR. |
rack-cors 1.1.1 | 2.x (e.g. 2.0.2) | 1.x is not Rack-3-safe (lowercased header handling) — already a latent bug today since the app runs Rack 3.0.9.1 (confirmed resolved version, audit §3). Wave 0. |
grape 2.0.0 | 2.4.x | Bump for Rack 3 / Ruby 3.4 currency (2.1–2.4 include Rack 3.x fixes) per research.md. grape-swagger and grape-entity stay at their currently-resolved versions this wave — no compatibility issue flagged for them at Rails 7.2/Ruby 3.4. Wave 0. |
webdrivers 5.3.1 | Remove | Gem is archived/unmaintained and pins selenium-webdriver ~> 4.0, < 4.11, which just barely still resolves against the app's current selenium-webdriver 4.10.0 — any future selenium bump breaks it. Replace with Selenium Manager, built into selenium-webdriver >= 4.11. Test/dev-only; wave 0. |
rubocop 1.59.0 / rubocop-performance ~1.9.2 / parser (transitive, ~3.2.x) | rubocop ≥ 1.88, drop the 1.9.2 performance pin | parser 3.2.x cannot parse Ruby 3.4 syntax — the lint toolchain must move before/alongside the Ruby bump so CI can actually run. Also fix the stale .rubocop.yml:6 TargetRubyVersion: 2.6.3 (4 majors behind; the file's own comment at line 5 explains it was set low as a workaround, never revisited) to 3.4. No TargetRailsVersion key exists in the file — none to fix. |
webpacker 5.4.4 | No forced bump — add a boots-on-7.2 CI gate | Confirmed load-bearing, not vestigial (real webpacker:compile in both build Dockerfiles; live Turbolinks in app/javascript/packs/application.js). Unmaintained since 2021; whether it still boots/compiles cleanly under Rails 7.2 is unverified from this repo. Full migration to shakapacker is deferred to Phase 2 (FE-touching); Phase 1 only needs the CI asset-compile gate (see Execution plan) plus a documented fallback (pin a known-compatible sprockets/webpacker combination) if the gate fails. |
Wave-0 principle: every gem above except the framework version itself can and should land as a separate small deploy on the current stack (Ruby 3.2.2 / Rails 7.1.3.2) before the Rails 7.2 bump PR. This shrinks the risky change to "flip the Rails/Ruby version with dependencies already proven compatible" instead of "flip the version and fix N gems simultaneously."
Ruby 3.2 → 3.4 language impact
- Chilled string literals: files without
# frozen_string_literal:now compile string literals as "chilled"; mutation only warns whenWarning[:deprecated] = trueis explicitly enabled (not on by default) — no forced behavior change, but worth enabling in CI to surface latent mutation bugs before Phase 2 (where the default may tighten further). itimplicit block parameter: a bareitcall inside a block with no explicit parameter now resolves to the block's first argument. Audit greppedapp//lib/for bareitusage as a block-local and found zero hits — clean.- Prism becomes the default parser. Tools pinned to the old
parsergem cannot parse Ruby 3.4 syntax — this is why the rubocop/parser bump above must land before or with the Ruby PR, not after. - Default gems become bundled gems in 3.4:
abbrev,base64,bigdecimal,csv,drb,getoptlong,mutex_m,nkf,observer,repl_type_completor,resolv-replace,rinda,syslog. Any of theserequired directly by app code without a Gemfile entry will raiseLoadErrorunder Bundler once no longer shipped by default.require 'base64'— 3 hits:lib/auth/token_flows/oauth2_client_credentials.rb:3,lib/auth/header_strategies/basic_auth.rb:3,lib/mekari_hmac/signer.rb:4.base64is already an explicit transitive dependency ofactivesupport/sidekiq-proper the lock, so noLoadErroris expected — confirm it stays declared after the bump.requireofcsv/mutex_m/drb/observer/getoptlong/rinda/syslog/abbrev— zero direct hits in app code (all pulled transitively viaactivesupport/rails_admin/sshkit). Clean at the app-code level, but re-run this grep after the bump as a verification step, not just before.remote_syslog_logger1.0.4 is understood to be pure-Ruby over thesyslog_protocolgem, not the stdlibsyslog— this was not independently code-verified (research.md flags it as such); grep the gem's own source or its dependency tree before assuming it is unaffected.
OpenStruct— ~24 hits acrosslib/http.rb,lib/qontak_crm_service/http.rb,lib/harmonia/http.rb,lib/mekari_account/http.rb,lib/hub/chat_service/http.rb, and severalapp/core/{repositories,use_cases}//app/api/files.ostructis not removed from default gems in 3.4 (that happens in 4.0 — see the Phase 2 RFC), but confirm it stays resolvable and watch for new deprecation noise.
Rails 7.1 → 7.2 framework impact
ActiveSupport::Deprecationsingleton delegation is removed in 7.2 — callers must useRails.application.deprecatorsor an ownedDeprecationinstance. Audit greppedapp/ lib/ config/for directActiveSupport::Deprecation.calls and found zero hits — clean, no code will break on this removal.- Enum-syntax modernization — the largest volume of app-code surface for this bump. Audit
found 46 legacy hash-argument
enumdeclarations acrossapp/models/*.rb(e.g.app/models/intent.rb:73-76,app/models/path.rb:58,63,app/models/response.rb:53-55,app/models/attachment.rb:52-53). Rails 7.0+ introduced the positionalenum :col, {...}, suffix: trueform and has progressively tightened the legacy hash-argument form across 7.0→7.2. Every one of the 46 call sites must be checked against the exact Rails 7.2enumchangelog before this bump lands — mechanically fixable, but non-trivial surface area, and a missed case fails silently as a wrong enum mapping, not a boot error. - Staged
load_defaultsplan — do not jump straight from6.1to7.2:- Land Rails 7.2.3.1 with
config.load_defaults 6.1unchanged and the existing hand-applied 7.0-hybrid initializer untouched. This isolates "does the app boot on the new framework version" from "does it behave under new defaults." - Step to
new_framework_defaults_7_0.rbfully uncommented (all settings, not just the 13 of 19 already live), deploy, monitor, then flipload_defaultsto7.0. Dangerous flags at this step: the SHA-256 key generator (affects encrypted cookies and message verifiers — rotating this changes both),cache_format_versionmoving to the 7.0 format, andcookies_serializerinteraction (already:jsonperconfig/initializers/cookies_serializer.rb:5, so lower risk here than a fresh app). - Step to
new_framework_defaults_7_1.rbfully uncommented (currently 100% commented, 284 lines — every setting is templated but unapplied), deploy, monitor, flipload_defaultsto7.1. Dangerous flags:to_time_preserves_timezone, the Active Support message-serializer default move, and the cache serializer default. Confirm as part of this step that theactive_record.encryption.hash_digest_classchange is a no-op for this app: grep found no Rails-nativeencryptsusage anywhere inapp//lib/— this app's encryption is vialockbox, not Active Record Encryption, so this particular 7.1 default has nothing to act on. - Generate
new_framework_defaults_7_2.rbviabin/rails app:update, review its (not exhaustively published in the release notes) settings, uncomment, deploy, flipload_defaultsto7.2. - Rolling-deploy note: each of steps 2–4 runs mixed-version pods during a rolling deploy. Cache-format and cookie-serializer changes are the specific risk — a pod on the new defaults writing a cache entry or cookie that an old-defaults pod cannot read (or vice versa) causes transient cache misses / cookie invalidation during the rollout window, not a hard failure. Plan the rollout window and cache-flush expectations accordingly, and keep each defaults step as an independent, individually-revertible deploy.
- Land Rails 7.2.3.1 with
Execution plan (call to action)
- Bundler reconciliation. Pick one target Bundler version compatible with Ruby 3.4 (e.g.
2.5.x+). Update
Gemfile.lock'sBUNDLED WITH,ENV BUNDLE_VERSIONin all three Dockerfiles (Dockerfile:32,Dockerfile.develop:6,Dockerfile.nonroot:42— the last usesENV BUNDLE_VERSION=2.3.8with=), and all 6gem install bundler -v 2.2.3occurrences inbitbucket-pipelines.yml(lines 26bundlerCache, 50rspecSetup, 67 code-coverage/rspec, 296vulnerabilitiesCheckDDMetric, 344rubocop/Lint, 359reviewdog). - Wave-0 gem deploys on the current stack (Ruby 3.2.2 / Rails 7.1.3.2), each as its own small
PR/deploy:
acts_as_paranoid→ 0.10.3;ddtrace→datadog2.x migration (preferred: thepigeon-httpowner re-releases it dropping the unusedddtracegemspec dependency, a one-line gemspec change, before this lands; decided fallback: removepigeon-httpentirely and port its 5lib/wit_ai/app_v2.rbcall sites to the in-houselib/http.rbwrapper);sidekiq→ 7.3.10;karafka2.2→2.3→2.4→2.5 sequential +karafka-web→ 0.11;rack-cors→ 2.x;grape→ 2.4.x; removewebdrivers, bumpselenium-webdriver; bumprubocop/droprubocop-performancepin, fix.rubocop.yml:6TargetRubyVersionto3.4. - CI additions before the framework bump: add an asset-precompile step
(
bundle exec rake webpacker:compile && bundle exec rake assets:precompile) tobitbucket-pipelines.yml(currently absent — audit §5); add a Karafka boot smoke step (currently zero coverage — audit §6); add explicit boot checks for every process type (Puma, Sidekiq, Karafka,rails console, thesidekiq-cronschedule load, andupdate_automation_result.rb's bare-rubyinvocation — confirm whether it loads the Rails environment at all, which is currently unverified). - Rails 7.2 bump PR: bump
Gemfile:9togem 'rails', '~> 7.2.3.1', runbundle update rails(only after step 2'sacts_as_paranoidbump has landed, or resolution fails), runbin/rails app:updateand review every generated/changed file as an explicit diff (do not blanket-accept), and re-verify the 46enumdeclarations against the 7.2 changelog. load_defaultsstepping deploys — 7.0 → 7.1 → 7.2, each its own deploy, per the staged plan above.- Ruby 3.4.10 bump PR (only after wave-0's
ddtrace→datadogmigration is complete, since ddtrace 1.x cannot run on Ruby 3.4): update.ruby-version,Gemfile:6, all three Dockerfiles (fixingDockerfile.develop's stale 3.1.0 pin in the same PR),bitbucket-pipelines.yml:1's image, and re-pindebase-ruby_core_sourceto match Ruby 3.4's ABI if any native profiling dependency still requires it post-migration. - Staging bake + canary: full staging soak (see Validation) before a production canary rollout; roll out gradually across both deployment targets (AWS and Alicloud — confirmed dual-cloud in audit §10) rather than simultaneously.
- Per-step rollback: each wave-0 gem PR, each
load_defaultsstep, and the Rails/Ruby bump PRs are independently revertible; see Risks & rollback below for the exceptions.
Validation
- Full
bundle exec rspecsuite (all ~11 sharded CI steps) green at each stage. - Boot smoke test per process type: Puma, Sidekiq worker, Sidekiq-cron scheduler, Karafka consumer,
rails console, DB migration job. - Staging soak covering: Karafka consumer processing real
chatbot_incoming_messagetraffic,sidekiq-cronschedules firing (config/schedule.yml, loaded atconfig/initializers/sidekiq.rb:46), and Datadog traces/APM flowing correctly after thedatadog2.x migration. - Vault-unreachable boot behavior.
config/application.rb:41-79fetches Vault secrets synchronously at boot with a barerescue []that swallows all exceptions (network, auth, timeout) — a fail-open path where the app can boot with missing credentials and no visible error. This is a pre-existing issue, not introduced by this upgrade, but the new Ruby/Rails boot path changes process boot order/timing enough to warrant re-asserting the expected behavior explicitly (does every process type still boot the same way when Vault is unreachable, and is that silence actually acceptable) rather than letting the upgrade silently carry the same gap forward unexamined. - Asset-compile parity: confirm
webpacker:compileandassets:precompileproduce a bootable, visually-correct app under Rails 7.2 (new CI gate from Execution plan step 3). aegisboot/logging check under Rails 7.2: confirmAegis::Logger's#taggedduck-typing status againstconfig.log_tags = [:request_id](does it still silently no-op, or start raising), and confirm the Sidekiq client/server middleware chain still wraps jobs correctly at the target Sidekiq version.
Risks & rollback
- Per-wave rollback: each wave-0 gem bump and each Dockerfile/CI change reverts independently (revert the image tag or gem-version PR); no cross-wave coupling by design.
- Irreversibility call-outs: the
load_defaultscache-format and cookie-serializer steps are not cleanly revertible mid-rollout — reverting after cache/cookie formats have already changed on some pods requires an explicit rollback flag (e.g. temporarily forcing the old cache/cookie format) rather than a plain code revert, to avoid stranding sessions/cache entries written under the new format. aegisprivate gem (git@bitbucket.org:terbang-ventures/aegis.git, pinned tag0.2.12) — source-audited 2026-07-13 against the pinned tag content (the owner's cloneHEADis 5 commits ahead, touchinglib/aegis/logger.rb/lib/aegis/fingerprint.rb— this is the candidate "updated aegis" path if a newer release is later needed). Assessed compatible-as-is for Phase 1 (medium-high confidence):required_ruby_version = '>= 2.6.0'has no upper ceiling, and none of aegis's 15 lib files touch any Ruby-3.4 default-gem departure,OpenStruct, or other hazard pattern. Two residual verification items remain, neither resolvable from static reading alone: (i) Rails 7.2'sActiveSupport::BroadcastLoggerinteraction withAegis.replace_rails_logger!(config/initializers/aegis.rb:21) — the swap installs a plain::Loggersubclass with no#taggedmethod, which already silently defeatsconfig.log_tags = [:request_id](config/environments/production.rb:71) today at Rails 7.1.3.2 — a pre-existing defect, not introduced by this upgrade, but worth fixing the next time aegis is updated; (ii) Sidekiq 7.3+ middleware-chain API drift against aegis's client/server patch classes. Two further audit findings change the risk picture: aegis has no CI at all (confirmed absent across its entire git history), and its gemspec omitsopentelemetry-api/opentelemetry-sdkeven though 4 lib files unconditionallyrequirethem — masked today only because chatbot's ownGemfile:230,232already declares both directly, so those two Gemfile lines must not be removed as "unused" during this upgrade. Decided fallback (2026-07-13): temporarily detach aegis if it blocks — verified observability-only impact (loses structured JSON logs, PII masking, error fingerprinting/grouping, trace correlation, and Sidekiq job tracing; no functional HTTP/Sidekiq/DB behavior depends on it). Caveat: PII masking is a data-protection control, not pure observability — if aegis is detached, explicitly confirm no other log path (lograge, Rails' default logger,config/initializers/filter_parameter_logging.rb) emits unmasked PII in the interim; do not assume "observability-only" covers this specific loss without that check.webpackerboot risk: if the new CI gate (step 3) fails against Rails 7.2, the documented contingency is to pin a known-compatible sprockets/webpacker version combination rather than attempt an emergency shakapacker migration mid-Phase-1 — that migration is explicitly Phase 2 scope.
Open questions
Who owns theResolved 2026-07-13: source-audited (see the gem-waves table above). Preferred fix is a one-line gemspec change by the owner (drop the unused, unconstrainedpigeon-httpprivate-gem re-release againstdatadog2.x, and on what timeline?ddtracedep); decided fallback if that doesn't land in time is removing pigeon-http entirely — blast radius verified small.DoesResolved 2026-07-13: source-audited against the pinned tag (see Risks & rollback above) — assessed compatible-as-is (medium-high confidence), with two residual verification items (Rails 7.2aegis0.2.12 function correctly on Ruby 3.4/Rails 7.2? Needs a spike against its actual source, not inference from this repo.BroadcastLogger/#taggedinteraction, Sidekiq 7.3+ middleware API) that still require booting a real upgrade branch to close. Decided fallback if it blocks: temporarily detach aegis (verified observability-only loss — except PII masking; see the data-protection caveat in Risks & rollback).What Redis server version runs in production? Sidekiq 7.3 needs Redis server ≥ 6.0/6.2 — unverified from this audit (only theResolved 2026-07-13 (stakeholder-confirmed): the Redis server backing Sidekiq is 7.x — the ≥ 6.0/6.2 requirement is satisfied. The app's other Redis (cache/app usage) is 6.0, which nothing in Phase 1 requires upgrading.redisgem client version was confirmed).- Does the team's
sidekiq-proregistry access (gems.contribsys.com) cover the 7.3.10 release, or does it need a subscription check? - Does Datadog profiling parity hold after the
ddtrace→datadog2.x migration (nativelibdatadog/libddwafbehavior vs. the olddebase-ruby_core_sourceapproach)? - Does
webpacker5.4.4 actually boot and compile cleanly under Rails 7.2 — no authoritative compatibility statement exists; must be answered by the new CI gate, not assumed.