Pylon buyout discounts now finalize net TCV after pricing

Dealops 2 quote finalization now applies Pylon’s organization-configured buyout concession once, keeps the order form and pricing footer on the same subtotal, and leaves raw pricing-engine facts intact.

Author: @mehulshinde PR: dealops#7207 Status: open Branch: codex/pylon-buyout-net-tcv Files: 41 Scope: Dealops 2 + Dealops 3 specs/formulas

What it fixes
Pylon’s order form already subtracted a buyout discount, but the pricing-page TCV did not. The verified 2% example now displays $82,843.32 from $84,534 − $1,690.68.
Where it lives
The new boundary is finalizeQuoteSummary: calculate raw engine output, apply amendment accounting, then attach summary.buyoutAdjustment.
What stays raw
Pricy, engine TCV, product revenue, ARR, promotion totals, approval inputs, CRM inputs, traces, and engine-only analyses keep their existing meanings.
Rollout shape
Configuration is opt-in via pricing spec. The included enablement script targets only local Neon Pylon Test Org; there is no production config change, schema migration, or backfill.
Raw pricing engine
Quote finalizer
Order-form subtotal
Buyout adjustment
Pylon formulas/specs
UI footer / trace

1. Why this exists

Before
Pricing page headline$84,534.00
Order form net payable$82,843.32

Two customer-facing surfaces disagreed because only the order-form formula subtracted the buyout.

After
Engine TCV$84,534.00
Buyout discount−$1,690.68
Configured net TCV$82,843.32

The payable headline now uses the same concession as the order form, without mutating engine TCV.

Design choice: keep Pricy unchanged. This PR adds a post-pricing, quote-level adjustment block so consumers can choose the payable headline while still seeing raw pricing facts.

2. What changes

Finalization finalizeQuoteSummary.ts and service/router callers now share one output boundary.
Buyout math computeBuyoutAdjustment.ts produces baseTcv, subtotal, discount, and net.
Shared subtotal orderFormQuoteTotals.ts is used by both server finalization and CEL builtins.
Presentation Footer fallback paths, tooltip tokens, and trace sheet display make the new block visible.
Area Files Reviewer focus
Types packages/types/v2/buyoutAdjustment.ts, pricingQuoteOutput.ts, pricingSpecData.ts Adds opt-in config and optional output schema; no DB migration.
Server quote paths PricingQuoteService.ts, pricingEngine/calculatePricing.ts, pricingQuote/get.ts, pricingQuote/update.ts Create, update, recompute, preview, and recalculating GET branches finalize through the same function.
Order form runtime buildInput.ts, builtins.ts, pylonPriceSummary.json, pylonBuyoutValue.json CEL formulas prefer saved concessions and keep legacy behavior when the block is absent.
Spec conversion pricingSpec/converter.ts, pricingSpec/v2Converter.ts, flowSpec/* Preserves buyoutAdjustment, footer fallbackPath, and tooltip text across V2/V3.
Client display FinancialSummaryBottomBar.tsx, PricingTraceSheet.tsx Footer can read a primary path with fallback; trace sheet explains buyout is applied after pricing.
Enablement + docs enablePylonBuyoutAdjustments.ts, knowledge/concepts/quote-level-adjustments.md Local-only Neon enablement and a knowledge entry documenting the finalization contract.

3. How it works

Finalization order
  1. Compute raw PricingEngineSummary.
  2. Copy the summary; do not mutate raw output.
  3. Apply amendment override when that context exists.
  4. Compute optional buyoutAdjustment.
Buyout activation
  • Requires pricingSpecData.buyoutAdjustment.
  • Only grants on NEW_BUSINESS.
  • Selection term must be one of configured activeValues.
  • Bad historical amount/unit values read as zero buyout.
Subtotal contract
  • Eligible, non-complimentary product list value.
  • Minus line discounts.
  • Minus booked promotion from the summary.
  • Product types are normalized, so Pylon title-case tags match.
Core calculation shape
baseTcv = summary.tcv.all
subtotal = eligibleList - max(eligibleList - eligibleNet, 0) - promotionDiscounts.total

buyoutDiscount =
  inactive ? 0 :
  unit === '$' ? amount :
  baseTcv * amount / 100   // blank unit also means percent

netTcv = subtotal - buyoutDiscount

The percent base and subtotal intentionally can differ. That matches Pylon’s published formula: percent uses engine TCV; payable subtotal uses the order-form product scope.

4. Before / after numeric parity

Opportunity Engine TCV Product subtotal after promotion Buyout Net in server + CEL
New business $84,534 $84,534 2% = $1,690.68 $82,843.32
Renewal $300 $84,534 $0 $84,534
Amendment −$500 $1,900 $0 $1,900
Important non-new-business behavior
Renewals and amendments still compute the real order-form subtotal. They only zero the buyout; they do not replace order-form net with engine TCV.
Idempotency
Repeated save/recompute starts from raw summary values and attaches one adjustment. A save cannot subtract the concession twice.

5. UI, formulas, and configuration

Pricing footer

The footer can point at buyoutAdjustment.netTcv and fall back to tcv.all for historical saved outputs.

Tooltip strings can interpolate pricing values using {pricing.buyoutAdjustment.subtotal}-style tokens.

Trace sheet

The trace sheet shows a compact buyout row:

subtotal − buyoutDiscount = netTcv

It also clarifies the detailed pricing breakdown remains pre-buyout.

Pylon formulas

pylonPriceSummary and pylonBuyoutValue prefer saved input.pricing.buyoutDiscount.

When absent, they retain the legacy branch for older outputs.

Local enablement script

6. Tests and validation

Mocha coverage

115 tests passed across buyout computation, ECM parity, input validation, Pylon formulas, runtime regressions, order-form input, and footer conversion.

Jest coverage

11 existing amendment-credit tests passed. This matters because the buyout finalizer runs after amendment accounting.

Integration scenarios

Three Neon-backed scenarios covered create, preview, service recompute, repeated save/reload, edits, ECM lifecycle, frozen output, and pinned-spec behavior.

Manual parity check

The unchanged 2% local Pylon page displays $82,843.32. Fixtures also cover Pylon’s title-case product tags.

Validation note: server TypeScript only reported a pre-existing unrelated local script error in repairMergeCoTermQuotes.main.ts. That script is not part of this PR.

7. What it doesn’t change

8. Risks / rollback / open questions

Primary risk: the configured payable headline can differ from engine TCV by design. Reviewers should verify downstream consumers use buyoutAdjustment.netTcv only where the payable Pylon headline is intended.
Rollback
  • Remove or stop publishing pricingSpecData.buyoutAdjustment.
  • Point the footer metric back to tcv.all or rely on its fallback.
  • Revert formula release if needed; historical saved outputs remain readable.
Review focus
  • Finalization happens exactly once in create/update/recompute/preview paths.
  • GET does not mix saved output with live spec config.
  • Renewal/amendment subtotals stay real while buyout is zero.
Open questions

No explicit product open questions are listed in the PR. The main operational decision is when, if ever, to publish equivalent configuration outside the local Pylon test org.