Skip to content

Sasquatch National Bank — Chains

A chain row declares "when {{ parent }} fires, one of these {{ children }} SHOULD fire too". A row with one child encodes "required" (every parent firing must invoke that child); a row with two or more children encodes "XOR" alternation (exactly one of the listed children MUST fire per parent invocation). The L2 Flow Tracing app's Chain Orphans check fails when the expected child firing is missing.

Total: 5 chain rows declared on l2.yaml. The chains diagram on the overview shows the edges visually.

Parent Children Cardinality Description
ACHOriginationDailySweep ChainChildSpec(name='ConcentrationToFRBSweep', fan_in=False, expected_parent_count=None) required Required: every daily ACH origination sweep should be followed by a Concentration→FRB sweep that rolls the consolidated balance out to the Fed. A missing child means SNB swept ACH activity internally but never settled it externally — surfaces as an orphan exception.
CustomerInboundACH ChainChildSpec(name='CustomerInboundACHReturnNSF', fan_in=False, expected_parent_count=None), ChainChildSpec(name='CustomerInboundACHReturnStopPay', fan_in=False, expected_parent_count=None) xor Return-reason XOR group on inbound ACH (NACHA codes). At most one of these returns fires per inbound original — most inbound ACHs aren't returned at all. NSF (R01) covers insufficient funds; StopPay (R08) covers the customer's stop-payment instruction. If both fire on the same original that's a runtime anomaly (post-time check, not catchable at validation).
MerchantSettlementCycle ChainChildSpec(name='MerchantPayoutACH', fan_in=False, expected_parent_count=None), ChainChildSpec(name='MerchantPayoutWire', fan_in=False, expected_parent_count=None), ChainChildSpec(name='MerchantPayoutCheck', fan_in=False, expected_parent_count=None), ChainChildSpec(name='MerchantWeeklyPayoutBatch', fan_in=True, expected_parent_count=5) xor AB.6.6.sasq (2026-05-19) — mixed-cardinality demonstration. Each settled MerchantSettlementCycle fires both: - exactly ONE of three 1:1 payout vehicles (ACH preferred default, Wire for merchants banking elsewhere, Check for legacy paper); AND - contributes to the week's MerchantWeeklyPayoutBatch (5 daily settlements share one weekly batch Transfer — AB.6 per-child fan_in shape). The L1 invariants split the work: multi_xor_violation enforces the XOR alternation on [ACH, Wire, Check]; fan_in_disagreement enforces parent_count=5 on the batch.
CustomerFeeAccrual ChainChildSpec(name='InternalTransferCycle', fan_in=False, expected_parent_count=None) required Template-as-chain-child shape (AB.2, gap doc §3). Every customer fee accrual SHOULD trigger an InternalTransferCycle to move the accrued amount from the customer's DDA to the fee revenue GL. All three leg_rails of the child template (InternalTransferDebit, InternalTransferCredit, InternalTransferSuspenseClose) share one child Transfer and one parent_transfer_id (first-firing-wins per gap doc §3). The L1 chain_parent_disagreement matview catches any leg that claims a different parent — surfaces as an ETL bug on Today's Exceptions.
MerchantDailySettleAggregator ChainChildSpec(name='MerchantWeeklyPayoutBatch', fan_in=True, expected_parent_count=5) required AB.4 fan-in chain (gap doc §2 MerchantPayoutBatch; AB.6 per-child shape). 5 daily MerchantDailySettleAggregator firings (one per business day of the week) share ONE MerchantWeeklyPayoutBatch Transfer. The AB.4.3 _transfer_parents matview derives the multi-parent set per child; AB.4.7's _fan_in_disagreement matview reads parent_count vs expected_parent_count=5 to flag batches missing a daily contribution (parent_count<5) or carrying an extra one (parent_count>5).