L1 Exceptions

What this sheet teaches. The unified snapshot of every L1 (account-integrity) SHOULD-constraint violation across all twelve invariant checks, scoped to the date window you're examining. This is your morning scan: one sheet that answers "what's broken across balance, chain flow and aging" without hopping between five separate invariant sheets.

What you're looking at

The sheet opens with a single KPI: Open Exceptions — the total count of violations in the selected date window. Below sits Exceptions by Check Type (a horizontal bar chart with log-scale Y axis) that groups the violations into twelve categories so you can see which invariant is dominating. The detail table Exception Detail lists every violation, sorted by dollar magnitude (largest first), so the highest-impact items surface at the top.

At the bottom is an Institution Context text box carrying your L2 instance's description — the unified-view landing page's anchor for "what this institution reconciles."

How to read the numbers

The detail table draws from a live UNION ALL across twelve L1 invariant matview branches, each contributing its own check_type discriminator column. The union branches across three categories:

Balance / numeric checks (5 types; each row is one account-day violation): - drift — leaf account's stored balance disagrees with cumulative net of postings; drawn from <prefix>_drift (see Drift) - ledger_drift — parent account's stored balance does not equal the sum of its children's stored balances; from <prefix>_ledger_drift - overdraft — stored balance is negative (< 0); from <prefix>_overdraft - limit_breach — the net outbound or inbound flow on a rail exceeded the per-account cap for that direction; from <prefix>_limit_breach (see Limit Breach) - expected_eod_balance_breach — the stored balance disagrees with a declared expected EOD target

Time-based aging checks (3 types; each row is one leg or account-day, keyed by posting / balance timestamp): - stuck_pending — a Pending leg has exceeded its rail's max_pending_age cap - stuck_unbundled — a Posted leg has exceeded its rail's max_unbundled_age cap and is not yet bundled - balance_cadence_gap — an account declared balance_cadence='explicit_daily' is missing a daily balance row (see Daily Statement)

Transfer-keyed chain / cardinality checks (4 types; each row is one transfer's violation, not an account-day): - chain_parent_disagreement — a child Transfer claims multiple parent Transfer IDs; the chain's parent linkage is ambiguous - xor_group_violation — an XOR group's firing count is not exactly one (0 = missed, ≥2 = overlap) - fan_in_disagreement — a fan-in child Transfer's parent count disagrees with the expected count - multi_xor_violation — multiple XOR groups on the same chain misfire together (a higher-order overlap)

Every row carries account_id, account_name, account_role and business_day. For money-based checks (balance and aging branches), magnitude_amount holds the dollar variance; for transfer-keyed checks, magnitude_count holds the cardinality disagreement (the count of unexpected parents, or firing/child count mismatch). Exactly one magnitude column is populated per row.

The Open Exceptions KPI counts all rows in the dataset within the selected date window and filter settings. The Exceptions by Check Type bar chart groups by check_type to show you the volume mix across the twelve branches — useful for spotting which invariant is the current bottleneck.

Common patterns

Single check type dominating

The bar chart shows one or two check types (e.g., stuck_unbundled) as massive bars while the others barely register. This is the steady-state shape — one aging rail is perpetually slow on bundling, or one specific invariant has a known endemic issue. Filter the detail table by that check_type using the filter controls, then sort by magnitude_amount desc to find the worst offenders. Cross to the invariant's dedicated sheet (e.g., Unbundled Aging for stuck_unbundled) to drill into which rails / accounts are the hotbed.

Transfer-keyed rows alongside account-day rows

The detail table mixes money rows (with magnitude_amount ≥ $0.01) and cardinality rows (with magnitude_count ≥ 1). The transfer-keyed checks (chain_parent_disagreement, xor_group_violation, fan_in_disagreement) have NULL on account_id and a count in magnitude_count. Account-day checks always have account_id and a dollar amount. This is expected — the sheet's design surfaces all twelve invariants on one canvas, which means two different key-shapes. When triaging, focus on money checks first (they map to accounts / roles you know), then loop in the chain-analysis team for the transfer-keyed exceptions.

Balance spike after a known outage

The bar chart shows a sudden wave in drift or ledger_drift, all on the same business_day, across many accounts of one account_role. This is a batch feed failure — a nightly balance load either re-ran with stale input or was skipped entirely. Drill into Drift sheet with the same account role filter to see which child accounts are involved; cross to Daily Statement for one account to confirm the posting timeline. If the postings landed but the balance never updated, escalate to the balance-emission team.

Cardinality checks pointing at a single parent or template

Several rows with check_type in ('chain_parent_disagreement', 'xor_group_violation', 'fan_in_disagreement') all show the same rail_name (or template name). This is a transfer-chain template issue — the L2 declaration for that template's leg sequence or parent linkage doesn't match what's actually posting. Right-click a row → View Daily Statement for this account-day (for account-day rows) or drill directly to Transactions to see the competing parent claims or fired rail set. Loop in the L2 chain-definition maintainer with the template name and a sample transfer ID.

What "no rows" means

A clean L1 Exceptions sheet means all twelve SHOULD-constraints held true on every account and every transfer within your date window. This is the steady-state target, not an edge case — exceptions exist to catch violations, not to trend metrics. If you see zero rows:

A NULL latest_date is NOT a staleness signal — it just means that matview carries no natural date dimension (or, on App Info, a custom matview was added without a date column). But if the l1_exceptions row count reads zero while the base tables' latest_date moved forward on data you posted recently, the ETL pipeline encountered an error. That's an ops alert, not a "system is clean" signal.

Cross-sheet drills


First time here? See the Vocabulary for L1, matview, account_role, rail, chain, template and the other project-specific terms.