Handling Gross-Up Caps and Occupancy Floors
A gross-up factor left unbounded will multiply a tenant’s variable CAM share several times over when a building sits nearly empty, so this page builds the guardrails — an occupancy floor and an optional gross-up ceiling — that hold that factor inside contractually defensible limits. It is the bounding half of gross-up normalization logic: the parent stage computes how far a variable pool should be scaled toward a target occupancy, and everything here is about refusing to scale it too far. The distinction matters because the raw normalization arithmetic has no upper limit built in. A pool at 34% actual occupancy against a 95% target produces a factor near 2.8 on its own, and nothing in the division stops it — the floor and the ceiling are the only reasons a thinly let property does not detonate a tenant’s statement. Where the companion recipe on calculating gross-up adjustments for variable occupancy derives the factor across a range of time-weighted occupancies, this one is concerned only with the two clamps that keep that factor lawful.
Context & When to Use This Approach
The clamping stage earns its place the moment a lease pairs a gross-up clause with any language limiting how aggressively the landlord may normalize. In an institutional office lease that is nearly always present, because a tenant negotiating a gross-up provision almost always negotiates its bounds in the same breath. The plain factor computation is sufficient only when occupancy stays comfortably between the floor and the target for every period; the guards here matter precisely when it does not. The concrete triggers are recognizable across a portfolio:
- A severe vacancy year. A property loses an anchor tenant and drops to 30-something percent occupancy. The raw factor would nearly triple the sitting tenants’ variable share, and the lease’s occupancy floor is the only thing between them and a statement they will refuse to pay.
- A “not to exceed” gross-up multiple. The clause reads that occupancy costs may be grossed up “to 95% occupancy, provided the gross-up shall not exceed 1.75 times actual expenses.” That explicit ceiling is a second, tighter clamp that the floor alone does not enforce.
- A newly delivered building in lease-up. A property still filling its first tenants runs at low occupancy by design, and the floor keeps the early tenants from absorbing the full cost of an empty shell they did not cause.
- A disputed reconciliation. A tenant’s consultant recomputes the factor and argues it breached the contractual maximum. The clamp — and its audit record showing which bound was active — is what settles the argument with a number rather than a negotiation.
The floor and the target are lease facts, sourced from the same abstract that supplies the gross-up normalization logic stage its target occupancy, and they must be read per pool rather than hard-coded to a house default. A gross-up ceiling is a different instrument from the fiscal-year recovery limits governed by managing expense caps and controllable limits: the ceiling here bounds an occupancy-driven multiplier at the normalization stage, while a controllable cap bounds a tenant’s cumulative recovery after allocation. Conflating the two double-limits a charge and is one of the most common errors in a maturing reconciliation engine.
Step-by-Step Implementation
The pipeline below takes a variable pool, its measured occupancy, and the lease bounds, and returns a grossed variable amount together with an audit record naming which clamp — if any — was active. Every monetary and ratio value is carried as decimal.Decimal; a gross-up factor computed in binary floating point drifts in the fourth decimal place, and that drift, multiplied across a six-figure pool, produces a recoverable amount a tenant’s spreadsheet will not reproduce.
Step 1 — Define the occupancy floor and gross-up ceiling. Model the bounds as a typed record alongside the pool’s variable component, actual occupancy, and target. The floor is a lower bound on the occupancy used in the denominator; the optional factor_ceiling is an explicit upper bound on the multiplier itself. Both are read from the lease abstract, and both are Decimal.
from __future__ import annotations
from decimal import Decimal, ROUND_HALF_UP
from pydantic import BaseModel, Field
CENTS = Decimal("0.01")
FACTOR_DP = Decimal("0.0001") # gross-up factor carried to four places
class GrossUpBounds(BaseModel):
"""A variable pool plus the lease-sourced bounds on its normalization.
occupancy_floor bounds the denominator from below; factor_ceiling, when
present, bounds the gross-up multiplier directly ("gross-up not to exceed
N times actual expenses"). Both come from the lease abstract per pool.
"""
pool_id: str
variable_component: Decimal = Field(..., ge=0) # occupancy-elastic spend
actual_occupancy: Decimal = Field(..., gt=0, le=1) # time-weighted fraction
gross_up_target: Decimal = Field(..., gt=0, le=1) # e.g. Decimal("0.95")
occupancy_floor: Decimal = Field(..., ge=0, le=1) # e.g. Decimal("0.50")
factor_ceiling: Decimal | None = None # optional multiplier cap
Step 2 — Clamp effective occupancy to the floor. Before any division, replace the raw occupancy with the greater of actual occupancy and the floor. This single max is the floor’s entire mechanism: by refusing to let the denominator fall below the floor, it implicitly ceilings the factor at the target divided by the floor, without the lease having to state a maximum multiplier at all.
def effective_occupancy(bounds: GrossUpBounds) -> Decimal:
"""Occupancy used in the denominator, never below the contractual floor."""
# A building at 34% with a 50% floor divides by 0.50, not 0.34, so the
# factor cannot exceed target / floor no matter how empty the property is.
return max(bounds.actual_occupancy, bounds.occupancy_floor)
The relationship the clamp enforces is a bounded division. Let actual occupancy be the time-weighted fraction the building achieved, the floor its contractual lower bound, and the target the occupancy the lease normalizes to. The effective occupancy is:
and the bounded factor is the target over that effective occupancy, itself capped by any explicit ceiling:
Because , the first term can never exceed — that quotient is the ceiling the floor imposes for free. An explicit factor_ceiling only matters when it is tighter than that implied bound.
Step 3 — Cap the gross-up factor at its ceiling. Compute the raw factor from the floored denominator, hold it at exactly one when the building already meets or exceeds the target (gross-up normalizes upward only and never grosses a full building down), and then apply the explicit ceiling if the lease supplies one.
def bounded_factor(bounds: GrossUpBounds) -> Decimal:
"""The gross-up multiplier after both the floor and the ceiling apply."""
denominator = effective_occupancy(bounds)
# At or above target there is nothing to normalize; pass the pool through.
if denominator >= bounds.gross_up_target:
return Decimal("1")
factor = bounds.gross_up_target / denominator
# An explicit "not to exceed" multiple clamps the factor below the value
# the floor alone would permit. It is a lease term, not a house default.
if bounds.factor_ceiling is not None and factor > bounds.factor_ceiling:
factor = bounds.factor_ceiling
return factor.quantize(FACTOR_DP, ROUND_HALF_UP)
Step 4 — Apply the bounded factor to the variable component. Multiply only the occupancy-elastic spend by the clamped factor and quantize to cents once, at the point the figure becomes a recoverable amount. The fixed portion of the pool never reaches this function; it passed through untouched at the parent stage.
Step 5 — Audit the clamp. Record which bound was active and fingerprint the decision so a reopened reconciliation can prove the factor honored the lease. A statement that shows a grossed figure without saying whether the floor or the ceiling shaped it is undefensible; the audit record is what turns the clamp from a silent adjustment into a reviewable one.
import hashlib
import json
class ClampedResult(BaseModel):
"""A grossed variable amount with a record of which clamp was active."""
pool_id: str
variable_grossed: Decimal
factor: Decimal
floor_active: bool # actual occupancy fell below the floor
ceiling_active: bool # explicit factor ceiling bound the multiplier
fingerprint: str
def apply_clamped_gross_up(bounds: GrossUpBounds) -> ClampedResult:
"""Gross the variable component with the floor and ceiling applied, audited."""
factor = bounded_factor(bounds)
denominator = effective_occupancy(bounds)
floor_active = bounds.actual_occupancy < bounds.occupancy_floor
if denominator >= bounds.gross_up_target:
raw = Decimal("1")
else:
raw = bounds.gross_up_target / denominator
ceiling_active = bounds.factor_ceiling is not None and raw > bounds.factor_ceiling
variable_grossed = (bounds.variable_component * factor).quantize(
CENTS, ROUND_HALF_UP
)
# Fingerprint the inputs and the clamp decision so the number is replayable.
payload = json.dumps(
{
"pool_id": bounds.pool_id,
"actual": str(bounds.actual_occupancy),
"floor": str(bounds.occupancy_floor),
"target": str(bounds.gross_up_target),
"factor": str(factor),
"floor_active": floor_active,
"ceiling_active": ceiling_active,
},
sort_keys=True,
)
fingerprint = hashlib.sha256(payload.encode("utf-8")).hexdigest()
return ClampedResult(
pool_id=bounds.pool_id,
variable_grossed=variable_grossed,
factor=factor,
floor_active=floor_active,
ceiling_active=ceiling_active,
fingerprint=fingerprint,
)
A worked example makes the two clamps concrete. Kestrel Tower, a downtown office building, lost its anchor mid-year and averaged 34% time-weighted occupancy against a 95% gross-up target, with a 50% occupancy floor in the lease. Its occupancy-elastic pool — janitorial and common-area utilities combined — recorded $210,000.00 of variable spend. Without the floor, the factor would be 0.95 divided by 0.34, about 2.7941, grossing the pool to $586,764.71. The floor holds the denominator at 50%, so the factor is 0.95 divided by 0.50, exactly 1.9, and the grossed figure is $399,000.00 — the floor alone spared the sitting tenants roughly $187,764.71 of over-normalization. If the same lease also carries a “not to exceed 1.75 times” ceiling, the factor is clamped again from 1.9 down to 1.75, and the grossed figure lands at $367,500.00, with both floor_active and ceiling_active recorded true on the audit record.
Gotchas & Known Limitations
The clamp is two comparisons and a division; the ways a real lease defeats a naive implementation are subtler. Treat each of the following as a case the code must handle by rule.
- A floor above the target grosses down. If a data-entry slip sets the floor higher than the target, the floored denominator exceeds the target and the factor drops below one, quietly reducing recovery below actual spend. Validate that
occupancy_floor <= gross_up_targetbefore any pool is grossed, and reject the configuration rather than emit a sub-one factor. - The floor and the ceiling are two different clamps. The floor bounds the denominator; the explicit ceiling bounds the multiplier. A lease can carry one, both, or neither, and treating the floor as if it were a factor cap — or vice versa — produces the wrong number whenever they disagree. Model them separately and record which one bound.
- A ceiling below one is never a gross-up. An explicit
factor_ceilingunder 1.0 would force the pool below actual spend. That is a clawback, not a gross-up, and almost certainly a mis-keyed value; guard against it. - The occupancy-driven ceiling is not a recovery cap. The gross-up ceiling limits normalization at the pool level, before allocation. The annual and cumulative limits in managing expense caps and controllable limits limit a tenant’s recovery after allocation. Applying one where the other belongs either under-recovers a landlord’s genuine cost or over-limits a tenant’s charge.
- The floor is time-weighted, not a spot reading. A building that was empty for a quarter and full for the rest has an average occupancy the floor compares against, not its worst month. Feed the clamp the same time-weighted fraction the parent stage uses, or the two stages will disagree about how full the building was.
- Quantize the factor before multiplying. A factor carried at full division precision and a factor quantized to four places produce cents that differ by a penny on a large pool. Fix the factor’s precision once, before it touches the variable component, so the grossed figure is reproducible against a tenant’s own recomputation.
Verification
The clamp is defensible only if a fixture proves each boundary behaves as the lease says, using exact Decimal equality rather than a floating-point tolerance. Four assertions carry the weight: the floor clamps a runaway factor, an explicit ceiling tightens it further, an occupancy inside the band passes through untouched, and a full building grosses to one.
from decimal import Decimal
def test_floor_clamps_runaway_factor() -> None:
"""At 34% occupancy the 50% floor holds the factor to 0.95 / 0.50."""
bounds = GrossUpBounds(
pool_id="kestrel-tower-utilities-2025",
variable_component=Decimal("210000.00"),
actual_occupancy=Decimal("0.34"),
gross_up_target=Decimal("0.95"),
occupancy_floor=Decimal("0.50"),
)
result = apply_clamped_gross_up(bounds)
assert result.factor == Decimal("1.9")
assert result.variable_grossed == Decimal("399000.00")
assert result.floor_active is True
assert result.ceiling_active is False
def test_explicit_ceiling_tightens_below_floor_bound() -> None:
"""A 'not to exceed 1.75x' clause clamps the factor below 1.9."""
bounds = GrossUpBounds(
pool_id="kestrel-tower-utilities-2025",
variable_component=Decimal("210000.00"),
actual_occupancy=Decimal("0.34"),
gross_up_target=Decimal("0.95"),
occupancy_floor=Decimal("0.50"),
factor_ceiling=Decimal("1.75"),
)
result = apply_clamped_gross_up(bounds)
assert result.factor == Decimal("1.75")
assert result.variable_grossed == Decimal("367500.00")
assert result.ceiling_active is True
def test_occupancy_within_band_uses_actual() -> None:
"""At 78% the floor and ceiling are inert; the factor is 0.95 / 0.78."""
bounds = GrossUpBounds(
pool_id="kestrel-tower-janitorial-2025",
variable_component=Decimal("100000.00"),
actual_occupancy=Decimal("0.78"),
gross_up_target=Decimal("0.95"),
occupancy_floor=Decimal("0.50"),
)
result = apply_clamped_gross_up(bounds)
assert result.factor == Decimal("1.2179")
assert result.variable_grossed == Decimal("121790.00")
assert result.floor_active is False
def test_full_building_grosses_to_one() -> None:
"""A building at 98% is above target, so the variable spend passes through."""
bounds = GrossUpBounds(
pool_id="kestrel-tower-janitorial-2025",
variable_component=Decimal("100000.00"),
actual_occupancy=Decimal("0.98"),
gross_up_target=Decimal("0.95"),
occupancy_floor=Decimal("0.50"),
)
result = apply_clamped_gross_up(bounds)
assert result.factor == Decimal("1")
assert result.variable_grossed == Decimal("100000.00")
Because every value is a Decimal, each assertion is exact equality, so a factor that drifts a ten-thousandth or a cent that leaks in quantization fails the test outright rather than surviving under an isclose tolerance. Beyond these per-pool checks, the stage needs a property to hold across every occupancy: the grossed figure produced with the clamps must never exceed the figure the un-floored, un-capped factor would produce, and must be strictly smaller whenever a floor or ceiling was active. The fingerprint on each result closes the loop for an audit — re-running a prior period must reproduce the identical hash, proving the same bounds were in force and the same clamp fired.
The unbounded per-occupancy factor these guards constrain is derived in the companion guide on calculating gross-up adjustments for variable occupancy, and the clamped result flows back into the parent gross-up normalization logic stage, which recombines it with the fixed portion before allocation.
Related
- Gross-Up Normalization Logic — the parent stage that computes the variable-pool normalization these floors and ceilings bound.
- Calculating Gross-Up Adjustments for Variable Occupancy — the per-period factor derivation that this page constrains with contractual limits.
- Managing Expense Caps and Controllable Limits — the fiscal-year recovery ceilings applied after allocation, distinct from an occupancy-driven gross-up ceiling.