Why this was needed
Between the initial Apr 8 migration and this date, dispatchers continued working in Airtable — adding new documents, fixing fuel-card statuses, updating phone numbers, and onboarding/deactivating drivers. TruxFlow's data drifted out of sync. This sweep reconciled the two systems for the in-scope set.
Scope: Active+Onboarding for drivers and trucks; Active for trailers; all carriers. Owners and contractors were explicitly skipped due to known data-quality issues on Airtable.
Overall result
Step 0 — ID mapping
Before any data movement, every TruxFlow record needed its Airtable counterpart's record ID, and every Airtable in-scope row needed the TruxFlow CUID. Two passes:
- Pass 1 — TF-side soft-match: trusted existing
airtableRecordIdfirst, then matched the unlinked majority by license number / unit number / trailer number / DOT — 161 PATCHes sent to Airtable. - Pass 2 — AT-side iteration: filled gaps where the TF row pointed at an out-of-scope AT row by redirecting the link to the in-scope row — 39 more filled, 35 stale links redirected, 29 obsolete CUIDs blanked.
- Pass 3 — Trailers without carrier scope:
trailerNumberproved unique org-wide, so dropped the carrier scope and filled 15 more.
Final coverage: Drivers 36/37 (97%), Trucks 36/36 (100%), Trailers 46/49 (94%), Carriers 17/18 (94%).
Step 1 — Document merge
For each in-scope entity: download Airtable CDN URL → upload to Linode S3 → insert Document row. Defensive defaults: dedupe by (relatedId, type, fileName); new docs default to isActive=false so existing favorites stay favorites (only the very first doc of a type for a given entity becomes the active one).
| Entity | Docs added | Newly active | History only |
|---|---|---|---|
| Drivers | 33 | 2 | 31 |
| Trucks | 23 | 6 | 17 |
| Trailers | 39 | 20 | 19 |
| Total | 95 | 28 | 67 |
Step 2 — Status mirror
For every TruxFlow row currently Active/Onboarding with an Airtable link, if the linked AT row was not Active/Onboarding, deactivate TruxFlow.
- 44 drivers deactivated (mostly recent test rows D-1474..D-1517 plus 1 real driver — Jose Luis Aguinga).
- 6 trucks deactivated.
- 6 trailers deactivated.
All matched what the team had already inactivated on Airtable. Guardrail: skipped rows with no AT link and rows on the "Archived" placeholder carrier.
Step 3 — Field merge (rule A)
Rule A: fill empty TruxFlow fields from Airtable, Airtable wins on both-populated conflicts, never wipe TruxFlow when Airtable is empty, ignore cosmetic differences.
Two normalizers added to suppress no-op conflicts:
- Phone equivalence: TF stores
+15804618783, AT stores(580) 461-8783— same data, compared digits-only. Reclassified 63 false conflicts. - Driver type alias: TF stores
Driver, AT storesCompany Driver. Same enum, different label. Mapped both to canonicalcompany.
| Entity | Updated | Notable |
|---|---|---|
| Trucks | 23 | 11 fuelCardStatus flips, 5 status overrides |
| Drivers | 10 | After type alias, real conflicts dropped 53 → 4 |
| Carriers | 3 | Phone-number cleanups |
Items that needed human attention afterwards
The merge couldn't auto-resolve everything. Surfaced the following for review:
- 3 known Active-vs-Active duplicates on Airtable — 1 driver pair, 2 trailer pairs.
- 1 driver, 3 trailers, and 1 carrier that exist on Airtable but never on TruxFlow (PTLZ202425 trailer was the most prominent — see the May 3 event).
- 14 drivers, 20 trucks, 32 trailers Active+Onboarding on TruxFlow with no Airtable link.
Most of these were addressed in the May 3 link-integrity event the next day.
Safety measures
- All writes ran with
AIRTABLE_SYNC_DISABLED=truekill switch on, so the merge wouldn't fire-back over the Airtable edits we were pulling in. - Postgres dumps taken before each entity-class write — recoverable rollback at any point.
- Dry-run pass before every live pass; live pass only after the dry-run plan was reviewed.