previews · sprint reports · Data Migration Engine · Sprint 1

Sprint 1 — The migration engine takes shape

The squad's first sprint. The four-stage architecture was agreed and written down, the import service merged into platform-v3, the boundary-schema contract landed on both sides of the pipeline, and extraction and mapping started for both source firms.

✅ Final Sprint 1 · Aug 6 → Aug 19 2026 · numbers as of Aug 18 Engine · Lukas, Daniele, Cesar · Adolfo joined for the import-service close Migration projects · Cameron, Aadam, Sally, Kha-Ai Linear · Build & Test Migration Engine [LLL V2 > V3] Notion · Data Migration Hub Design docs · firm-migrations Deck · review deck
TL;DR

The squad formed on 2 August to move two firms into platform v3: Lawhive Legal off v2, and Woodstock off LEAP. In its first sprint it published 14 design docs that settle the architecture, merged the import service into platform-v3 (23 PRs on develop), and proved the load path end to end by importing a full 714-matter dev firm, tearing it down, and importing it again.

39 of the team's 68 tickets are Done, all verified against trunk. The remaining halves of the pipeline, extraction and mapping for each source firm, are in flight: the first v2 staged slice and the Dagster packet exporter are in review, and the LEAP mapping has been rehearsed over Woodstock's full book. Around the engine, the operational track stood up the programme itself: a migration-project template with phased gates, the RACI, a data dictionary, and testing plans that define what done looks like.

Sprint health

39/ 68
Tickets done
verified against trunk, not Linear columns
27PRs
Landed
23 platform-v3 · 3 data-dbt · 1 infra
14docs
Design docs published
architecture, schemas, mappings, runbook
714matters
End-to-end rehearsal
full dev firm imported, torn down, re-imported

Tickets by status

The team does not point tickets, so these are counts, not points. One ticket is closed as a duplicate and excluded.

Done (57%) In review (7%) In progress (9%) Backlog (26%)

What we are migrating

Two firms are waiting to move onto platform v3, and the engine this project builds is what moves them. Lawhive Legal runs on platform v2: 37,958 cases, 1.65 million files, 1.8 TB of documents. Woodstock runs on LEAP, a third-party practice-management system: 27,005 matters going back to 2014. The engine is deliberately source-agnostic, so every migration after these two reuses the same pipeline and the same import service.

How we are building it: four stages, one contract

The pipeline has four stages. The first three live in the data platform and turn whatever a source firm can give us into a standard package. The fourth lives in platform-v3 and loads that package into the product. The two halves only meet at the package, so each half is built and tested on its own.

Data pipeline · BigQuery, dbt, Dagster
Stage 1
Extract
Source data lands raw in BigQuery. v2 already replicates continuously; LEAP arrives as report exports today, with an API route identified for documents.
Stage 2
Stage & map
dbt models reshape source rows into the canonical form: one model per boundary table, per source. This is where source quirks are resolved and recorded.
Stage 3
Package
Dagster exports one sorted JSONL file per boundary table, plus a manifest of row counts and checksums, into a regulated S3 bucket.
Platform · platform-v3
Stage 4
Load
The import service streams the package, validates every row against the boundary schemas, and writes into the service databases, recording provenance for every inserted row so a run can be verified and undone.
The contract 17 boundary schemas define what a "ready to load" firm looks like: matters, participants, contacts, files, notes, tasks, and the rest. They are Zod schemas in platform-v3, and a generator emits matching dbt contracts into the warehouse, so the two halves cannot drift apart silently.

The isolation is the point: the pipeline side never touches a production database, the import service never needs to know what LEAP or v2 look like, and any future source that can produce the package can be migrated.

The four fronts of the sprint

The squad formed and planned inside this window, so its goals were set at the programme kick-off as end-of-August targets rather than sprint commitments. These are the four engine fronts the work organised around, each validated against trunk; the operational track has its own section below.

Front 1

Architecture agreed and written down

Done

14 design docs published to firm-migrations by Lukas, Daniele and Adolfo. The import service v2 plan is the build reference: it folded a full review round and a working MVP into one document before the code merged, so code review was about code, not direction.

