Skip to content

v4.24 — Dependency Convergence & Upgrade

Seven packages, one version matrix: Ruby, Rails, Node, and the whole Vue toolchain land on newest-stable, and the repo's worst laggard — ionic_frontend — closes the gap on every axis a real cost-benefit case supports.

Summary

Before this milestone, the Enkidu monorepo's seven packages (rails_api, design_system, admin_dashboard, ionic_frontend, agent_runner, docs_site, guide_site) had drifted onto different majors and minors of the same core dependencies. Node was split 20/22 across CI and Docker. ionic_frontend — the app carrying production mobile builds — was stuck on Vue 3.3, vue-router 4.2, Vite 7.3, and vue-tsc 2.1 while admin_dashboard had already moved to Vue 3.5, vue-router 5, Vite 8, and vue-tsc 3. agent_runner carried floating dependency ranges (vitest: latest, vite: >=8.0.16) that were themselves a source of drift. The longer this went on, the more painful and risky the eventual convergence would get.

This milestone closed that gap deliberately, one phase at a time, behind a single committed version matrix. Ruby moved to 4.0.6, Node to 24 (Active LTS), and every package that could take a breaking major did — but only where an explicit cost-benefit case supported it. vue-router 4→5 and TypeScript 5→6 both got a POSITIVE verdict and shipped across every package that needed them, including ionic_frontend. Vite 7→8 got a NEGATIVE verdict specifically for ionic_frontend — its vite.config.ts hits three of Vite 8's named breaking changes plus a fragile Capacitor/PWA-elements workaround — so ionic_frontend deliberately stayed on Vite 7.3.5 while converging everywhere else. That's not a gap; it's the milestone's one real decision gate working as designed.

All five phases shipped in roughly 24 hours (Phase 1 kicked off 2026-07-29, the rest landed 2026-07-30), with zero rollbacks and no cross-phase rework. Every package's build and test suite is green on the new pinned toolchain, and the repo now has exactly one Node version (with ten documented, upstream-forced exceptions for Firebase-deploy steps) instead of a silent 20/22 split.

Goal

Bring every package in the Enkidu monorepo to newest-stable Ruby / Rails / Node / Vue toolchains and converge them onto one shared version matrix, so the repo stops carrying multiple simultaneous versions of the same core dependency. Every package's build + test suite stays green; CI and Dockerfiles read one Node version; the target matrix is a committed source of truth.

Scope — What Shipped

  • A committed, sourced version matrix (.planning/milestones/v4.24-version-matrix.md + human-facing docs/architecture/version-matrix.md) pinning the newest-stable target for Ruby, Rails, Node, Vue, vue-router, Vite, TypeScript, vue-tsc, vitest, and vitepress across all 7 packages — the source of truth every phase converged against.
  • Node normalized to 24 (Active LTS) across every .nvmrc, every package.json engines.node, and both Node-based Dockerfiles (agent_runner, ionic_frontend) — up from a mixed 20/22 split. Ten CI steps stay deliberately pinned to Node 20 for their firebase-tools deploy call (firebase-tools#10726, an upstream WIF/ADC bug on Node ≥22, not repo drift).
  • Three per-major cost-benefit verdicts, each written against ionic_frontend's actual config rather than the abstract changelog: vue-router 4→5 POSITIVE (no breaking changes for this app's router usage), TypeScript 5→6 POSITIVE (small, contained fix), Vite 7→8 NEGATIVE (three named breaking changes plus Capacitor/PWA-elements risk on the app that ships production mobile builds).
  • Ruby bumped to 4.0.6 in rails_api. Rails was already at the pinned 8.1.3.1 from a prior security patch, so this phase touched zero application code.
  • design_system converged first (the shared foundation) — vue-router 4.6→5.2.0, TypeScript 5.9→6.0.2, plus the rest of the matrix — with its public API surface (tailwind-tokens.cjs, css/tokens.css) verified untouched before its consumers upgraded.
  • admin_dashboard (light bump) and ionic_frontend (the heavy lift) converged in Phase 4. ionic_frontend crossed both POSITIVE majors — vue-router 4.2.0→5.2.0 needed zero code changes; TypeScript 5.9→6.0.2 plus vue-tsc 3's stricter checking surfaced two real latent type gaps, fixed rather than suppressed — and deliberately stayed on Vite ^7.3.5 per the NEGATIVE verdict, re-confirmed to still build and test clean against every other bumped dependency.
  • agent_runner moved to TypeScript 6.0.2 on the node-24 Docker toolchain Phase 1 already set up; its floating vitest/vite ranges (pinned to exact versions in Phase 1) stayed pinned, no floats reintroduced.
  • docs_site and guide_site moved to vitepress 2.0.0-alpha.18 + Vue 3.5.40, deliberately staying on the 2.0 alpha track rather than "upgrading" to npm's latest 1.6.4 tag, which would have been a downgrade off the track both sites intentionally run.
  • Desi's post-upgrade visual-smoke pass on admin_dashboard and ionic_frontend: PASS, no unaccepted regressions in light or dark mode.

Phases

