Source truth:
- ../truth/decisions/accepted/0032-qbo-first-controlled-cutover.md
- ../truth/contracts/company-conversion-run.contract.md
- ../truth/contracts/accounting-import-run.contract.md
- ../truth/contracts/accounting-import-candidate.contract.md
- ../truth/contracts/qbo-conversion-connector.contract.md
Last reviewed: 2026-08-01
QBO Controlled-Cutover Fixture Profile
This profile is replacement-scenario infrastructure. It applies when an
existing QBO accounting instance is being replaced by BooksPlus. Startup-
scenario company creation uses ordinary setup and must not manufacture a QBO
connection, capture, qualified package, or CompanyConversionRun.
This page records the Draft provider compatibility, mapping, control-schedule, and live-capture foundation qualified by Step 14, Slices 14B through 14D. It does not add accounting meaning. The accepted QBO controlled-cutover decision and canonical contracts remain authoritative.
Qualified fixtures
The qualified inputs are BooksPlus-owned JSON fixture packages in the bp3
domain-test data. They are representative, non-sensitive, and
documentation-derived; they are not raw QuickBooks Online exports, captured
API responses, or production company data.
Fixture identity:
- profile key:
qbo-controlled-cutover-fixture; - profile version:
2; - compatibility identity:
qbo-fixture-package-v2; - fixture kind:
representative_non_production; - source form:
documentation_derived_fixture_package; - declared edition:
qbo_us_sandbox; - baseline fixture
qbo-controlled-cutover-v1.jsonSHA-256:3fccb8da9b688ff2cbcdf7e82403ac7e70ca04666fff519af422d8801c483020; - chart-complete fixture
qbo-controlled-cutover-chart-mapping-v1.jsonSHA-256:4ae2c92be0bb364c113328d5af290333e69b215a8698d72f6a8c8a5b9792ac79.
The baseline fixture deliberately exposes a trial-balance account without a matching account fact and therefore proves the missing-source-account blocker. The chart-complete fixture adds that exact account fact and is the successful mapping, control, and approval fixture. Both use the version 2 package contract with explicit control applicability.
AccountingImportRun preserves the exact package bytes, file hash, source
system, profile identity, company scope, accepted time, and company currency.
The profile also retains the raw JSON text for every supported company,
account, trial-balance line, trial-balance report, and object-state fact.
Draft provider support matrix
| Concern | Qualified in version 2 | Not qualified |
|---|---|---|
| QBO edition | Two US sandbox-shaped representative fixtures | Other countries, editions, feature combinations, and production companies |
| Input form | BooksPlus fixture-package JSON with exact payload hash | Native QBO files, spreadsheets, arbitrary JSON, raw API envelopes, or Desktop files |
| Transport | Previously staged fixture payload and versioned qbo-live-api-capture-v1 manifest |
Recurring polling, webhooks, change-data capture, writes, or synchronization |
| Source company | Explicit realmId, repeated selectedRealmId, CompanyInfo subset, and expected realm check |
Realm discovery, user-company lists, or implicit company choice |
| Accounting settings | Home currency, country, declared edition, minor-version metadata, capture timestamp, and cutover date | Fiscal-year, tax, multicurrency, closing-date, or locale behavior not present in the package |
| Chart facts | Account Id, SyncToken, name, optional number, type, optional subtype, active state, currency, and modified time |
Automatic BooksPlus target selection, chart mutation, or provider account semantics becoming canonical |
| Opening position | One accrual-basis, company-currency trial balance at the selected cutover date, with account identity and exact debit/credit text | Cash basis, comparative periods, foreign currency, posting, or a claim that report rows are ledger lines |
| Cutover controls | Explicit applicability, amount, count, source-account ids, and evidence for receivables, payables, inventory, bank, credit card, sales tax, payroll liabilities, and retained earnings/prior income; bank controls include checks, deposits, payments, and transfers | Materiality policy, inferred applicability, operational subledger creation, or provider reconciliation becoming ledger truth |
| Object changes | Explicit fixture evidence for changed, inactive, voided, deleted, and merged states | Inferring deletion, merge, void, or history from absence or descriptive text |
| Other QBO objects | May be retained later as non-posting control evidence | Customer, vendor, item, receivable, payable, banking, payroll, fixed-asset, inventory, or transaction masters |
The package field names are a stable BooksPlus compatibility contract, not a claim that raw QBO response casing or envelopes have the same shape. A later captured-response or live connector profile must translate provider responses into this review boundary and earn its own compatibility identity and tests.
Live capture boundary
Slice 14D adds the canonical QBO Conversion Connector Contract and a read-only HTTP client for sandbox or production realm-scoped endpoints. One explicitly confirmed QBO realm is bound to one BooksPlus company before capture. The desktop stores no provider client secret. A separately deployed authorization broker must perform any client-secret-bearing callback, code exchange, token refresh, or revocation and hand BooksPlus a short-lived exact- realm token bundle.
BooksPlus encrypts token bundles and provider responses with the company data-
protection service. One restartable extraction checkpoints CompanyInfo, every
deterministically paged Account response, and TrialBalance, BalanceSheet,
AgedReceivables, AgedPayables, InventoryValuationSummary, and
SalesTaxLiability reports at the cutover date. Completed checkpoint bytes are
never fetched again during resume. Throttling, timeout, and temporary provider
failure preserve in_progress; authentication failure additionally marks the
connection reauthorization_required.
Only a complete ordered manifest enters AccountingImportIntakeService under
profile qbo-live-api-capture version 1. The manifest contains protected-
payload identities, response hashes, lengths, request identities, capture
times, and provider request ids, but no token, raw response, customer name,
account name, or amount. PostgreSQL and company backup version
company-snapshot-v23 / bp3-schema-202608130002 preserve connections,
encrypted credentials, interrupted checkpoints, and completed import links.
This capture is not yet a qualified live conversion profile. Slice 14E must translate and compare live response shapes to the version 2 controlled-cutover facts, prove every applicable control, and hold unavailable or inconsistent provider evidence.
Qualified live package
QboLiveCaptureQualificationService reads only a completed extraction after
authorizing qbo_conversion_extraction.qualify. It verifies the immutable
manifest, checkpoint sequence, protected-response ownership and purpose,
authenticated recovery, byte length, and SHA-256 before translation.
A successful translation stages qbo-controlled-cutover-live version 1
with compatibility identity qbo-live-qualified-package-v1. The package uses
the same company, account, opening trial-balance, eight-schedule, and object-
state fact shape as the fixture profile, so the existing mapping,
reconciliation, approval, recovery, and application path re-parses the same
immutable payload throughout.
Qualification fails closed. Missing report totals, account/report identity gaps, nonzero controls without applicable accounts, source-control differences, or mismatched date/currency/basis stage no qualified import. The current capture does not include bank outstanding checks, deposits, payments, and transfers; therefore any applicable bank account is a visible qualification blocker. No operator-entered or inferred zero substitutes for missing evidence.
Identity, dates, and normalization
realmIdidentifies the selected QBO company. A mismatch between the package realm, its repeated selection evidence, and the conversion context is a blocking issue.- An account source identity is
qbo.account/{Id}@{SyncToken}. MissingIdorSyncTokenholds the proposal. Repeated identical IDs are visible duplicates; changed values under the same ID are conflicts. - A trial-balance control identity includes its date, basis, and exact package SHA-256. It is a control fact, not a source event or posting identity.
- Package and trial-balance dates must equal the selected cutover date. Timestamps require ISO 8601 offset form. No local-time assumption is made.
- Decimal source text is retained before invariant-culture parsing. Negative, dual-sided, malformed, or unbalanced values are blocking issues.
- Account names are normalized only to detect ambiguous mapping proposals. They never select a BooksPlus account automatically.
Chart mapping review
QboChartMappingReviewService version 1 requires one explicit decision for
every qualified QBO account:
- map to one exact active same-company BooksPlus account id;
- stage one explicitly classified active account for creation; or
- exclude a non-balance-bearing source account with a reason.
The service does not infer BooksPlus type, normal balance, code, or account
identity from QBO account numbers, names, types, or subtypes. A new-account
decision supplies those BooksPlus values explicitly and becomes a row in the
canonical staged ChartImportBatch. Account creation and its authorization,
history, and audit remain owned by chart-import commit and account maintenance.
The caller supplies the current mapping-review actor explicitly; chart staging
does not reuse the earlier import-intake actor by assumption.
Mapping review uses fingerprint schema qbo-chart-mapping-v1. The lowercase
SHA-256 binds company, import run, payload hash, realm, profile version,
mapping version, source identities and raw-object hashes, and every normalized
decision. Decision order does not affect the fingerprint. An exact replay
reuses its existing staged chart batch; changed meaning under an already staged
mapping version is a conflict.
The immutable review result records source identity, disposition, exact target account id and version for existing targets, or the staged chart row for a new target. Missing source facts or decisions, duplicate decisions, unknown source accounts, inactive source or target accounts, duplicate targets or codes, balance-bearing exclusions, and chart-import validation errors block dependent conversion work.
The transient review result is not itself accepted conversion state. Slice
14C2A copies its exact mapping identity, version, fingerprint, decisions,
dispositions, and staged chart references into the durable
CompanyConversionRun before control evaluation. This boundary avoids creating
a second mapping or chart workflow.
Conversion controls and approval
Profile version 2 requires every supported control-schedule family to appear exactly once. An applicable schedule supplies its normal balance, exact control amount, record count, source trial-balance account ids, and evidence references. A non-applicable schedule supplies an explicit reason and cannot claim an amount or account. Applicable bank controls explicitly enumerate outstanding checks, deposits, payments, and transfers, including zero counts and amounts.
CompanyConversionWorkflowService compares these schedules to the exact
opening trial balance selected by the durable mapping. Control result version
conversion-control-v1 contains trial-balance equality, balance-sheet
equality, all eight schedule outcomes, outstanding instruments, source and
mapping disposition counts and amounts, evidence, and a deterministic
fingerprint. Exact equality is required because no accepted materiality policy
currently authorizes an immaterial-difference threshold. Blocked evaluations
remain durable in mapped; only a result with matched or explicitly
not-applicable controls reaches reconciled.
Approval version conversion-approval-v1 binds the BooksPlus company and
selected source company, source links and hashes, profile, cutover date and
currency, mapping selection, control result and dispositions, and approving
actor. The protected approval command requires visible confirmation of that
exact fingerprint and source-company identity. It does not commit the chart,
create accounts or Source Documents, or post opening balances.
Application and recovery
Application version conversion-application-v1 requires a separate protected
apply decision and the same visible approval-fingerprint and source-company
confirmation. The run enters durable applying before downstream mutation.
Its chart step commits the exact approved staged batch using the applying
actor's chart authority. Every resulting account is then bound to its mapping
ordinal, source identity, chart row, account id, and account version. Recovery
accepts those accounts only when batch-correlated account history proves their
origin; matching account codes are insufficient.
The opening step resolves every nonzero trial-balance line through the approved
existing-account mapping or the persisted chart results. It calls
OpeningBalanceSetupReviewService, which preserves readiness, company-
currency, eligible-period, Source Document, authorization, audit, and central
posting rules. A run-derived source identifier makes an interrupted posting
recoverable. Resume validates the exact posting date, explanation, lines,
currency, source evidence, actor, journal entry, Source Document, and posting
audit before reusing it.
The aggregate persists each completed step before beginning its successor.
Only both durable result sets plus the succeeded apply audit can produce
applied. PostgreSQL still enforces at most one applied controlled cutover per
company. Company backup version company-snapshot-v23 preserves applying and
applied recovery state with company-scoped result constraints.
Dispositions and limitations
Active, complete, company-currency account facts become non-posting mapping proposals. Inactive accounts and ambiguous names are held. Unsupported currency, missing identity, conflicting identity, invalid dates or amounts, voided, deleted, merged, and otherwise unsupported state evidence blocks qualification or dependent conversion work. Changed and exact-duplicate evidence remains visible for review.
Each fixture contains one inactive account and one explicit changed-object fact to exercise review behavior. There is no captured provider event stream that can establish delete or merge completeness. Absence from a fixture therefore has no state meaning.
The provider profile itself remains pure in-memory normalization. It has no repository, workflow, chart, Source Document, period, audit, ledger, network, or provider-client dependency. Mapping review remains non-mutating; only the separately protected conversion application coordinates canonical chart and opening-balance owners.
Provider references used for fixture shape
The representative fields and limitations were checked against Intuit's official documentation for the QuickBooks Online Accounting API, data queries, QuickBooks Online basics, and reports. Live connector behavior was also checked against Intuit's official OAuth 2.0 guidance, query and pagination guidance, and limits and throttles. Provider documentation is evidence for this Draft compatibility record only; it is not BooksPlus accounting truth.