The docs and what each settles
Front 2 · Heart of the sprint

The import service merged into platform-v3

Merged to develop

Lukas built the service as a 13-PR stack; it was hardened through review and security review, and the full stack merged on 18 August. It reads a package through forward-only cursors, assembles and validates one unit at a time, writes each unit and its provenance in a single transaction, derives a per-cell run report, and can tear a run down to zero. Dry run and real run share the same code path.

What the merge includes, and what it proved
  • #13548–#13606: scaffold, boundary catalogue, own database, cursors, writers, importers, walk, run report, control API, runbook
  • End-to-end rehearsal on the 714-matter dev firm: 10,184 rows, zero failures, dry run identical to apply, teardown back to zero
  • Security review passed: real runs are gated on super-admin and refused in production until the service is deliberately enabled there
  • Not yet in place, and named as next steps: deployment wiring (nothing ships the image yet) and a real file store (imported file rows carry no bytes yet)
Front 3

The contract, landed on both sides

Landed · sync in review

Daniele landed the contract in both repos. The 17 boundary Zod schemas merged in platform-v3 (DM-25, DM-30), the zod-to-dbt generator merged alongside them (#13585), and the receiving dbt package landed in data-dbt (DM-64). The GitHub Action that keeps the two repos in sync automatically is in review (DM-66, DM-17).

Why the generator matters
  • The Zod schemas in platform-v3 are the single source of truth; the generator emits matching dbt schema.yml contracts, so a pipeline model that drifts from the contract fails its build instead of failing at load time
  • Extension in review adds primary-key and parent tests plus the dump ORDER BY, which is what makes stage 3's sorted files trustworthy
Front 4

v3 made ready to receive

Done

The platform work that has to exist before any firm's data arrives. Matter references (humanReadableId) became per-firm strings across the whole product, so an imported matter keeps the reference its firm has always cited (8 PRs, DM-5, DM-7–13). Every service database gained the ImportedRecord provenance table. Imported matters carry their own origin (MatterSource.IMPORT).

Infrastructure and data protection
  • Regulated migration dump S3 bucket provisioned via Terraform (DM-22), registered for backup (infra #192), with Dagster granted access (DM-23)
  • Retention, protection and backup policy for migration data written and agreed (DM-61)
  • In the warehouse: a single-source-of-truth Staff PII tag taxonomy (data-dbt #3835)

The two sources: extraction and mapping

Stage 1 and 2 work, per source firm. This is where Cesar's pipeline work and the mapping investigations live.

Lawhive Legal · from platform v2

  • The mapping is written and proven. The v2 mapping doc ships a working transform: one real closed matter carried across all 17 boundary tables.
  • Coverage is measured: 28% of the firm's book maps onto the catalogue today, another 17% could map with agreed catalogue additions, and 52% is money data, deliberately parked for a later, separately signed-off wave.
  • First staged slice in review: v2 Cases shaped into the matter boundary in dbt, reworked after review into a four-PR stack (data-dbt #3823–#3826) that adds staging models, mapping seeds, the boundary catalogue as a dbt package, and the Dagster-ready JSONL exporter.

Woodstock · from LEAP

  • The full book is profiled: 27,198 matter rows and 26,027 client rows from LEAP's own exports, refreshed into the warehouse twice this sprint.
  • The mapping has been rehearsed end to end over the whole book: 100% of source rows resolved, mapped, or excluded with a written reason (LEAP mapping doc). The status model is decided: LEAP's 58 statuses collapse to v3's four lifecycle states, and the original status is kept as a firm-scoped field.
  • The gaps are named: the exports carry no machine key between matters and clients (name-matching links 65%), so a client-id export has been requested; documents are not in any export and need the LEAP API route.
  • The risk is external: LEAP's automated feed has been dead since March, and access decisions sit with LEAP, not with us. This is the Woodstock critical path.

The operational track

The programme is deliberately not run as a purely technical project; the Data Migration Hub names that as its highest risk. Alongside the engine there is a second pillar, Migration Projects: one operational workstream per source firm, coordinated by Cameron with Aadam, Sally and Kha-Ai. Its job is the business half of a migration: data-quality agreements, mappings someone who uses the data has signed, validation the firm's own people can read, and named sign-offs. This sprint it stood up the programme scaffolding on Notion:

Programme

The hub and the project template

Stood up

The Data Migration Hub is the programme home: goals, the two pillars, and where each kind of truth lives (Notion for owners and status, Linear DM for current work, firm-migrations for design decisions). The Migration Projects template defines the five phases every migration runs, discovery through cutover, with ten gates, each carrying an exit condition and a named deliverable, and a per-phase table of what the business track owes versus what the technical track owes.

First project · Lawhive Legal UK

Scoped, staffed, and testable

In motion

The RACI names who owns what across the project, engine, enablement, product, engineering, data and the business side. A v2 → v3 data dictionary gives everyone the same vocabulary. Testing plans per track define what done looks like for the first slice: one matter run end to end in dev, every automated check green, run twice with the same result, and a lawyer can open the migrated matter and work with it. A pre-mortem lists the risks with actions.

One rule from the template worth repeating, because it de-risks Woodstock: discovery does not close until extraction has been proven by a spike, and the LEAP contract is never terminated until the extract is verified — LEAP allows only a 30-day window from termination.

Where the milestones stand

Staging & infrastructure ready
50%
Platform v3 migration readiness
50%
Data contracts / canonical model
33%
Import-service readiness
30%
Files migration mapping
25%
E2E load of matter
17%
Canonical mapping · Full load on dev · Testing framework · Verification · Live
≤5%

Milestone progress from the Linear project after the close-of-sprint status sync. Milestones are delivery goals that pull tickets across areas; the project targets 20 October for the full LLL load.

In flight at close

TicketWhatState
DM-46 / 49Dagster JSONL packet exporter + canonical models as a source-parameterized dbt package (data-dbt #3823–#3826)In review
DM-17 / 66 / 69Zod→dbt: PK/parent tests, dump ordering, the cross-repo sync GitHub Action, and dbt-parse validation of the generated modelsIn review
DM-47 / 53 / 54Idempotency semantics, the adapter contract for new sources, and reconciliation models so nothing is silently droppedIn progress
DM-44 / 16 / 65Dagster job shape for the canonical dbt build, and the GitHub App auth for the sync workflowIn progress

Lessons learnt

What went well

  • Docs before code paid off. The import-service plan absorbed a full review round and an MVP proof before the stack merged, so the expensive decisions (S3 dumps over BigQuery reads, Inngest batch-ping over a bespoke worker) were settled once, in writing.
  • The contract let three people build in three repos at once. Platform, warehouse and orchestration work proceeded in parallel against the same 17 schemas, without waiting on each other.
  • Provisioning was sequenced right. The service's database Terraform was applied before the stack merged, so the deploy pipeline's migration checks passed on the first develop deploy instead of blocking every deploy in the company.

What to improve

  • Graphite's merge queue closes PRs instead of merging them, so Linear never moves tickets on its own. 26 tickets whose code was already on trunk still read "In Review" at close and were synced by hand. Worth wiring or scripting before next sprint's close.
  • Agree what Done means for the per-entity boundary tickets. The catalogue PR landed all 17 schemas at once; the per-entity tickets were closed with it. If the team wants per-entity review to a deeper bar, that is new tickets, not reopened ones.
  • The Woodstock critical path is outside the squad. The client-id export ask and LEAP API access need named owners and dates, or the LEAP half of the project waits on unmanaged externalities.

Next sprint

Pending sprint planning; these are the fronts the backlog already points at.

Front Work
First slice end to end One v2 matter through all four stages into v3 on dev (DM-68): the first time the pipeline and the import service meet on a real environment
Pipeline Land the in-review dbt stack · v2 staging models for all in-scope entities (DM-62) · the packet exporter running inside Dagster (DM-43/44)
Import service Deployment wiring so the service actually ships · a real file store so imported file rows carry bytes · the walker and cursor tickets that survived into the backlog (DM-19/20)
Verification Reconciliation models (DM-54) · the coverage loop over the full Lawhive Legal book · fixture-driven integration tests (DM-58)