migration-work

v1v2 · +194 −243 · View latest

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="description" content="A chronological record of Unravel migration work across product, cloud, data, SDK, and backend systems.">
  <title>Migration Control Map | Unravel</title>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Barlow+Condensed:wght@500;600;700&amp;family=Source+Sans+3:opsz,wght@8..60,400;8..60,500;8..60,600;8..60,700&amp;display=swap" rel="stylesheet">
  <style>
    :root {
      --paper: #f4eddf;
      --paper: oklch(95.5% 0.017 78);
      --paper-bright: #fbf7ee;
      --paper-bright: oklch(98% 0.012 78);
      --ink: #24231f;
      --ink: oklch(24% 0.015 72);
      --ink-soft: #5f594e;
      --ink-soft: oklch(45% 0.018 72);
      --line: #cfc3b2;
      --line: oklch(82% 0.025 75);
      --signal: #ed5a22;
      --signal: oklch(64% 0.21 41);
      --signal-deep: #9d3212;
      --signal-deep: oklch(44% 0.16 40);
      --signal-wash: #f7c8a8;
      --signal-wash: oklch(84% 0.095 50);
      --sage: #aeba9f;
      --sage: oklch(75% 0.055 135);
      --focus: #174f91;
      --focus: oklch(43% 0.13 251);
      --display: "Barlow Condensed", "Arial Narrow", sans-serif;
      --body: "Source Sans 3", "Segoe UI", sans-serif;
      --paper: #f4f6f9;
      --paper: oklch(96.7% 0.015 257);
      --paper-bright: #fbfdff;
      --paper-bright: oklch(99.1% 0.01 257);
      --ink: #161a24;
      --ink: oklch(15% 0.02 262);
      --ink-soft: #5a6273;
      --ink-soft: oklch(48% 0.04 260);
      --line: #dde3ea;
      --line: oklch(88% 0.03 257);
      --signal: #2f56bd;
      --signal: oklch(48% 0.15 260);
      --signal-deep: #1e3e8e;
      --signal-deep: oklch(35% 0.18 260);
      --signal-wash: #d9e2fa;
      --signal-wash: oklch(87% 0.09 258);
      --sage: #8fa58a;
      --sage: oklch(77% 0.04 130);
      --focus: #1f4ea0;
      --focus: oklch(43% 0.12 260);
      --display: -apple-system, "system-ui", "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
      --body: -apple-system, "system-ui", "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
      --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
    }
