> ## Documentation Index
> Fetch the complete documentation index at: https://docs.arcuserp.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Subledger Drift Investigation

> When Arcus reports that an AR, AP, Inventory, or Sales Tax subledger no longer agrees with its GL control account, this guide walks the standard accountant workflow for finding the cause and posting the corrective journal entry.

<Note>
  Subledger drift is a CONTROL signal, not a posting prompt. A variance always
  means a source record, a posting rule, or a historical import needs review.
  Never close the variance with a blind journal entry; always understand the
  root cause first.
</Note>

## What Subledger Drift Means

Arcus tracks two views of the same money:

1. **The subledger** is the operational detail. AR = the sum of open invoice
   balances. AP = the sum of open vendor bill balances. Inventory = the sum
   of on-hand x weighted-average-cost across every location. Sales Tax
   Payable = tax collected on posted invoices not yet remitted.
2. **The GL control account** is the rolled-up financial statement view,
   driven entirely by posted journal entries.

In a clean system the two views must be equal to the penny. A non-zero
variance means a posting was made directly to the control account without a
matching source record, or a source record changed without a balancing
journal entry, or a historical import landed with mismatched halves.

## Where Arcus Surfaces Drift

| Surface                           | When it fires                                                           | What it shows                                                                                                         |
| --------------------------------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| **Dashboard banner**              | Any open browser session, top of dashboard                              | Amber (>$10 drift) or red (>$100 drift) card naming each out-of-balance subledger and the dollar gap                  |
| **Period-Close pre-close**        | Operator opens "Close Period" modal                                     | Inline amber banner listing every subledger out of balance, with the option to acknowledge and close anyway           |
| **GL Reconciliation page**        | `Accounting > GL Reconciliation`                                        | Full per-subledger detail: GL balance, subledger balance, variance, and a CSV export per subledger for offline review |
| **Period close response payload** | Backend emits `gl.subledger_drift_detected` event on every period close | Logged to the GL integrity check log for audit trail                                                                  |

## Common Root Causes

<AccordionGroup>
  <Accordion title="Deleted payment without GL reversal">
    The most common cause. An operator removed a customer payment from the
    UI but the original `DR Cash / CR AR` journal entry was not reversed.
    Result: GL AR is lower than the subledger by the deleted payment amount.

    **Fix:** find the missing payment via `Accounting > Account Ledger`
    filtered by the Cash account around the suspect date. Either re-post
    the payment if the deletion was an error, or post a corrective JE
    `DR AR / CR Cash` referencing the original payment id in the
    description.
  </Accordion>

  <Accordion title="Manual UPDATE bypassing the canonical writer">
    A developer or admin ran a direct SQL UPDATE on `orders.balance_due` or
    `accounts.credit_balance` outside the canonical helper. The subledger
    column changed but no journal entry was posted.

    **Fix:** identify the SQL change via the activity log. If the manual
    UPDATE was correct, post a corrective JE to align the GL. If it was an
    error, reverse the column UPDATE through the canonical workflow
    (re-post the payment, re-issue the credit memo, etc.).
  </Accordion>

  <Accordion title="Payment application mismatch">
    A customer payment was applied to multiple invoices but the application
    rows do not sum to the payment amount. This drifts AR subledger but not
    GL AR (the GL only sees the gross payment).

    **Fix:** open `Accounting > AR Management`, find the payment, and
    review its application rows. Re-apply the unapplied remainder, or post
    a writeoff for the unallocated amount.
  </Accordion>

  <Accordion title="Inventory adjustment with $0 cost">
    A positive inventory adjustment posted with `unit_cost = NULL` against a
    fresh product whose weighted-average-cost was \$0. The inventory units
    increased but the inventory subledger value did not, while the GL
    inventory control account may have posted at the system default.

    **Fix:** open `Inventory > Adjustments`, find the adjustment, and post
    a follow-up adjustment with the correct unit cost to bring the WAC
    back in line. The canonical helper now blocks this scenario
    (`ZeroCostAdjustmentError`) but historical entries may exist.
  </Accordion>

  <Accordion title="Voided invoice without GL reversal">
    An invoice was marked `voided` in the UI but the original posting JE
    was not reversed. GL AR overstates by the voided invoice amount.

    **Fix:** look up the voided invoice via `Orders` filtered by
    `invoice_status = voided`. Confirm the original posting JE exists and
    has NO reversal entry. Post a reversing JE
    `DR Sales Revenue / CR AR` for the invoice total (or whatever the
    original posting pattern was) and reference the invoice number in the
    description.
  </Accordion>

  <Accordion title="Historical import with unbalanced JE">
    A migration or one-time data load posted journal entries where debits
    did not equal credits across the population (each individual JE was
    balanced, but the population as a whole drifted because some source
    records were skipped or duplicated).

    **Fix:** export both the subledger detail and the GL transaction log
    for the migration window (CSV from GL Reconciliation + Account Ledger).
    Diff line-by-line in Excel to find the missing or duplicated rows. Post
    a single corrective JE covering the net difference, with a description
    citing the migration batch id.
  </Accordion>
