Plaid v2 tier walks now key off the real effective monthly minimum
The placeholder that read raw rep-typed MM is gone — both recommendedPrice and l1..l4price now delegate to evaluatePlaidEffectiveMonthlyMinimum, with a parity fixture and Neon e2e guarding the swap.
getEffectiveMonthlyMinimumValue in the Plaid registry that delegates to the contractual MM calc (multiplier × proration × rampable-support), cached per quote input via WeakMap.
resolveRecommendedPrice, resolveApprovalPrice) now look up tiers using the computed effective MM instead of the rep-typed value. Parity harness rewired to match.
1. Why this exists
Plaid's v2 price lookups need to pick the right monthly-minimum tier when resolving list prices and approval prices. Each tier is keyed by a minimum MM threshold — the higher the effective MM, the deeper the tier (lower price). Two formulas drive this:
resolveRecommendedPrice→LIST_PRICE/ L0resolveApprovalPrice→APPROVAL_PRICE/ L1..L4
The real contractual effective MM is non-trivial: rep-typed base × number of MM-line product codes, plus rampable-support contributions, prorated by subscription term. evaluatePlaidEffectiveMonthlyMinimum (shipped by dealops-xq9.31) computes exactly that — but nothing consumed it. Both tier walks instead used a placeholder helper that just read minimumCommitment.monthlyMinimumAmount.value straight off the rep input.
Consequence: any deal where the effective MM diverges from the rep-typed value (multiple MM-line products, rampable support, sub-12-month terms) could pick the wrong tier compared to v1.
2. Before / after
function getEffectiveMonthlyMinimum(
attr: FormulaEvaluateAttr
): number {
const mm = attr.pricingQuoteInput
.minimumCommitment
?.monthlyMinimumAmount?.value;
return typeof mm === 'number' && mm >= 0
? mm : 0;
}
// TODO: swap this for the real
// effectiveMonthlyMinimum variable
// (8 sub-pieces: MM-product fan-out,
// rampable support, term proration…)
const _effectiveMMCache =
new WeakMap<object, number>();
function getEffectiveMonthlyMinimumValue(
attr: FormulaEvaluateAttr
): number {
const key = attr.pricingQuoteInput;
if (key && _effectiveMMCache.has(key)) {
return _effectiveMMCache.get(key)!;
}
const mm =
evaluatePlaidEffectiveMonthlyMinimum(attr);
const val = typeof mm?.value === 'number'
&& mm.value >= 0 ? mm.value : 0;
if (key) _effectiveMMCache.set(key, val);
return val;
}
Both resolveApprovalPrice and resolveRecommendedPrice were repointed at the new helper; the placeholder and its TODO are deleted; the stale "downstream consumers can call into it" comment on the effectiveMonthlyMinimum variable definition was updated to past tense.
3. The formula being wired in
The contractual calc (already in PlaidEffectiveMonthlyMinimum.ts, untouched by this PR) is:
+ sum(listPrice of rampable-support products))
× min(subscriptionTerms, 12) / 12
The four legs, and which tests exercise each:
| Leg | What it does | Covered by |
|---|---|---|
| Multiplier | base × number of MM-line product codes | Registry unit test #1; parity fixture; e2e |
| Rampable support | sum list-price of products with productCode in RAMPABLE_SUPPORT_PRODUCT_CODES | Registry unit test #2; e2e |
| Proration | × min(terms, 12) / 12 (sub-12 month deals) | Registry unit test #3; parity fixture |
| Fail-open | 0 when unset / invalid / negative — picks lowest tier | Registry unit test #4 |
4. Where the call sites moved
Two one-line repoints inside registry.ts:
// resolveApprovalPrice (L1..L4)
- const monthlyMin = getEffectiveMonthlyMinimum(attr);
+ const monthlyMin = getEffectiveMonthlyMinimumValue(attr);
// resolveRecommendedPrice (L0)
- const monthlyMin = getEffectiveMonthlyMinimum(attr);
+ const monthlyMin = getEffectiveMonthlyMinimumValue(attr);
The downstream getVal(attr, { type: APPROVAL_PRICE_SELECTOR_TAG, ... monthlyMin }) call is unchanged — the selector tag matching still uses the same MM key, but now that key is the contractually-correct number.
5. The parity harness had to move with it
The parity harness lives at apps/server/src/scripts/penguin/2026_05_15__v1_v2_quote_parity/. It runs three layers per fixture and asserts they agree:
catalog_parity.csv, walks v1's monthlyMinimumTiers at the fixture's MM.
datasheet.json, walks tiers via pickTierByMonthlyMin.
PricingEngineService end-to-end and calls getRevenue per product.
Before this PR, layers 1 and 2 keyed off the fixture's typed monthlyMinimum directly, and layer 3 did the same internally because the registry placeholder also read the raw value. All three agreed by accident. After the swap, layer 3's registry now computes a different number (when codes/term differ from defaults), so layers 1 and 2 would diverge from layer 3 unless they too compute the effective value.
The fix: a shared helper effective_mm.ts that calls the same pure primitive (computeEffectiveMonthlyMinimum) the registry uses. All three layers now key off the value it returns.
The complex-MM fixture that guards the swap end-to-end
Added to fixtures.ts:
| Field | Value | Effect |
|---|---|---|
name | complex-mm-auth-multiline-prorated | — |
monthlyMinimum | 1000 | Typed base |
additionalMonthlyMinimumProductCodes | ['MIN - FLAT', 'MIN - CRA', 'MIN - FLATEC', 'MIN - SHA'] | Multiplier = 4 |
subscriptionTerms | 6 | Proration = 6/12 = 0.5 |
| effectiveMM = 1000 × 4 × 0.5 = 2000 — crosses a tier boundary on Auth USD/CPQ | ||
| Result | typed 1000 → unit 1.335; effective 2000 → unit 1.32 | Different tier; both rows are exact_match in v1, so parity stays match |
CSV schema gets an effective_monthly_minimum column
The golden CSV grew one column (effective_monthly_minimum) right after monthly_minimum. For every pre-existing fixture they're equal — the default fallback in codesForFixture returns ['MIN - FLAT'] (one code, multiplier 1) and subscriptionTerms defaults to 12 (proration 1). The new fixture is the only row where the two columns differ:
complex-mm-auth-multiline-prorated,Auth,USD,CPQ,1000,2000,100000,1.32,1.32,...,match,true
Guard against silently-divergent fixtures
The per-cell layers pass products: [] into the MM primitive, so they contribute zero from the rampable-support leg. The engine layer, on the other hand, would happily fold any support-SKU product's price into its internal effective MM. To prevent a future fixture from quietly diverging layer 3 from layers 1+2, drive_v2_engine.ts now rejects fixtures whose products contribute to the effective MM:
for (const { name, productSpec } of resolved) {
if (productSpec && doesProductContributeToMonthlyMin(productSpec.productCode)) {
throw new Error(
`Parity fixture '${fixture.name}' contains product '${name}' ` +
`(productCode='${productSpec.productCode}'), which contributes to the ` +
`effective monthly minimum. ...`
);
}
}
6. How the engine driver threads the new inputs
For the engine to compute the same effectiveMM the per-cell helper computes, three quote-input pieces have to be threaded through:
| Input | Where it lives on PricingQuoteInput | Source in fixture |
|---|---|---|
monthlyMinimumAmount | minimumCommitment.monthlyMinimumAmount | fixture.monthlyMinimum |
| MM-line codes | injected as a termInput with id ADDITIONAL_MONTHLY_MINIMUM_PRODUCT_CODES_TERM_ID | codesForFixture(fixture) |
| Subscription term | subscriptionTerms | fixture.subscriptionTerms ?? 12 |
minimumCommitment.enabled is still false — that suppresses applyMonthlyMinimumDiscount, which is correct for this harness (we want per-product price × volume parity, not the cross-contribution discount). Wiring enabled=true fixtures is dealops-xq9.34's job.
7. The Neon e2e
A DB-gated check (e2e_effective_mm_neon.ts) loads the real Plaid Test Org PricingSpec from Neon, sets up inputs that put the typed MM in one tier and the effective MM (after multiplier + support) in a deeper tier, and asserts PricingEngineService picks the deeper one. Runs only when NEON_DB_URL is set.
selectorTags from datapoint rows; the e2e loads them from the committed datasheet.json instead, with a tier-0 price cross-check that guards against catalog drift between the committed snapshot and the live DB.
8. What it doesn't change
- No change to
evaluatePlaidEffectiveMonthlyMinimumitself — this PR consumes it, doesn't modify it. - No change to
applyMonthlyMinimumDiscountor the MM cross-contribution / 60%-of-revenue discount. Those still run only whenminimumCommitment.enabled = true; the harness keeps it false. - No change to the v1 codepath. Dealops 1 was already correct.
- No change to the existing golden prices or revenues — every previously-passing parity row is byte-identical after the swap (because their effective MM equals their typed MM under the default 1-code / 12-month assumption).
- No change to ramps (
cjd), renewals (n5u),transferHiddenProducts(xq9.39), or Signal 3× routing (xq9.7).
9. Risks and follow-ups
evaluatePlaidEffectiveMonthlyMinimum runs once per price-variable eval per product. Per the PR description this is O(N²) for an N-product quote. The WeakMap cache on pricingQuoteInput already collapses the per-variable factor (recommendedPrice / l1..l4 share one computation), so it's effectively O(N) extra work per quote. Negligible at real quote sizes; the author flagged it as a possible follow-up if quotes grow.
drive_v2_engine.ts will fail loudly if anyone tries to add a fixture that would silently exercise that leg only in the engine layer.