Routing Low-Income Assistance Flags Automatically
Once an account’s eligibility is known, a single question decides whether the bill is right: where does the flag go? This page is the dispatch layer that sits under the Assistance Program Eligibility Taxonomy, inside Municipal Utility Billing Architecture & Rate Taxonomy. The failure mode it resolves is the mis-route: a residential hardship credit computed with float that reconciles a cent off, a percentage discount handed to a commercial account that is not entitled to a direct rate reduction, or a flagged account whose rate structure failed to resolve and so gets billed at full price with no trace. The fix is a router that maps (customer_class, assistance_flag) to exactly one action through an explicit table, computes any credit with decimal.Decimal and a hard cap, and refuses to guess — every unmapped or degraded case falls to a deferred queue or manual review, never to a silent full-price bill.
Prerequisites
The imports and the data contract this router assumes — nothing else.
from __future__ import annotations
from dataclasses import dataclass
from decimal import Decimal, ROUND_HALF_UP
from enum import Enum
import hashlib
- Python 3.11+ for the
X | Noneunion syntax and modernenumsemantics; no third-party runtime is required for the router itself. decimal.Decimalfor every money value — the base charge, the credit, and the posted charge. A percentage discount computed in binaryfloatdrifts, and thousands of off-by-a-cent bills are exactly what reconciliation cannot close.- A resolved eligibility flag as input. This router runs after status resolution: the
ACTIVE/GRACEdecision, effective-date and grace-window math, and income verification are already handled upstream by the parent taxonomy. Here the flag is a settled fact; routing decides the billing consequence. - A resolved base charge. The rate engine has already priced consumption for the service period following Step-Rate vs Block-Rate Structure Design; the router adjusts that resolved charge, it does not re-rate usage.
Annotated Implementation
The router below is the whole dispatch layer. It classifies the account with Customer Class & Service Tier Mapping, looks up the single permitted action in a deterministic table, computes any credit with a cap so a household is never credited below zero, and seals every decision into an audit record before it leaves the function.
Figure: One resolved flag, one action — the router converges every branch, including the deliberate class guard, onto a single hash-sealed audit record.
CENTS = Decimal("0.01")
class CustomerClass(str, Enum):
RESIDENTIAL = "residential"
COMMERCIAL = "commercial"
INDUSTRIAL = "industrial"
class AssistanceFlag(str, Enum):
LIHEAP_DISCOUNT = "liheap_discount" # low-income percentage credit
MEDICAL_BASELINE = "medical_baseline" # fixed exempt-allowance credit
DEFERRED_PAYMENT = "deferred_payment" # arrears plan, no rate change
NONE = "none" # no assistance on this account
class RouteAction(str, Enum):
APPLY_CREDIT = "apply_credit"
DEFER_PAYMENT = "defer_payment"
PASSTHROUGH = "passthrough"
MANUAL_REVIEW = "manual_review"
# Exactly one action per (class, flag). The table is the policy: a direct rate
# reduction is a residential customer-protection instrument, so commercial and
# industrial hardship flags are deliberately absent and fall through to a guard
# below rather than silently receiving a credit they are not entitled to.
ROUTING_TABLE: dict[tuple[CustomerClass, AssistanceFlag], RouteAction] = {
(CustomerClass.RESIDENTIAL, AssistanceFlag.LIHEAP_DISCOUNT): RouteAction.APPLY_CREDIT,
(CustomerClass.RESIDENTIAL, AssistanceFlag.MEDICAL_BASELINE): RouteAction.APPLY_CREDIT,
(CustomerClass.RESIDENTIAL, AssistanceFlag.DEFERRED_PAYMENT): RouteAction.DEFER_PAYMENT,
(CustomerClass.COMMERCIAL, AssistanceFlag.DEFERRED_PAYMENT): RouteAction.DEFER_PAYMENT,
(CustomerClass.INDUSTRIAL, AssistanceFlag.DEFERRED_PAYMENT): RouteAction.DEFER_PAYMENT,
}
@dataclass(frozen=True, slots=True)
class BillingContext:
"""Everything the router needs, already resolved upstream. Frozen so a
routing decision can never mutate the inputs it was judged against."""
account_id: str
customer_class: CustomerClass
assistance_flag: AssistanceFlag
base_charge: Decimal # resolved by the rate engine
discount_pct: Decimal = Decimal("0") # e.g. Decimal("0.25") for 25%
baseline_credit: Decimal = Decimal("0") # fixed $ value of exempt volume
@dataclass(frozen=True, slots=True)
class RoutingResult:
account_id: str
action: RouteAction
posted_charge: Decimal # what the ledger receives
credit_applied: Decimal
integrity_hash: str
def _to_money(value: Decimal) -> Decimal:
# Quantize once, at the boundary, so no fractional cent survives to the GL.
return value.quantize(CENTS, rounding=ROUND_HALF_UP)
def _credit_for(ctx: BillingContext) -> Decimal:
# One rule fires per flag; the credit is capped at the gross charge so a
# subsidy can never invert the bill into a negative (a refund it is not).
if ctx.assistance_flag is AssistanceFlag.LIHEAP_DISCOUNT:
raw = ctx.base_charge * ctx.discount_pct
elif ctx.assistance_flag is AssistanceFlag.MEDICAL_BASELINE:
raw = ctx.baseline_credit
else:
raw = Decimal("0")
return min(raw, ctx.base_charge)
def _seal(account_id: str, action: RouteAction, posted: Decimal, credit: Decimal) -> str:
# Tamper-evident: any later edit to the routed amounts changes the digest,
# so the audit log proves the posted charge was never altered after the fact.
basis = f"{account_id}|{action.value}|{posted}|{credit}"
return hashlib.sha256(basis.encode("utf-8")).hexdigest()
def route_assistance_flag(ctx: BillingContext) -> RoutingResult:
"""Dispatch a resolved assistance flag to exactly one billing action."""
# 1. No assistance -> the charge passes through untouched.
if ctx.assistance_flag is AssistanceFlag.NONE:
posted = _to_money(ctx.base_charge)
return RoutingResult(
ctx.account_id, RouteAction.PASSTHROUGH, posted, Decimal("0.00"),
_seal(ctx.account_id, RouteAction.PASSTHROUGH, posted, Decimal("0.00")),
)
# 2. Policy guard: a non-residential account carrying a rate-reduction flag
# is a mis-classification, not a discount. Route it to a deferred plan
# (which every class may use) instead of applying an unentitled credit.
action = ROUTING_TABLE.get((ctx.customer_class, ctx.assistance_flag))
if action is None and ctx.customer_class is not CustomerClass.RESIDENTIAL:
action = RouteAction.DEFER_PAYMENT
# 3. Anything still unmapped (unknown class/flag pair) is escalated, never
# guessed — the whole point of the router is to make gaps visible.
if action is None:
action = RouteAction.MANUAL_REVIEW
if action is RouteAction.APPLY_CREDIT:
credit = _to_money(_credit_for(ctx))
posted = _to_money(ctx.base_charge - credit)
else:
# DEFER_PAYMENT and MANUAL_REVIEW change the bill's *handling*, not its
# amount: the full charge stands while an arrears plan or a caseworker
# takes over, so no credit is posted here.
credit = Decimal("0.00")
posted = _to_money(ctx.base_charge)
return RoutingResult(
ctx.account_id, action, posted, credit,
_seal(ctx.account_id, action, posted, credit),
)
The load-bearing detail is the ordering of the three fall-throughs: the routing table encodes what is allowed, the policy guard converts a non-residential rate-reduction flag into a deferred plan rather than a credit, and only a genuinely unknown pair reaches MANUAL_REVIEW. A flagged account can therefore never leave this function at full price without also being tagged for deferral or review — the silent full-price bill is structurally impossible. A DEFER_PAYMENT result then feeds arrears handling, and any account that could not resolve its rate at all is handed to Fallback Routing for Missing Rate Data before it ever reaches this router.
Edge Cases and Billing Gotchas
- Commercial account carrying a residential hardship flag. A data-entry error or a mis-migrated ERP record can attach a
LIHEAP_DISCOUNTto a small commercial account. The routing table has no entry for that pair, so the policy guard sends it toDEFER_PAYMENT(a plan any class may use) instead of applying a rate reduction the account is not entitled to — preventing the cross-subsidization that surfaces in a quarterly audit as an unexplained revenue gap. - Discount exceeds the gross charge. A low-usage month can leave a base charge smaller than the computed percentage or baseline credit.
min(raw, ctx.base_charge)caps the credit at the gross charge so the posted amount floors at0.00; a subsidy reduces a bill, it never becomes a cash refund the router was never authorized to issue. - Rounding drift on a percentage credit.
base_charge * discount_pctproduces long decimals. Quantizing the credit and the posted charge exactly once, at the boundary, withROUND_HALF_UPkeeps the two internally consistent (credit + posted == base_charge) so reconciliation against the Data Governance & Privacy Compliance ledger never breaks by a cent. - Unknown class/flag pair after a program change. When a new program tier ships upstream but the routing table has not yet been extended, the pair is unmapped and the account routes to
MANUAL_REVIEWrather than defaulting to a credit or a passthrough. The gap is loud by design, and the audit hash records exactly which accounts were held.
Verification Snippet
Prove the two invariants that keep the ledger whole: a credit never exceeds the gross charge, and a non-residential rate-reduction flag never receives a credit. Both assert with Decimal equality — never float tolerance.
def test_capped_credit_and_class_guard():
# Residential LIHEAP: 25% off an exact charge posts to the cent.
res = route_assistance_flag(BillingContext(
account_id="ACC-00010001",
customer_class=CustomerClass.RESIDENTIAL,
assistance_flag=AssistanceFlag.LIHEAP_DISCOUNT,
base_charge=Decimal("120.00"),
discount_pct=Decimal("0.25"),
))
assert res.action is RouteAction.APPLY_CREDIT
assert res.credit_applied == Decimal("30.00") # exact, not 29.999...
assert res.posted_charge == Decimal("90.00")
assert res.credit_applied + res.posted_charge == Decimal("120.00")
# Commercial account with the same flag: NO credit, routed to deferral.
com = route_assistance_flag(BillingContext(
account_id="ACC-00020002",
customer_class=CustomerClass.COMMERCIAL,
assistance_flag=AssistanceFlag.LIHEAP_DISCOUNT,
base_charge=Decimal("120.00"),
discount_pct=Decimal("0.25"),
))
assert com.action is RouteAction.DEFER_PAYMENT
assert com.credit_applied == Decimal("0.00")
assert com.posted_charge == Decimal("120.00")
assert len(com.integrity_hash) == 64
Run the same suite against a corpus of hand-verified fixtures before every deployment. A single mismatch means a table, guard, or rounding regression that would otherwise ship as thousands of mis-routed bills.
Frequently Asked Questions
Related Topics
- Assistance Program Eligibility Taxonomy — the parent workflow that resolves the flag this page routes.
- Customer Class & Service Tier Mapping — the class model the routing table keys on.
- Step-Rate vs Block-Rate Structure Design — how the base charge this router adjusts is priced.
- Fallback Routing for Missing Rate Data — where accounts with an unresolvable rate go before reaching this dispatch.
- Security Boundaries & Role-Based Access — who may override a routing decision or edit eligibility state.
- Data Governance & Privacy Compliance — the metadata-only audit and retention discipline the sealed record satisfies.
Up one level: Assistance Program Eligibility Taxonomy · Parent guide: Municipal Utility Billing Architecture & Rate Taxonomy · Return to the utilitybilling.org home.