PhaseNameStatusPlansHighlights
1Foundation — target matrix, Node normalization, cost-benefit gateShipped1Version matrix committed; Node respec'd 22→24 mid-phase (Josh-approved); 3 verdicts locked; agent_runner floats pinned
2Backend — Ruby + RailsShipped1Ruby 4.0.2→4.0.6; Rails already at target; RSpec 6081 green, 92.86% coverage
3design_system toolchainShipped1Both POSITIVE majors crossed; public API surface verified zero-drift for consumers
4admin_dashboard + ionic_frontendShipped2 (4a/4b split)ionic_frontend crosses both POSITIVE majors, deliberately holds Vite 7; Desi visual-smoke PASS
5agent_runner + doc sitesShipped1agent_runner → TS 6.0.2; doc sites → vitepress 2.0.0-alpha.18

Key Decisions

  • "Latest" means newest-stable, with laggards pulled up to the most-advanced sibling already in the repo — not a hypothetical next major nobody runs. Locked by Josh at kickoff (OBJ-1891). This is why the matrix targets TypeScript 6.0.2 (the most-advanced sibling's pin) and not the newly-released Go-native TypeScript 7 line that nothing in the repo runs yet.
  • The per-major cost-benefit verdict is a real gate, not a formality. Phase 1 wrote each verdict against ionic_frontend's actual config; Phase 4 independently re-verified the Vite NEGATIVE verdict's premise still held before accepting the partial convergence, rather than trusting the Phase 1 writeup at face value.
  • Node target respec'd mid-milestone: 22 → 24. 22 is Maintenance LTS with ~9 months left before EOL — normalizing onto it would have front-loaded another forced Node bump almost immediately, defeating the point of a convergence milestone. 24 is Active LTS (EOL 2028-04-30) and every toolchain in the matrix already supports it. Josh-approved on Orion's recommendation, 2026-07-29.
  • ionic_frontend stays on Vite 7, by design. Its vite.config.ts hits three of Vite 8's named breaking changes (the esbuildoxc rename, rollupOptionsrolldownOptions, the dropped object form of manualChunks) plus a fragile Capacitor/PWA-elements dependency-optimizer workaround not worth risking without dedicated device testing — on the one app that ships production mobile builds. This is a documented, deliberate partial convergence, not a silently skipped major.
  • Ten Firebase-deploy CI steps stay on Node 20, permanently, until upstream fixes it. firebase-tools 15.22.x's WIF/ADC credential exchange fails on Node ≥22 (firebase/firebase-tools#10726) — every other job in those same workflow files runs on 24.

Requirements Coverage

10 / 10 requirements satisfied (per v4.24-dependency-convergence-MILESTONE-AUDIT.md) — every phase's ROADMAP acceptance line verified met against its shipped diff, with no unsatisfied or orphaned items. This milestone has no standalone REQUIREMENTS.md; the milestone ROADMAP is the requirement source, per this repo's convention for informal Multica-crew milestones.

Outcomes

The repo now builds and tests every package against a single, committed version matrix instead of inferring "current" from whichever package happened to upgrade most recently. A future dependency bump has one target to converge toward, not seven independent drift trajectories. ionic_frontend's Vite 8 migration is deferred to a dedicated follow-up phase with real-device smoke coverage — tracked, not forgotten — rather than rushed into this milestone's timeline. Node 24 buys the whole monorepo roughly two more years of Active LTS runway before the next forced bump.

Tech Debt

  • (Phase 5) agent_runner/src/agent/runner.ts:89 — a TypeScript 6 discriminated-union narrowing was suppressed with as any rather than fixed. Non-blocking; worth a small cleanup follow-up.
  • (Phase 5) agent_runner's node-24 Docker build is unexercised by CI until a master/tag push (Docker builds don't run on PR CI). First real exercise was the post-merge Staging Deployment run; a manual docker build confirmation is recommended.
  • (Phase 2, pre-existing) A mobile-android Playwright-lane flake (21/156 failures) surfaced in Phase 2's post-deploy staging smoke — root-caused by Vicki as a pre-existing environment issue predating this milestone, not a regression. Owner: Tess. Not yet filed as a standalone issue as of this close.
  • (Phase 2, pre-existing) rails_api/Gemfile.lock's RUBY VERSION stanza still reads ruby 4.0.0 (bundle install doesn't rewrite it under the repo's ~> 4.0 constraint) — unrelated to this bump, closeable with a future bundle lock --update-ruby.
  • 14c500548 — Phase 1 foundation: version matrix, Node 24 normalization, cost-benefit gate (PR #1875)
  • e0568f6b9 — Phase 2: bump Ruby to 4.0.6 in rails_api (PR #1878)
  • 0a163cbd — Phase 3: converge design_system toolchain to v4.24 matrix pins (PR #1879)
  • 39f94a168 — Phase 4a: admin_dashboard v4.24 toolchain convergence (PR #1881)
  • 28498cfff — Phase 4b: ionic_frontend v4.24 heavy toolchain convergence (PR #1882)
  • b806e206c — Phase 5: agent_runner TS6 + doc-site vitepress/Vue align (PR #1880)

Last updated: 2026-07-30

Loading…