⋯ 49 unchanged lines
    }
    .site-header {
      position: sticky;
      top: 0;
      z-index: 60;
      display: grid;
      grid-template-columns: 1fr auto;
      gap: 2rem;
      align-items: center;
      min-height: 5rem;
      padding: 1rem clamp(1rem, 4vw, 4.5rem);
      border-bottom: 1px solid var(--line);
      background: var(--paper-bright);
      min-height: 3.75rem;
      padding: 0.7rem clamp(1rem, 4vw, 4.5rem);
      border-bottom: 1px solid color-mix(in oklch, var(--line) 72%, transparent);
      background: color-mix(in oklch, var(--paper) 88%, transparent);
      backdrop-filter: blur(6px);
    }
    .wordmark {
      display: inline-flex;
      align-items: center;
      gap: 0.6rem;
      font-family: var(--display);
      font-size: 1.35rem;
      font-size: 1rem;
      font-weight: 700;
      letter-spacing: 0.02em;
      letter-spacing: 0.06em;
      text-decoration: none;
    }
    .wordmark::before {
      content: "";
      width: 0.62rem;
      height: 0.62rem;
      border-radius: 50%;
      background: var(--signal);
    }
    .site-header nav {
      display: flex;
      flex-wrap: wrap;
⋯ 15 unchanged lines
      box-shadow: inset 0 -2px 0 var(--signal);
    }
    .hero {
      min-height: min(820px, calc(100vh - 8rem));
      display: grid;
      grid-template-columns: minmax(0, 1.15fr) minmax(22rem, 0.85fr);
      border-bottom: 1px solid var(--ink);
      overflow: clip;
    }
    .hero-copy {
      display: flex;
      flex-direction: column;
      justify-content: center;
      padding: clamp(4rem, 9vw, 9rem) clamp(1rem, 6vw, 7rem) clamp(4rem, 8vw, 7rem) clamp(1rem, 4vw, 4.5rem);
      background: var(--paper-bright);
    .simple-hero {
      border-bottom: 1px solid var(--line);
      background: var(--paper);
    }
    .kicker {
      margin: 0 0 1.5rem;
      font-family: var(--display);
      font-size: 1.05rem;
      font-weight: 700;
      letter-spacing: 0.09em;
      text-transform: uppercase;
    .simple-hero .hero-inner {
      width: min(100%, 76ch);
      margin: 0 auto;
      padding: clamp(3.5rem, 7.8vw, 7rem) clamp(1rem, 4vw, 4.5rem);
    }
    .hero h1 {
      max-width: 12ch;
    .simple-hero h1 {
      margin: 0;
      font-family: var(--display);
      font-size: clamp(4.4rem, 10.5vw, 10rem);
      font-weight: 600;
      letter-spacing: -0.035em;
      line-height: 0.82;
      font-size: clamp(3rem, 4.2vw, 4rem);
      line-height: 0.98;
      letter-spacing: -0.03em;
      text-wrap: balance;
    }
    .hero-deck {
      max-width: 62ch;
      margin: clamp(2rem, 4vw, 3.5rem) 0 0;
      font-size: clamp(1.2rem, 1.05rem + 0.6vw, 1.65rem);
      line-height: 1.42;
    .hero-title-main {
      display: block;
      color: var(--ink);
      font-weight: 820;
    }
    .hero-principles {
      display: grid;
      grid-template-columns: repeat(3, minmax(0, 1fr));
      gap: 1rem;
      max-width: 48rem;
      margin: clamp(2rem, 4vw, 3.5rem) 0 0;
      padding: 1.25rem 0 0;
      border-top: 1px solid var(--line);
    .hero-title-continue {
      display: block;
      margin-top: 0.2rem;
      color: var(--ink-soft);
      font-weight: 400;
    }
    .hero-principles p {
      margin: 0;
      font-size: 0.95rem;
      line-height: 1.42;
    .simple-hero p {
      max-width: 60ch;
      margin: clamp(1.25rem, 3vw, 2rem) 0 0;
      color: var(--ink-soft);
      font-size: 1.1rem;
      line-height: 1.5;
    }
    .hero-principles b {
      display: block;
      margin-bottom: 0.3rem;
    .simple-hero .accent-pill {
      display: inline-flex;
      align-items: center;
      gap: 0.45rem;
      margin-top: 0.8rem;
      color: var(--signal-deep);
      font-family: var(--display);
      font-size: 1.25rem;
      line-height: 1;
      font-size: 0.88rem;
      font-weight: 700;
      letter-spacing: 0.03em;
      text-transform: uppercase;
    }
    .hero-map {
      position: relative;
      min-height: 34rem;
      display: grid;
      place-items: center;
      padding: clamp(2rem, 5vw, 5rem);
    .simple-hero .accent-pill::before {
      content: "";
      width: 0.55rem;
      height: 0.55rem;
      border-radius: 50%;
      background: var(--signal);
      color: var(--ink);
    }
    .hero-map svg {
      width: min(100%, 34rem);
      height: auto;
      overflow: visible;
    }
    .hero-map .map-caption {
      position: absolute;
      inset: auto 2rem 2rem;
      max-width: 25rem;
      margin: 0;
      font-size: 0.95rem;
      font-weight: 600;
      line-height: 1.4;
      display: inline-block;
    }
    .section-shell {
⋯ 375 unchanged lines
    }
    @media (max-width: 980px) {
      .hero {
        grid-template-columns: 1fr;
      }
      .hero-map {
        min-height: 30rem;
      }
      .timeline-heading,
      .patterns .section-shell,
      .discovery-intro,
⋯ 38 unchanged lines
        justify-content: flex-start;
      }
      .hero-principles,
      .discovery-weeks {
        grid-template-columns: 1fr;
      }
⋯ 99 unchanged lines
  <a class="skip-link" href="#main-content">Skip to main content</a>
  <header class="site-header">
    <a class="wordmark" href="#top" aria-label="Unravel migration control map home">UNRAVEL / MIGRATION CONTROL MAP</a>
    <a class="wordmark" href="#top" aria-label="Unravel migration work home">unravel / migration work</a>
    <nav aria-label="Document navigation">
      <a href="#timeline">Timeline</a>
      <a href="#patterns">What we learned</a>
      <a href="#timeline">Timeline</a>
      <a href="#discovery">Three-week discovery</a>
    </nav>
  </header>
  <main id="main-content">
    <section class="hero" id="top" aria-labelledby="hero-title">
      <div class="hero-copy">
        <p class="kicker">A decade of system change</p>
        <h1 id="hero-title">Keep business moving while core systems change.</h1>
        <p class="hero-deck">Eight migrations across frontend, cloud, data, SDKs, and backend systems. Different technologies, same discipline: diagnose before prescribing, preserve continuity, and accelerate only where verification can keep up.</p>
        <div class="hero-principles" aria-label="Migration principles">
          <p><b>01 / Diagnose</b>Start with business impact, not architecture fashion.</p>
          <p><b>02 / Protect</b>Design cutovers around live contracts and operational risk.</p>
          <p><b>03 / Accelerate</b>Use AI when evidence and gates can verify machine-speed work.</p>
        </div>
    <section class="simple-hero reveal" id="top" aria-labelledby="hero-title">
      <div class="hero-inner">
        <h1 id="hero-title">
          <span class="hero-title-main">Changing core systems.</span>
          <span class="hero-title-continue">Without stopping the business.</span>
        </h1>
        <p>Eight verified migrations across frontend, cloud, data, SDK, and backend systems. Each case leads with business impact, elapsed duration, and complexity, then explains continuity constraints and execution choices.</p>
        <p class="accent-pill" aria-label="Page tone">Focused on judgment before mechanism.</p>
      </div>
      <div class="hero-map" aria-hidden="true">
        <svg viewBox="0 0 500 620">
          <path d="M74 50V162C74 216 118 260 172 260H330C384 260 428 304 428 358V570" fill="none" stroke="currentColor" stroke-width="7"/>
          <path d="M74 164H238C292 164 336 120 336 66V50" fill="none" stroke="currentColor" stroke-width="2" stroke-dasharray="8 10"/>
          <g fill="var(--paper-bright)" stroke="currentColor" stroke-width="5">
            <circle cx="74" cy="72" r="13"/><circle cx="74" cy="164" r="13"/><circle cx="172" cy="260" r="13"/><circle cx="276" cy="260" r="13"/><circle cx="382" cy="284" r="13"/><circle cx="428" cy="382" r="13"/><circle cx="428" cy="474" r="13"/><circle cx="428" cy="570" r="13"/>
          </g>
          <g fill="currentColor" font-family="Barlow Condensed, sans-serif" font-size="20" font-weight="700">
            <text x="102" y="80">YUI → REACT</text>
            <text x="102" y="172">CLOUD REGION</text>
            <text x="202" y="248">SDK CORE</text>
            <text x="300" y="248">DATABASE</text>
            <text x="298" y="326">DATA PLATFORM</text>
            <text x="278" y="390">CHECKOUT</text>
            <text x="278" y="482">RETOOL</text>
            <text x="274" y="578">JAVA → PYTHON</text>
          </g>
        </svg>
        <p class="map-caption">Route shows sequence, not a single migration recipe. Every crossing uses its own continuity and verification plan.</p>
    </section>
    <section class="patterns" id="patterns" aria-labelledby="patterns-title">
      <div class="section-shell">
        <header class="reveal">
          <p class="kicker">What repeated</p>
          <h2 id="patterns-title">Judgment before machinery.</h2>
        </header>
        <ol class="pattern-list reveal">
          <li><div><h3>Business continuity sets architecture.</h3><p>Zero downtime, customer-paced upgrades, and continuous feature work each demand different migration shapes.</p></div></li>
          <li><div><h3>Parallel paths buy reversibility.</h3><p>Dual databases, coexistence, staged customer cohorts, and versioned opt-in reduce irreversible cutover risk.</p></div></li>
          <li><div><h3>Contracts beat source translation.</h3><p>Consumers, wire formats, and data invariants define what must survive. Languages and frameworks are implementation choices.</p></div></li>
          <li><div><h3>AI speed needs stronger gates.</h3><p>Four-week delivery was possible because human-defined contracts and live-stack checks could reject machine-speed mistakes.</p></div></li>
        </ol>
      </div>
    </section>
    <section id="timeline" class="section-shell" aria-labelledby="timeline-title">
      <header class="timeline-heading reveal">
        <h2 id="timeline-title">The crossings.</h2>
        <p>Each entry leads with business impact, elapsed duration, and a complexity rating with reasons. Technical details follow only to explain how value and continuity were protected.</p>
      </header>
      <ol class="route-list">
        <li class="migration-case reveal" data-case="helpshift-yui-to-react" data-evidence="confirmed" data-sort="2017">
          <div class="case-year">2015<br>2017</div>
        <li class="migration-case reveal" data-case="celerity-java-to-python" data-evidence="confirmed" data-sort="2026.5">
          <div class="case-year">2026</div>
          <div class="case-node" aria-hidden="true"></div>
          <article class="case-content">
            <header class="case-header">
              <h3>Helpshift<br>YUI → React</h3>
              <span class="case-status">Live system</span>
              <h3>Celerity<br>Java → Python backend</h3>
              <span class="case-status">Unreleased target</span>
            </header>
            <div class="case-metrics">
              <p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Product roadmap never paused. React improved future delivery, performance, reliability, consistency, usability, and extensibility.</p>
              <p class="metric" data-metric="duration"><span class="metric-label">Duration</span>About 2 years elapsed.</p>
              <p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. Live product, broad UI surface, long coexistence, and uninterrupted feature work.</p>
              <p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Removed vendor lock-in, returned direct product change control, reduced source maintenance surface 55%, and created 4 independently deployable and scalable processes.</p>
              <p class="metric" data-metric="duration"><span class="metric-label">Duration</span>4 active weeks. Original Java build took about 21 active weeks. Two more weeks would have avoided overtime.</p>
              <p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. Two strict mobile contracts, Kafka compatibility, hidden framework behavior, data and storage invariants, and a compressed finish.</p>
            </div>
            <div class="case-facts">
              <section><h4>The change</h4><p>YUI frontend to React.</p></section>
              <section><h4>The constraint</h4><p>Keep shipping product features throughout migration.</p></section>
              <section><h4>The method</h4><p>Move incrementally by product surface while YUI and React coexist.</p></section>
              <section><h4>The change</h4><p>Java Quarkus monolith to Python FastAPI API, consumer, renderer, and dispatcher.</p></section>
              <section><h4>The constraint</h4><p>Live iOS and Android clients defined compatibility, but Python target was unreleased. This was not a live production cutover.</p></section>
              <section><h4>The method</h4><ul><li>Extract contracts from mobile clients.</li><li>Verify API, database, and storage behavior against real stack.</li><li>Use 101 client contract assertions and 247 live-stack checks per gate.</li></ul></section>
            </div>
            <p class="case-ai"><span>AI-assisted?</span>No. Pre-LLM delivery.</p>
            <p class="case-ai"><span>AI-assisted?</span>Yes. Claude Code agents did substantial build and verification work; humans defined contracts, gates, and architectural boundaries.</p>
            <a class="deep-dive" data-deep-dive href="https://thing.unravel.tech/kapil/terra-incognita-before-you-migrate" rel="noopener">Read Terra Incognita, the detailed migration account →</a>
          </article>
        </li>
        <li class="migration-case reveal" data-case="helpshift-aws-california-to-virginia" data-evidence="confirmed" data-sort="2021">
          <div class="case-year">2021</div>
        <li class="migration-case reveal" data-case="reify-retool-to-react-and-clojure" data-evidence="confirmed" data-sort="2026">
          <div class="case-year">2025<br>2026</div>
          <div class="case-node" aria-hidden="true"></div>
          <article class="case-content">
            <header class="case-header">
              <h3>Helpshift<br>AWS California → Virginia</h3>
              <span class="case-status">Zero downtime</span>
              <h3>Reify<br>Retool → React + Clojure</h3>
              <span class="case-status">Internal operations</span>
            </header>
            <div class="case-metrics">
              <p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Lower infrastructure cost, higher reliability, and a current critical stack with a clear path to later Java and AWS Graviton modernization.</p>
              <p class="metric" data-metric="duration"><span class="metric-label">Duration</span>9 months from start through production rollout. Active engineering duration remains to be normalized.</p>
              <p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. Zero downtime, broad dependencies, data and traffic cutover, and a rotating 9 to 25 person roster.</p>
              <p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Higher reliability and lower operating cost for internal workflows.</p>
              <p class="metric" data-metric="duration"><span class="metric-label">Duration</span>Under 3 months elapsed.</p>
              <p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. Live staff operations, integrations and data contracts, and multi-team coordination.</p>
            </div>
            <div class="case-facts">
              <section><h4>The change</h4><p>AWS California to AWS Virginia, plus Postgres, Mongo, Kafka, Redis, Flink, Hadoop, Spark, Elasticsearch, ScyllaDB, and Java modernization.</p></section>
              <section><h4>The constraint</h4><p>Move a B2B customer portfolio without interruption, including a long tail and very large customers.</p></section>
              <section><h4>The method</h4><ul><li>Audit dependencies and upgrade target services in waves.</li><li>Establish dual-run and replication paths.</li><li>Move smallest customers first, then largest.</li></ul></section>
              <section><h4>The change</h4><p>Internal operations workflows moved from Retool to a custom React and Clojure implementation.</p></section>
              <section><h4>The constraint</h4><p>Keep live staff operations working across integrations and data dependencies.</p></section>
              <section><h4>The method</h4><p>Move workflow by workflow from Retool into the custom system.</p></section>
            </div>
            <p class="case-ai"><span>AI-assisted?</span>No.</p>
            <p class="case-ai"><span>AI-assisted?</span>Yes.</p>
          </article>
        </li>
        <li class="migration-case reveal" data-case="helpshift-native-sdks-to-js" data-evidence="confirmed" data-sort="2021.5">
          <div class="case-year">2021<br>2022</div>
        <li class="migration-case reveal" data-case="healthtech-angular-to-react-checkout" data-evidence="confirmed" data-sort="2024">
          <div class="case-year">2024</div>
          <div class="case-node" aria-hidden="true"></div>
          <article class="case-content">
            <header class="case-header">
              <h3>Helpshift<br>Native SDKs → shared JS core</h3>
              <span class="case-status">Customer-paced rollout</span>
              <h3>HealthTech<br>Angular checkout → React</h3>
              <span class="case-status">Anonymous client</span>
            </header>
            <div class="case-metrics">
              <p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Faster SDK delivery, consistent behavior across platforms, lower duplicated maintenance cost, and broader customer upgrade reach.</p>
              <p class="metric" data-metric="duration"><span class="metric-label">Duration</span>4 to 6 months elapsed.</p>
              <p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. Multi-platform compatibility, version support, customer-controlled upgrades, and coordinated releases.</p>
              <p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Checkout conversion increased 6 to 8%. Disruptions caused by navigation or payment-window closure fell 30%.</p>
              <p class="metric" data-metric="duration"><span class="metric-label">Duration</span>About 3 months elapsed.</p>
              <p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>Medium. Revenue-critical flow, navigation and payment state risk, bounded frontend scope, and one cutover.</p>
            </div>
            <div class="case-facts">
              <section><h4>The change</h4><p>Separate iOS, Android, and Unity or game-engine SDK implementations to a shared JavaScript core.</p></section>
              <section><h4>The constraint</h4><p>Keep existing native versions supported while customers choose their upgrade timing.</p></section>
              <section><h4>The method</h4><p>Validate shared behavior across all three platform families, then release through versioned opt-in.</p></section>
              <section><h4>The change</h4><p>Angular checkout to React, with checkout reliability improvements delivered during migration.</p></section>
              <section><h4>The constraint</h4><p>Protect customer progress and transaction completion through refreshes, back navigation, and payment-window closure.</p></section>
              <section><h4>The method</h4><ul><li>Persist early checkout state in local storage.</li><li>Use a reopenable payment popup.</li><li>Release through one controlled cutover.</li></ul></section>
            </div>
            <p class="case-ai"><span>AI-assisted?</span>No.</p>
            <p class="case-ai"><span>AI-assisted?</span>Yes.</p>
          </article>
        </li>
        <li class="migration-case reveal" data-case="helpshift-mongodb-to-yugabyte" data-evidence="confirmed" data-sort="2022">
        <li class="migration-case reveal" data-case="helpshift-hadoop-hive-to-spark-redshift" data-evidence="confirmed" data-sort="2022.5">
          <div class="case-year">2022</div>
          <div class="case-node" aria-hidden="true"></div>
          <article class="case-content">
            <header class="case-header">
              <h3>Helpshift<br>MongoDB → YugabyteDB</h3>
              <span class="case-status">Zero downtime</span>
              <h3>Helpshift<br>Hadoop + Hive → Spark + Redshift</h3>
              <span class="case-status">Live data platform</span>
            </header>
            <div class="case-metrics">
              <p class="metric" data-field="impact"><span class="metric-label">Business impact</span>More consistent data operations, greater scalability, and headroom for future load without interrupting customer service.</p>
              <p class="metric" data-metric="duration"><span class="metric-label">Duration</span>About 6 months elapsed.</p>
              <p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. Live 2 TB store, data integrity, dual reads and writes, and a 20-plus phase roadmap.</p>
              <p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Supported 10x platform growth, improved data accuracy from 90% to 99.99% in one year, and strengthened resiliency, scalability, and adoption.</p>
              <p class="metric" data-metric="duration"><span class="metric-label">Duration</span>About 6 months elapsed. The 1-year accuracy period is an outcome window, not migration duration.</p>
              <p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. 2 billion devices, 1 PB daily ingestion, live accuracy requirements, and a broad warehouse change.</p>
            </div>
            <div class="case-facts">
              <section><h4>The change</h4><p>MongoDB primary store to YugabyteDB distributed SQL, with supporting service extraction.</p></section>
              <section><h4>The constraint</h4><p>Preserve data integrity and customer availability throughout cutover.</p></section>
              <section><h4>The method</h4><ul><li>Build staging environment.</li><li>Run both databases through dual reads and writes.</li><li>Move gradually across more than 20 phases.</li></ul></section>
              <section><h4>The change</h4><p>Hadoop and Hive to Spark and Redshift. Supporting stack included Hudi, PostgreSQL, Arrow, Airflow, and DBT.</p></section>
              <section><h4>The constraint</h4><p>Maintain processing continuity and data correctness at petabyte daily scale.</p></section>
              <section><h4>The method</h4><p>Modernize processing and warehouse architecture around Spark and Redshift, supported by Hudi, PostgreSQL, Arrow, Airflow, and DBT.</p></section>
            </div>
            <p class="case-ai"><span>AI-assisted?</span>No.</p>
          </article>
        </li>
        <li class="migration-case reveal" data-case="helpshift-hadoop-hive-to-spark-redshift" data-evidence="confirmed" data-sort="2022.5">
        <li class="migration-case reveal" data-case="helpshift-mongodb-to-yugabyte" data-evidence="confirmed" data-sort="2022">
          <div class="case-year">2022</div>
          <div class="case-node" aria-hidden="true"></div>
          <article class="case-content">
            <header class="case-header">
              <h3>Helpshift<br>Hadoop + Hive → Spark + Redshift</h3>
              <span class="case-status">Live data platform</span>
              <h3>Helpshift<br>MongoDB → YugabyteDB</h3>
              <span class="case-status">Zero downtime</span>
            </header>
            <div class="case-metrics">
              <p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Supported 10x platform growth, improved data accuracy from 90% to 99.99% in one year, and strengthened resiliency, scalability, and adoption.</p>
              <p class="metric" data-metric="duration"><span class="metric-label">Duration</span>About 6 months elapsed. The 1-year accuracy period is an outcome window, not migration duration.</p>
              <p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. 2 billion devices, 1 PB daily ingestion, live accuracy requirements, and a broad warehouse change.</p>
              <p class="metric" data-field="impact"><span class="metric-label">Business impact</span>More consistent data operations, greater scalability, and headroom for future load without interrupting customer service.</p>
              <p class="metric" data-metric="duration"><span class="metric-label">Duration</span>About 6 months elapsed.</p>
              <p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. Live 2 TB store, data integrity, dual reads and writes, and a 20-plus phase roadmap.</p>
            </div>
            <div class="case-facts">
              <section><h4>The change</h4><p>Hadoop and Hive to Spark and Redshift. Supporting stack included Hudi, PostgreSQL, Arrow, Airflow, and DBT.</p></section>
              <section><h4>The constraint</h4><p>Maintain processing continuity and data correctness at petabyte daily scale.</p></section>
              <section><h4>The method</h4><p>Modernize processing and warehouse architecture around Spark and Redshift, supported by Hudi, PostgreSQL, Arrow, Airflow, and DBT.</p></section>
              <section><h4>The change</h4><p>MongoDB primary store to YugabyteDB distributed SQL, with supporting service extraction.</p></section>
              <section><h4>The constraint</h4><p>Preserve data integrity and customer availability throughout cutover.</p></section>
              <section><h4>The method</h4><ul><li>Build staging environment.</li><li>Run both databases through dual reads and writes.</li><li>Move gradually across more than 20 phases.</li></ul></section>
            </div>
            <p class="case-ai"><span>AI-assisted?</span>No.</p>
          </article>
        </li>
        <li class="migration-case reveal" data-case="healthtech-angular-to-react-checkout" data-evidence="confirmed" data-sort="2024">
          <div class="case-year">2024</div>
        <li class="migration-case reveal" data-case="helpshift-native-sdks-to-js" data-evidence="confirmed" data-sort="2021.5">
          <div class="case-year">2021<br>2022</div>
          <div class="case-node" aria-hidden="true"></div>
          <article class="case-content">
            <header class="case-header">
              <h3>HealthTech<br>Angular checkout → React</h3>
              <span class="case-status">Anonymous client</span>
              <h3>Helpshift<br>Native SDKs → shared JS core</h3>
              <span class="case-status">Customer-paced rollout</span>
            </header>
            <div class="case-metrics">
              <p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Checkout conversion increased 6 to 8%. Disruptions caused by navigation or payment-window closure fell 30%.</p>
              <p class="metric" data-metric="duration"><span class="metric-label">Duration</span>About 3 months elapsed.</p>
              <p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>Medium. Revenue-critical flow, navigation and payment state risk, bounded frontend scope, and one cutover.</p>
              <p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Faster SDK delivery, consistent behavior across platforms, lower duplicated maintenance cost, and broader customer upgrade reach.</p>
              <p class="metric" data-metric="duration"><span class="metric-label">Duration</span>4 to 6 months elapsed.</p>
              <p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. Multi-platform compatibility, version support, customer-controlled upgrades, and coordinated releases.</p>
            </div>
            <div class="case-facts">
              <section><h4>The change</h4><p>Angular checkout to React, with checkout reliability improvements delivered during migration.</p></section>
              <section><h4>The constraint</h4><p>Protect customer progress and transaction completion through refreshes, back navigation, and payment-window closure.</p></section>
              <section><h4>The method</h4><ul><li>Persist early checkout state in local storage.</li><li>Use a reopenable payment popup.</li><li>Release through one controlled cutover.</li></ul></section>
              <section><h4>The change</h4><p>Separate iOS, Android, and Unity or game-engine SDK implementations to a shared JavaScript core.</p></section>
              <section><h4>The constraint</h4><p>Keep existing native versions supported while customers choose their upgrade timing.</p></section>
              <section><h4>The method</h4><p>Validate shared behavior across all three platform families, then release through versioned opt-in.</p></section>
            </div>
            <p class="case-ai"><span>AI-assisted?</span>Yes.</p>
            <p class="case-ai"><span>AI-assisted?</span>No.</p>
          </article>
        </li>
        <li class="migration-case reveal" data-case="reify-retool-to-react-and-clojure" data-evidence="confirmed" data-sort="2026">
          <div class="case-year">2025<br>2026</div>
        <li class="migration-case reveal" data-case="helpshift-aws-california-to-virginia" data-evidence="confirmed" data-sort="2021">
          <div class="case-year">2021</div>
          <div class="case-node" aria-hidden="true"></div>
          <article class="case-content">
            <header class="case-header">
              <h3>Reify<br>Retool → React + Clojure</h3>
              <span class="case-status">Internal operations</span>
              <h3>Helpshift<br>AWS California → Virginia</h3>
              <span class="case-status">Zero downtime</span>
            </header>
            <div class="case-metrics">
              <p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Higher reliability and lower operating cost for internal workflows.</p>
              <p class="metric" data-metric="duration"><span class="metric-label">Duration</span>Under 3 months elapsed.</p>
              <p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. Live staff operations, integrations and data contracts, and multi-team coordination.</p>
              <p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Lower infrastructure cost, higher reliability, and a current critical stack with a clear path to later Java and AWS Graviton modernization.</p>
              <p class="metric" data-metric="duration"><span class="metric-label">Duration</span>9 months from start through production rollout. Active engineering duration remains to be normalized.</p>
              <p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. Zero downtime, broad dependencies, data and traffic cutover, and a rotating 9 to 25 person roster.</p>
            </div>
            <div class="case-facts">
              <section><h4>The change</h4><p>Internal operations workflows moved from Retool to a custom React and Clojure implementation.</p></section>
              <section><h4>The constraint</h4><p>Keep live staff operations working across integrations and data dependencies.</p></section>
              <section><h4>The method</h4><p>Move workflow by workflow from Retool into the custom system.</p></section>
              <section><h4>The change</h4><p>AWS California to AWS Virginia, plus Postgres, Mongo, Kafka, Redis, Flink, Hadoop, Spark, Elasticsearch, ScyllaDB, and Java modernization.</p></section>
              <section><h4>The constraint</h4><p>Move a B2B customer portfolio without interruption, including a long tail and very large customers.</p></section>
              <section><h4>The method</h4><ul><li>Audit dependencies and upgrade target services in waves.</li><li>Establish dual-run and replication paths.</li><li>Move smallest customers first, then largest.</li></ul></section>
            </div>
            <p class="case-ai"><span>AI-assisted?</span>Yes.</p>
            <p class="case-ai"><span>AI-assisted?</span>No.</p>
          </article>
        </li>
        <li class="migration-case reveal" data-case="celerity-java-to-python" data-evidence="confirmed" data-sort="2026.5">
          <div class="case-year">2026</div>
        <li class="migration-case reveal" data-case="helpshift-yui-to-react" data-evidence="confirmed" data-sort="2017">
          <div class="case-year">2015<br>2017</div>
          <div class="case-node" aria-hidden="true"></div>
          <article class="case-content">
            <header class="case-header">
              <h3>Celerity<br>Java → Python backend</h3>
              <span class="case-status">Unreleased target</span>
              <h3>Helpshift<br>YUI → React</h3>
              <span class="case-status">Live system</span>
            </header>
            <div class="case-metrics">
              <p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Removed vendor lock-in, returned direct product change control, reduced source maintenance surface 55%, and created 4 independently deployable and scalable processes.</p>
              <p class="metric" data-metric="duration"><span class="metric-label">Duration</span>4 active weeks. Original Java build took about 21 active weeks. Two more weeks would have avoided overtime.</p>
              <p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. Two strict mobile contracts, Kafka compatibility, hidden framework behavior, data and storage invariants, and a compressed finish.</p>
              <p class="metric" data-field="impact"><span class="metric-label">Business impact</span>Product roadmap never paused. React improved future delivery, performance, reliability, consistency, usability, and extensibility.</p>
              <p class="metric" data-metric="duration"><span class="metric-label">Duration</span>About 2 years elapsed.</p>
              <p class="metric" data-metric="complexity"><span class="metric-label">Complexity</span>High. Live product, broad UI surface, long coexistence, and uninterrupted feature work.</p>
            </div>
            <div class="case-facts">
              <section><h4>The change</h4><p>Java Quarkus monolith to Python FastAPI API, consumer, renderer, and dispatcher.</p></section>
              <section><h4>The constraint</h4><p>Live iOS and Android clients defined compatibility, but Python target was unreleased. This was not a live production cutover.</p></section>
              <section><h4>The method</h4><ul><li>Extract contracts from mobile clients.</li><li>Verify API, database, and storage behavior against real stack.</li><li>Use 101 client contract assertions and 247 live-stack checks per gate.</li></ul></section>
              <section><h4>The change</h4><p>YUI frontend to React.</p></section>
              <section><h4>The constraint</h4><p>Keep shipping product features throughout migration.</p></section>
              <section><h4>The method</h4><p>Move incrementally by product surface while YUI and React coexist.</p></section>
            </div>
            <p class="case-ai"><span>AI-assisted?</span>Yes. Claude Code agents did substantial build and verification work; humans defined contracts, gates, and architectural boundaries.</p>
            <a class="deep-dive" data-deep-dive href="https://thing.unravel.tech/kapil/terra-incognita-before-you-migrate" rel="noopener">Read Terra Incognita, the detailed migration account →</a>
            <p class="case-ai"><span>AI-assisted?</span>No. Pre-LLM delivery.</p>
          </article>
        </li>
      </ol>
    </section>
    <section class="patterns" id="patterns" aria-labelledby="patterns-title">
      <div class="section-shell">
        <header class="reveal">
          <p class="kicker">What repeated</p>
          <h2 id="patterns-title">Judgment before machinery.</h2>
        </header>
        <ol class="pattern-list reveal">
          <li><div><h3>Business continuity sets architecture.</h3><p>Zero downtime, customer-paced upgrades, and continuous feature work each demand different migration shapes.</p></div></li>
          <li><div><h3>Parallel paths buy reversibility.</h3><p>Dual databases, coexistence, staged customer cohorts, and versioned opt-in reduce irreversible cutover risk.</p></div></li>
          <li><div><h3>Contracts beat source translation.</h3><p>Consumers, wire formats, and data invariants define what must survive. Languages and frameworks are implementation choices.</p></div></li>
          <li><div><h3>AI speed needs stronger gates.</h3><p>Four-week delivery was possible because human-defined contracts and live-stack checks could reject machine-speed mistakes.</p></div></li>
        </ol>
      </div>
    </section>
    <section class="discovery" id="discovery" aria-labelledby="discovery-title">
⋯ 77 unchanged lines