Skip to content

Deduplicate rates by tariff_rate_id in tariff_iter_rates_for_dt #52

Description

@alexhyunminlee

What

tariff_iter_rates_for_dt yields the same rate twice when Arcadia inlines a rider rate into the parent tariff. The parent tariff contains both (a) a direct rate entry with populated rate_bands and (b) a separate rider-pointer entry (rider_id set, rate_bands empty) whose resolved rider tariff contains the exact same rate (same tariff_rate_id). The iterator yields both without deduplication, causing the charge to be counted twice in the URDB output.

Why

This produces incorrect URDB tariffs. For example, BGE's Universal Service Charge (tariff_rate_id=18603035, $0.32/month) is yielded once from the inline entry and once from rider 669, producing a total of $0.64/month. The Maryland OPC confirms the actual charge is a single fixed fee (currently ~$0.36/month). The bug affects both fixed charges and consumption-based energy rates for any utility where Arcadia inlines rider rates into the parent tariff.

Known affected tariffs (Maryland):

BGE (masterTariffId=674): Universal Service Charge counted twice → fixed charge overstated by $0.32/month
Pepco (masterTariffId=832): Electric Universal Service surcharge counted twice → fixed charge overstated by ~$0.05/month
DPL (masterTariffId=2639): Renewable Portfolio Credit counted twice → fixed charge understated by ~$0.06/month (credit applied twice)
Hagerstown (masterTariffId=3240941): Universal Service Program Charge counted twice in energy rates

How

Add tariff_rate_id deduplication to tariff_iter_rates_for_dt. Pass a seen set through the recursive rider traversal and skip any rate whose tariff_rate_id has already been yielded:

def tariff_iter_rates_for_dt(tariff, scenario, library, dt, _seen=None):
    if _seen is None:
        _seen = set()
    rates = tariff.get("rates", [])
    for rate in rates:
        if not rate_is_applied_to_scenario(rate, scenario, library):
            continue
        if not rate_is_applied_to_datetime(rate, dt):
            continue
        if rate["rate_bands"]:
            rate_id = rate["tariff_rate_id"]
            if rate_id in _seen:
                continue
            _seen.add(rate_id)
            yield rate
        elif rider_id := rate.get("rider_id"):
            rider_tariff = library.tariffs.get_tariff(rider_id)
            yield from tariff_iter_rates_for_dt(rider_tariff, scenario, library, dt, _seen)

The _seen parameter defaults to None so the public API signature is unchanged.

Deliverables

tariff_iter_rates_for_dt deduplicates by tariff_rate_id so that the same physical rate is never yielded more than once per call.
Test case: BGE (masterTariffId=674) fixed charge resolves to ~$9.97 (not $10.29) with charge_classes={DISTRIBUTION, TRANSMISSION, OTHER} and competitiveBilling=False.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions