Threshold Tuning for Allocation Accuracy

A CAM reconciliation almost never fails because someone multiplied wrong. It fails because a tenant’s shares summed to $1,000,000.004, the engine rounded that to a pool that no longer ties out, and eleven months later a lease auditor found the four-tenth-of-a-cent drift multiplied across 480 line items into a number nobody can defend. Threshold tuning is the discipline of choosing — and version-controlling — the exact tolerance bands, rounding rules, cap-breach triggers, and data-completeness gates that decide when the engine finalizes a number and when it stops and asks. It is the calibration layer of the Expense Allocation Logic & Rule Engines pipeline: the same allocation math is either audit-ready or quietly wrong depending on how these thresholds are set. This page specifies the data contracts a threshold engine consumes, the deterministic tolerance formulas it applies, a typed and runnable implementation, the edge cases that separate a calibrated engine from a fragile one, and how tuned thresholds feed the reconciliation and audit layers downstream.

Threshold engine decision cascade with four verdicts Allocated shares and a pool total pass through three ordered gates. A completeness gate below its floor halts the run as INCOMPLETE_DATA. A deviation larger than the tolerance band is flagged OUT_OF_TOLERANCE to the review queue. A zero residual finalizes as RECONCILED; a non-zero residual inside the band is ROUNDING_ADJUSTED, routing the leftover penny to the largest tenant. Allocated shares + pool total Coverage ≥ floor? |Σaᵢ − P| ≤ band? residual = 0? INCOMPLETE_DATA OUT_OF_TOLERANCE RECONCILED ROUNDING_ADJUSTED halt · data-quality ticket → review queue ties out to the cent route penny → largest tenant no yes no yes yes no

Prerequisites & Data Contracts

Threshold tuning sits between the allocation math and the reconciliation ledger, so it can only be as trustworthy as the two contracts on either side of it. A tolerance band applied to a mislabeled pool does not protect accuracy — it certifies an error. Three inputs must be settled before a single threshold fires.

A reconciled recoverable pool. The engine tolerances a pool total, not a raw ledger. Each expense pool arrives already partitioned into recoverable and excluded amounts by exclusion mapping for tenant-specific CAM, each amount a Decimal, each carrying a pool_id and a property_id. If a capital charge leaked past exclusion, no tolerance band downstream can find it — the pool total will simply be wrong and every tenant share proportionally so. Records that failed schema validation for parsed expense data must never reach this stage; a null amount silently coerced to zero collapses the denominator and passes every tolerance check while under-billing the entire building.

Allocated tenant shares with their basis. The shares being checked come from implementing pro-rata allocation algorithms, and each share must arrive with the inputs that produced it — the tenant’s rentable square footage, the total denominator, and the raw unrounded factor — not just the final dollar figure. Threshold tuning needs the pre-rounding value to measure how much drift the rounding introduced. A share stripped of its basis is a number the engine can compare but cannot correct.

A versioned threshold configuration. Every tolerance band, cap trigger, and completeness gate is a configuration fact, not a constant buried in code. Thresholds are keyed by (property_id, fiscal_year) and carry a config_version, so a reconciliation can be replayed against the exact tolerances in force during the period under review. When an auditor asks why a $3.12 remainder was routed to the anchor tenant rather than flagged, the answer is a specific, dated configuration line — not “that is how the script ran that day.”

Rule Design: Tolerance Bands, Rounding, and Cap Triggers

Allocation accuracy has three distinct failure surfaces, and each needs its own kind of threshold. Conflating them — using one magic number for all — is the most common tuning mistake.

Conservation tolerance. After shares are allocated, their sum must reconcile to the pool. Because rounding to the cent is lossy, the sum will rarely equal the pool exactly, so the engine defines an acceptable band rather than demanding exact equality. Let the recoverable pool be PP and the allocated shares be a1,,ana_1, \dots, a_n. The engine reconciles the pool when the total deviation falls inside a combined absolute-and-relative band:

i=1naiPmax(τabs,  τrelP)\left| \sum_{i=1}^{n} a_i - P \right| \le \max\bigl(\tau_{\text{abs}},\; \tau_{\text{rel}} \cdot P\bigr)

The relative term τrelP\tau_{\text{rel}} \cdot P scales the tolerance with pool size — a $0.02 band is right for a $40,000 landscaping pool but absurd for a $4,000,000 operating pool — while the absolute floor τabs\tau_{\text{abs}} keeps a tiny pool from having a tolerance of essentially zero. A single fixed dollar band fails at both ends of the portfolio.

Rounding and remainder routing. The deviation that remains inside the band is not ignored — it is a real fraction of a cent that must land somewhere or the ledger will not balance. The engine allocates the residual deterministically. The pro-rata share itself is the familiar

ai=round ⁣(rsfijrsfjP,  2)a_i = \operatorname{round}\!\left( \frac{\text{rsf}_i}{\sum_j \text{rsf}_j} \cdot P,\; 2 \right)

and the leftover r=Piair = P - \sum_i a_i (typically a cent or two) is routed to a single, pre-declared recipient — conventionally the largest tenant, whose relative error from absorbing one cent is smallest. What matters is that the rule is fixed and recorded, so the same inputs always produce the same tenant’s share carrying the same penny. Randomly distributing remainders, or letting them fall to whichever tenant sorts first, is how two runs of the same reconciliation disagree.

Cap-breach and completeness triggers. Not every threshold is about pennies. When a controllable-expense pool crosses the ceiling set by managing expense caps and controllable limits, the engine must split the recoverable portion from the landlord-absorbed portion before it finalizes — a cap breach is a threshold event that changes the pool, not just a rounding nuance. Likewise, a data-completeness gate stops the run when occupancy or square-footage coverage falls below a floor (commonly 95%), because allocating a pool across a denominator you only partly trust produces confident, precise, wrong numbers.

The conservation tolerance band on a number line A number line centered on the pool total P. A symmetric shaded band of half-width max(tau_abs, tau_rel times P) is the finalize zone; deviations larger than the band on either side fall into flag-for-review zones. The sum of allocated shares lands just inside the band, and the leftover residual r = P minus the sum is routed whole to the largest tenant. P — pool total finalize |Σaᵢ − P| ≤ band flag for review residual > band flag for review residual > band Σaᵢ band = max(τ_abs, τ_rel·P) Inside the band, leftover r = P − Σaᵢ is routed whole to the largest tenant.

Python Implementation

The engine below is deterministic and typed, and every monetary value is a Decimal — binary float cannot represent most cent values exactly, and drift summed across hundreds of shares is precisely the error threshold tuning exists to prevent. Configuration and shares are pydantic models so a malformed threshold set is rejected at the boundary rather than deep inside the reconciliation. Quantization uses ROUND_HALF_UP from the standard library (docs.python.org/3/library/decimal.html).

from __future__ import annotations

from decimal import Decimal, ROUND_HALF_UP
from enum import Enum
from typing import Sequence

from pydantic import BaseModel, Field

CENT = Decimal("0.01")


class ReconStatus(str, Enum):
    """The engine's verdict for a tuned pool."""
    RECONCILED = "reconciled"
    ROUNDING_ADJUSTED = "rounding_adjusted"
    OUT_OF_TOLERANCE = "out_of_tolerance"
    INCOMPLETE_DATA = "incomplete_data"


class ThresholdConfig(BaseModel):
    """Versioned, per-property tolerance configuration."""
    property_id: str
    fiscal_year: int
    config_version: str
    abs_tolerance: Decimal = Decimal("0.05")      # absolute floor, dollars
    rel_tolerance: Decimal = Decimal("0.0000005")  # relative band, fraction of pool
    completeness_floor: Decimal = Decimal("0.95")  # min occupancy/RSF coverage


class TenantShare(BaseModel):
    """An allocated share carrying the basis that produced it."""
    tenant_id: str
    rentable_sf: Decimal
    allocated: Decimal


class ReconResult(BaseModel):
    """Outcome of tuning one pool, with an auditable adjustment record."""
    pool_id: str
    status: ReconStatus
    pool_total: Decimal
    allocated_sum: Decimal
    residual: Decimal
    adjusted_tenant_id: str | None
    config_version: str


def tolerance_band(pool_total: Decimal, cfg: ThresholdConfig) -> Decimal:
    """Combined absolute-and-relative band: floor for small pools, scale for large."""
    return max(cfg.abs_tolerance, (cfg.rel_tolerance * pool_total).quantize(CENT, ROUND_HALF_UP))


def tune_pool(
    pool_id: str,
    pool_total: Decimal,
    shares: Sequence[TenantShare],
    coverage: Decimal,
    cfg: ThresholdConfig,
) -> ReconResult:
    """Apply conservation tolerance and deterministic remainder routing to a pool.

    Coverage below the completeness floor halts finalization; a residual inside
    the band is routed to the largest tenant; a residual outside it is flagged.
    """
    if coverage < cfg.completeness_floor:
        return ReconResult(
            pool_id=pool_id, status=ReconStatus.INCOMPLETE_DATA,
            pool_total=pool_total, allocated_sum=Decimal("0.00"),
            residual=pool_total, adjusted_tenant_id=None,
            config_version=cfg.config_version,
        )

    allocated_sum = sum((s.allocated for s in shares), Decimal("0.00"))
    residual = (pool_total - allocated_sum).quantize(CENT, ROUND_HALF_UP)
    band = tolerance_band(pool_total, cfg)

    if abs(residual) > band:
        return ReconResult(
            pool_id=pool_id, status=ReconStatus.OUT_OF_TOLERANCE,
            pool_total=pool_total, allocated_sum=allocated_sum,
            residual=residual, adjusted_tenant_id=None,
            config_version=cfg.config_version,
        )

    if residual == Decimal("0.00"):
        return ReconResult(
            pool_id=pool_id, status=ReconStatus.RECONCILED,
            pool_total=pool_total, allocated_sum=allocated_sum,
            residual=residual, adjusted_tenant_id=None,
            config_version=cfg.config_version,
        )

    # Deterministic routing: largest RSF absorbs the residual (smallest relative error).
    # Tie-break on tenant_id so the choice is reproducible across runs.
    anchor = max(shares, key=lambda s: (s.rentable_sf, s.tenant_id))
    return ReconResult(
        pool_id=pool_id, status=ReconStatus.ROUNDING_ADJUSTED,
        pool_total=pool_total, allocated_sum=pool_total,
        residual=residual, adjusted_tenant_id=anchor.tenant_id,
        config_version=cfg.config_version,
    )

The two-line detail that makes the routing auditable is the tie-break: max on (rentable_sf, tenant_id) guarantees that two tenants of identical size never let a run flip the penny to a different statement. Every ReconResult also carries the config_version that governed it, so the adjustment is traceable to the exact tolerance line that authorized it.

Validation Rules & Edge Cases

Threshold bugs are invisible until an auditor or a tenant’s lease consultant finds them, so the engine is hardened against the cases that quietly defeat naive tolerance checks.

  • The tolerance that swallows a real error. A relative band set too loosely will absorb a genuine $40 misallocation as if it were rounding noise. Tune τrel\tau_{\text{rel}} against the smallest defensible per-tenant error, not the largest convenient one; a band should catch the mistakes you fear, not hide them.
  • Zero or negative pools. A credit-heavy pool (large vendor rebate) can net negative, and a pool of exactly zero makes the relative band collapse to the absolute floor. The engine must treat pool_total <= 0 as a review trigger, never divide by it, and never route a residual into a share that would flip its sign.
  • The empty or single-tenant pool. With no shares, there is no anchor to route a residual to; with one tenant, that tenant absorbs the entire pool and the tolerance check is trivially satisfied. Both are legitimate, but the routing step must guard against max() on an empty sequence rather than raising deep in the call stack.
  • Completeness gate versus mid-year turnover. Occupancy legitimately dips below the 95% floor during tenant turnover, so a hard halt on every dip generates false alarms. Distinguish a structural coverage gap (a wing with no RSF on file) from an expected vacancy, and let the gate consult the lease abstraction database for known vacant units before it stops the run.
  • Cap breach hiding inside tolerance. A controllable pool can sit one dollar over its ceiling — inside any sane rounding band but outside the lease’s recovery limit. Cap triggers are evaluated independently of the conservation tolerance, never folded into it, because they answer a different question: not “did the math balance?” but “is the landlord allowed to recover this much?”

Integration Points

Threshold tuning is a gate, not a terminus, and its output is consumed by three downstream systems that each depend on a different part of the ReconResult.

A RECONCILED or ROUNDING_ADJUSTED pool flows to the reconciliation ledger and tenant-statement generator, where the adjusted_tenant_id and residual become a line an auditor can read: this tenant’s share carries this penny under this configuration. An OUT_OF_TOLERANCE result routes to the same review queue that receives quarantined records from building a CAM data validation layer, so a human resolves the discrepancy before any statement is issued rather than after. An INCOMPLETE_DATA result blocks finalization entirely and raises a data-quality ticket against ingestion, because the fix belongs upstream at the source, not in a wider tolerance band.

Every result — including the successful ones — is written to the immutable audit log with its config_version, so a reconciliation can be reproduced bit-for-bit against the thresholds in force. That reproducibility is what lets a portfolio defend an adjustment years later: the number was not chosen by a person under audit pressure, it was produced by a dated, version-controlled rule.

Testing & Verification

Because tolerance bugs cost money only when discovered late, the engine is tested against small, hand-computed fixtures where the correct verdict is known in advance.

from decimal import Decimal


