Technical whitepaper · July 2026 · v1.0

MigrationGuard: architecture and verification

How generated schema catalogs, human-approved mappings, and an exact-arithmetic engine move a ledger from QuickBooks Online to NetSuite — with every claim in this paper stated against its evidentiary basis.

Executive summary

Financial migrations rarely fail loudly. They fail quietly: an enumeration validated against the wrong value set, a boolean copied without noticing the target stores its inverse, a column summed in floating point that drifts a cent at a time. Each passes a demo. Each corrupts a ledger.

MigrationGuard is built on one refusal: nothing in the pipeline may rest on an assumption that cannot be traced to a published vendor schema or measured from the customer's own data. Field names and permitted values are generated from schemas Intuit and Oracle publish. Requiredness — which those schemas deliberately cannot supply — is measured by profiling, never defaulted. Every mapping is approved by a named human, with the machine's confidence and reasoning shown. And after the load, the engine recomputes each business figure from the source and reads the same figure back from NetSuite, producing a reconciliation an auditor can read.

This paper describes the architecture as built and verified and states plainly which components remain in build.

The problem

Silent corruption beats loud failure

A crashed migration is recoverable; a plausible one is not. During MigrationGuard's own build, two defects of exactly this class were caught before a line of transform code existed. A specification assumed QuickBooks has five account types; Intuit's schema defines sixteen, and the five-value rule would have rejected every bank account, every receivables and payables control account, and all income — surfacing only later as an inexplicable trial-balance failure. The same specification mapped Active to isActive; NetSuite has no such field. It stores isInactive, the logical inverse, and a straight copy would have deactivated every migrated record.

Documentation you can't machine-read isn't a source of truth

Intuit's per-entity reference pages are a client-rendered application: an HTTP fetch returns a loading stub with no field content. Oracle's REST field catalog is rendered per account, behind authentication. A pipeline whose correctness depends on prose pages that cannot be fetched, diffed, or versioned is a pipeline built on transcription — and transcription is where invented field names come from.

The schema cannot tell you what's required

Across the 2,309 fields in Intuit's schemas, only 15 carry a minimum-occurrence constraint. One schema serves QuickBooks Online and Desktop, and serves create, update and read payloads alike, so it is permissive by construction. Requiredness must therefore be established empirically, from the tenant being migrated — which is why profiling is a gate in this architecture, not a convenience.

Architecture

Generated catalogs, not transcribed ones

The QuickBooks catalog is extracted from the XSD schemas Intuit publishes to generate its own official V3 SDK — 81 entities, 104 enumerations, 2,309 fields, with inheritance resolved and Intuit's embedded business-rule annotations captured as citable data-quality seeds. The NetSuite catalog is extracted from Oracle's published SuiteTalk schemas — 189 record types, 273 enumerations, 7,117 fields. Both are produced by scripts, so a vendor schema release regenerates the catalog rather than triggering a re-transcription.

Inference that shows its work

Every source column receives a proposed target with a confidence band — curated, high, medium, low, or none — and a stated reason. Confident matches arrive pre-approved; everything else arrives unticked, so the default action is review, not acceptance. Curated hints are validated against both catalogs at load time: a hint naming a field that does not exist is dropped and reported, never silently applied. Enumerated columns additionally receive a value translation; all sixteen QuickBooks account types resolve to their NetSuite counterparts mechanically, and any value left untranslated rejects its records rather than guessing.

A high-throughput ETL engine that refuses

Monetary amounts are integer minor units with per-currency scale — two decimals for USD, zero for JPY, three for KWD — parsed digit-by-digit with no floating point, every operation overflow-trapped. A value with more precision than its currency permits is rejected, not rounded: the caller must decide, in writing, what rounding is acceptable. The engine is built as a batch ETL core engineered for throughput — batched writes, configurable rate limiting and concurrency, and checkpointed resume so a large load restarts where it stopped rather than from row one. Consistent with this paper’s policy, measured throughput figures will be published with their benchmark basis once runs against live endpoints exist. The configuration loader enforces the same discipline upstream — a mapping whose requiredness is still UNVERIFIED stops the run.

A migration that will not start is recoverable. One that silently dropped a mandatory field, or rounded a half-cent ten thousand times, is not.

Reconciliation as a deliverable

After the load, eight checks recompute from source and read back from NetSuite: row counts, amount totals, receivables by customer, payables by vendor, the trial balance, chart-of-accounts structure, dangling references, and an itemised exception report. The default monetary tolerance is zero. A tolerance above zero must be justified in writing, because a cent of accepted drift per row across a hundred thousand rows is a thousand dollars no one can explain.

Verification

MigrationGuard publishes verification evidence, not performance benchmarks — none have been run yet, and this paper will not invent them. Every figure below states its basis.

MeasureResultBasis
Engine test assertions55 / 55 pass GCC 13.3 · -Wall -Wextra -Werror -Wconversion · Jul 2026
INI contract, cross-language parity7 / 7 fixtures identical High Fidelity structural diff parser
Account-type value translation16 / 16 at high confidence Intuit AccountTypeEnum ↔ Oracle AccountType
QuickBooks catalog81 entities · 2,309 fields Intuit V3 SDK XSDs, v6.5.5, commit c4d5dfa
NetSuite catalog189 records · 7,117 fields Oracle SuiteTalk WSDL v2019.1
Exactness property10,000 × 0.01 = 100.00 test_core.cpp — false in IEEE-754 double
Unverified-required interlockrun refused generated 77-mapping config, gate demonstrated in test

Reproduction: every artifact above is generated or compiled from the repository; catalogs regenerate from vendor schemas by script.

Deployment model

The engine writes to NetSuite over SuiteTalk REST. This is not a preference: Oracle's own schedule names 2025.2 as the last planned SOAP endpoint and removes SOAP at 2028.2, at which point existing SOAP integrations stop working. The SOAP schemas are used at build time only, as the sole public machine-readable catalog of the NetSuite record model; no SOAP client ships in the engine.

Two items are disclosed as open in the project's own unverified-items register: target field names remain provisional until reconciled against the customer account's REST metadata catalog, and account-level rate limits are read from the account, never assumed. Engineering that discloses its open questions is the same engineering that caught the sixteen account types.

About Pacific Data Integrators

Pacific Data Integrators builds data platforms and migration accelerators for enterprise systems. MigrationGuard™ for QuickBooks Online → NetSuite joins PDI's product family alongside its SAP ECC to S/4HANA Accelerator.

Bring your chart of accounts.

A briefing runs against your entity list, not a demo set.

Request a briefing