# How must an instance bound rounding residual so party shares sum to the total? **Date of Record:** 2026 November 2 **Scope:** Applies to allocations of a total across multiple parties (fees, distributions, cost shares, royalties) where each party's share is computed and rounded, and the sum of rounded shares may differ from the rounded total. Does not apply to allocations where the total is derived from the shares (the sum is the total by construction). ## Core Distinction Rounding is idempotent for a single value but not distributive over a sum. `sum(round(x_i))` is generally not equal to `round(sum(x_i))`. If each party's share is rounded independently and the total is a separate figure, the shares will not sum to the total, and the discrepancy is not a computation error — it is the rounding operator failing to preserve the total. **Invariant.** Shares sum to the total if and only if `sum(round(x_i)) == round(sum(x_i))`, which requires (a) rounding the total first and allocating the residual to a designated party, or (b) using a largest-remainder allocation, or (c) carrying the residual as an explicit account. **Violation.** The **Rounding Residual**. Three parties sharing $10.00 equally, each 33.33%. Each share rounds to $3.33; total is $9.99. The missing cent is not an error in any share — it is the rounding operator's failure to be distributive. Without a residual allocation rule, the missing cent is unaccounted for, and every period adds another cent to the discrepancy. **Asymmetry.** Each party's share is correct within rounding. The total is correct. The sum of shares is not. No single computation is wrong, but the aggregate fails to account for all of the total. **Recorded elements.** The `total-receipt` (the total, rounded), the `share-receipts` (each share, rounded), and the `residual-allocation-signature` (which party receives the residual, or which residual account holds it) together make the sum-vs-total checkable. ## What Was Observed **Signature.** Sum of party shares differing from total by a small amount, stable in direction (always short, never over, if rounds toward zero) and accumulating across periods. Reconciliation that compares total-only misses the divergence; reconciliation that compares sum-of-shares to total catches it. **Trace.** Distribution of $10.00 to 3 parties equally. Each share: 3.333..., rounds to $3.33. Sum = $9.99. Total = $10.00. $0.01 residual. Over 12 periods, $0.12 accumulates and appears as an unexplained reconciliation break. If rounds toward nearest, the direction of the residual depends on the numbers and can flip between periods, masking accumulation. **Why monitoring stays green.** Each party's share is a valid number. The total is a valid number. Reconciliation comparing total to source system matches. Only sum-of-shares vs total reveals the residual. ## Condition of Validity The instance must ensure at least one holds before it treats shares as summing to the total: 1. **Must round the total first, then allocate residual.** The total is rounded first; shares are computed against the rounded total; the residual (if any) is assigned to a designated party by an explicit rule. 2. **Must use largest-remainder allocation.** Shares are computed to full precision; the rounded shares are adjusted by largest remainder until they sum to the total. 3. **Must hold residual in an explicit account.** The residual is carried in a designated account (rounding account, unallocated reserve), so the sum of shares + residual = total by construction. Condition 1 is simplest for a fixed party; condition 2 is fairest across parties; condition 3 is required when the party count varies. ## Decision Boundary - Total rounded first, residual allocated to designated party: shares sum to total. - Largest-remainder allocation: shares sum to total; each party's share is within 1 unit of exact. - Residual in explicit account: shares sum to total minus residual, with residual visible. - Independent rounding without residual handling: shares do not sum to total; treat as defect. ## Operational Effect The invariant couples a distributive operator (shares) to a rounding operator that does not preserve the total. The instance's correct posture is to round the total first, allocate the residual explicitly, and reconcile sum-of-shares against the total at every distribution. **Trap.** Round shares to more decimal places. More precision postpones the residual but does not eliminate it — at any finite precision the residual is non-zero, and at a future period it appears. The fix is structural (residual handling), not precision-related. ```python from dataclasses import dataclass class RoundingResidualError(RuntimeError): """Raised when the sum of rounded party shares does not equal the rounded total.""" @dataclass(frozen=True) class RoundingGate: rounded_total: float rounded_shares: tuple residual_handled: bool # either allocated to a party or held in explicit account def verify(self, epsilon: float = 1e-9) -> bool: if not self.rounded_shares: raise RoundingResidualError("no shares to allocate") share_sum = sum(self.rounded_shares) residual = round(self.rounded_total - share_sum, 10) if abs(residual) <= epsilon: return True if self.residual_handled: return True raise RoundingResidualError( f"shares sum to {share_sum} but total is {self.rounded_total}: " f"residual {residual} unallocated" ) def dispatch_allocation_mode(gate: RoundingGate) -> str: try: gate.verify() except RoundingResidualError: return "largest-remainder-or-residual-account" return "allocate-shares" ```