</AccordionGroup>

## Investigation Workflow

<Steps>
  <Step title="Confirm the drift on GL Reconciliation">
    Open `Accounting > GL Reconciliation` and click **Run Reconciliation**.
    Verify the subledger and GL numbers shown on the dashboard banner
    match the reconciliation page. Refresh once if the numbers are stale.
  </Step>

  <Step title="Export the subledger detail">
    Click the **Export CSV** button on the variant's row (AR, AP, Inventory,
    or Tax). The CSV lists every source record (invoice, bill, balance,
    posted-tax order) with its individual contribution to the subledger
    total.
  </Step>

  <Step title="Export the GL detail">
    Open `Accounting > Account Ledger` and select the matching control
    account (1300 AR, 2000 AP, 1400 Inventory, 2200 Sales Tax Payable).
    Filter to the same date range. Export the journal entry lines.
  </Step>

  <Step title="Diff the two CSVs">
    Subtract subledger total from GL total. Sort each CSV by date and
    walk forward looking for the period when the two views diverged.
    Common pattern: one date where GL jumped without a matching
    subledger row, or vice versa.
  </Step>

  <Step title="Identify the bad source record">
    Once the divergence date is known, open the source workflow (the
    payment, the invoice, the inventory adjustment, the bill) and inspect
    the activity log. The activity log will name the operator and the
    action that broke the link.
  </Step>

  <Step title="Post the corrective journal entry">
    Open `Accounting > Journal Entries > New`. Use a description like
    "Corrective JE to align AR subledger with GL control 1300 -- ref
    invoice INV-12345 voided 2026-05-01 without reversal". Both legs must
    cite the source record id and the root cause in plain English.

    Send for approval per your entity's `je_approval_threshold` policy.
    Re-run GL Reconciliation after the JE posts to verify the variance is
    back to zero.
  </Step>
</Steps>

## When To Get Help

<Warning>
  Do not post a corrective JE if any of the following are true. Escalate to
  the accounting lead or to Arcus support first.

  * The variance is greater than 10% of the control account balance.
  * The variance spans more than one closed accounting period.
  * The drift appeared without any operator change (no activity log entries
    in the variance window).
  * The same subledger has drifted more than once in the same fiscal year.
  * The control account is involved in an external audit, tax filing, or
    bank reconciliation that has already been signed off.
</Warning>

In any of these cases the corrective JE may need to be paired with a prior-
period restatement, a tax amendment, or a bank-reconciliation reopen. The
accounting lead owns the decision; the operator owns the documentation.

## Related Topics

* [GL Reconciliation and Integrity](/support/accounting/gl-reconciliation-integrity) -- the full reconciliation surface and how to read the variance cards.
* [Journal Entries](/support/accounting/journal-entries) -- how to post a corrective JE through the approval workflow.
* [Account Ledger](/support/accounting/account-ledger) -- how to inspect transaction history on one GL account.
* [Period Close](/support/accounting/period-close) -- how the pre-close checklist warns on outstanding subledger drift before period close.
