Skip to main content

Reconciliation engine

A separate, advisory-locked scheduler that runs categorized integrity checks continuously.

Categories

CatMeaningCadence
AInternal integrityEvery cycle (default 3600s)
BDerivationEvery cycle
CExternal (broker)Longer cadence (default 86400s)
DLifecycle (aging)Every cycle

A + B are cheap (SQL-only). C hits live brokers, throttled to daily. D is cheap.

The check list

CheckCategoryWhereBoth books?
trial_balance_zeroAchecks/trial_balance.py
journal_line_completenessAchecks/journal_lines.py
source_txn_uniquenessAchecks/uniqueness.py
dr_cr_sign_conventionAchecks/sign.py
wallet_derivationBchecks/wallet.py
account_totalsBchecks/accounts.py
snapshot_reconcileBchecks/snapshot.py
gtn_ledger_reconCUAE onlyUAE
zag_holdings_reconCUAE onlyUAE
viewtrade_ledger_reconCIndia onlyIndia
viewtrade_holdings_reconCIndia onlyIndia
lrs_viewtrade_tie_outCIndia (degrades OK on UAE)✓ (safe)
pending_flow_ageDBoth

Every India-only check is registered on both books. When it runs on UAE the query against India-only tables comes back empty and the check returns ok.

Each check returns

ReconCheckResult(
check_name="lrs_viewtrade_tie_out",
category="C",
status="ok" | "warn" | "fail",
metrics={...},
ran_at=datetime,
)

A warn or fail also gets:

  • Variances — a list of specific rows that broke it.
  • Alert callback — if ALERT_WEBHOOK_URL is set, a POST fires (fire-and-forget).
  • Optional persistence — if alert_persist_enabled=True, a row lands in reconciliation_variances for history.

Running a check

Config:

SettingDefaultEffect
RECON_SCHEDULE_ENABLEDtrue (UAE)master switch
RECON_INTERVAL_SECONDS3600A/B/D cadence
RECON_EXTERNAL_INTERVAL_SECONDS86400C cadence
RECON_SCHEDULE_INITIAL_DELAY_SECONDS60boot delay
INDIA_RECON_ENABLEDfalseIndia scheduler master switch
INDIA_RECON_INTERVAL_SECONDS3600India cadence
ALERT_WEBHOOK_URLunsetdrift-alert POST target

Manually — POST /v1/reconciliation/run (optional category filter):

curl -X POST -H "X-Ledger-Admin-Token: localdev" \
-H "Content-Type: application/json" \
http://localhost:8078/v1/reconciliation/run \
-d '{"category":"C"}'

Reading — GET /v1/reconciliation/runs + GET /v1/reconciliation/runs/{id}.

The three India firm-recon endpoints

Complement the scheduled Category-C checks with on-demand fetches:

EndpointWhat
GET /v1/india/ledger-reconPer-customer ledger cash+securities vs live VT balance
GET /v1/india/holdings-reconPer (customer, instrument) share-count tie-out
GET /v1/india/reconciliationLRS↔ViewTrade per-customer tie-out

All three fetch live broker data (bounded concurrency, per-customer failure isolation) and are read-only.

When a check fails

  1. Look at the variances — the detail is in metadata.variances on the run row.
  2. Trace to a transaction — variances almost always name a txn_id or a source_txn_id.
  3. Decide the class:
    • Data issue — reverse the offending transaction, fix ingest, re-sync.
    • Code issue — fix the rule, migrate the data if needed, add a test.
    • Timing — often self-heals on the next cycle.
  4. Confirm — re-run the check manually.