def test_rounding_residual_routes_to_largest_tenant() -> None:
    cfg = ThresholdConfig(
        property_id="P1", fiscal_year=2026, config_version="2026.1",
    )
    # Three shares summing to 999,999.99 against a 1,000,000.00 pool: 1c residual.
    shares = [
        TenantShare(tenant_id="anchor", rentable_sf=Decimal("60000"),
                    allocated=Decimal("600000.00")),
        TenantShare(tenant_id="mid", rentable_sf=Decimal("25000"),
                    allocated=Decimal("249999.99")),
        TenantShare(tenant_id="small", rentable_sf=Decimal("15000"),
                    allocated=Decimal("150000.00")),
    ]
    res = tune_pool("POOL-OPEX", Decimal("1000000.00"), shares,
                    coverage=Decimal("1.0"), cfg=cfg)

    assert res.status is ReconStatus.ROUNDING_ADJUSTED
    assert res.residual == Decimal("0.01")
    assert res.adjusted_tenant_id == "anchor"     # largest RSF absorbs the penny
    assert res.allocated_sum == res.pool_total     # ledger ties out exactly


def test_real_error_exceeds_band_and_is_flagged() -> None:
    cfg = ThresholdConfig(property_id="P1", fiscal_year=2026, config_version="2026.1")
    shares = [TenantShare(tenant_id="t", rentable_sf=Decimal("50000"),
                          allocated=Decimal("39960.00"))]
    res = tune_pool("POOL-LAND", Decimal("40000.00"), shares,
                    coverage=Decimal("1.0"), cfg=cfg)

    assert res.status is ReconStatus.OUT_OF_TOLERANCE   # $40 gap, not rounding
    assert res.adjusted_tenant_id is None


def test_low_coverage_halts_before_any_routing() -> None:
    cfg = ThresholdConfig(property_id="P1", fiscal_year=2026, config_version="2026.1")
    shares = [TenantShare(tenant_id="t", rentable_sf=Decimal("50000"),
                          allocated=Decimal("38000.00"))]
    res = tune_pool("POOL-OPEX", Decimal("40000.00"), shares,
                    coverage=Decimal("0.80"), cfg=cfg)

    assert res.status is ReconStatus.INCOMPLETE_DATA

The three assertions cover the properties that matter: a genuine rounding residual is absorbed by the correct, deterministic tenant and the ledger ties out to the cent; a real misallocation exceeds the band and is flagged rather than hidden; and insufficient coverage halts the run before a single penny is routed. Because every amount is Decimal, the conservation assertions use exact equality — a one-cent leak fails the test instead of slipping under a floating-point isclose.

Frequently Asked Questions

Why route the leftover cent to the largest tenant instead of splitting it? A residual of one or two cents cannot be split across tenants without creating fractional cents the ledger cannot represent, so it must land whole on one statement. The largest tenant is chosen because absorbing a fixed penny is the smallest error relative to their share, and the choice is tie-broken on tenant id so the same inputs always adjust the same statement. Splitting or randomizing the remainder is exactly how two runs of one reconciliation come to disagree.

Should I use a single tolerance number for the whole portfolio? No. A fixed dollar band that is reasonable for a $40,000 pool is far too loose for a $4,000,000 one and too tight for a $5,000 one. Combine an absolute floor with a relative term that scales to pool size, so the band catches proportionally small errors on large pools without raising false alarms on tiny ones.

Is a tolerance breach the same as a cap breach? No, and folding them together is a common error. A conservation tolerance answers whether the allocation math balanced; a cap trigger answers whether the landlord is contractually allowed to recover that amount. A controllable pool can be one dollar over its lease ceiling while still well inside any rounding band, so caps are evaluated on their own path, before finalization.

Why version the threshold configuration instead of hard-coding the numbers? Because reconciliations are audited years after they run, and the only defensible answer to “why was this penny routed here?” is a dated, version-controlled configuration line. Hard-coded constants make an adjustment impossible to reproduce once the script has changed, which is precisely the situation an auditor treats as a red flag.

Why Decimal instead of float for pool totals and residuals? Binary floating point cannot represent most cent values exactly, so summing hundreds of float shares drifts by fractions of a cent — the very error threshold tuning exists to catch. Decimal, quantized to two places, keeps the residual penny-exact and lets the conservation check use exact equality instead of a tolerance that could mask a real discrepancy.

Where This Fits

Threshold tuning is the point where allocation stops being arithmetic and becomes an auditable decision: this pool ties out within this dated band, this penny lands on this tenant, this run halts because coverage fell short. By scaling the conservation band to pool size, routing every residual deterministically, keeping cap triggers on their own path, and versioning the whole configuration, the engine turns a floating-point liability into a reproducible control. It reads the pool that exclusion mapping for tenant-specific CAM produced and the shares that implementing pro-rata allocation algorithms computed, and it hands a defensible, tied-out result to the reconciliation ledger — with the correctness of every tenant statement resting on whether these thresholds were tuned or merely guessed.