Skip to main content

Revenue Based estimates V1: 8–12% of annual revenue

Status: accepted Date: 2026-07-28 Fills the ADR-0008 follow-up (“MCA/BLOC funding range formulas”) with the V1 product rule: the Revenue Based pre-approval estimate is 8–12% of exact annual business revenue, applied identically to MCA and BLOC. SBA still never gets a pre-approval estimate (ADR-0003 / ADR-0008).

Decision

  1. Input: a new optional annualRevenue (exact dollars/year, operator-entered) flows through the canonical input factory (assembleUnderwritingInput) into UnderwritingInput, and is persisted on underwritingResults.annualRevenue. It is separate from the questionnaire’s banded avgRevenue, which remains the eligibility input (ADR-0009). No GHL custom field in V1 — the value lives in Convex and re-underwrite carries it forward server-side (getLatestAnnualRevenueByReportIdInternal), so re-runs triggered by other field edits don’t clear estimates.
  2. Formula: computeRevenueBasedEstimate (convex/lib/revenueBasedEstimate.ts) returns { low: 8%, high: 12% } of annual revenue, rounded to whole dollars; null when revenue is absent/non-positive.
  3. Attachment: deriveProductDecisions attaches the identical estimate to the mca and bloc Product Decisions regardless of status — mirroring how cardEstimate rides on card_stacking — and never to sba.
  4. Count-once rule: Total Estimated Funding = Cards + Term Loan + Revenue Based, where the RB contribution is counted once (never MCA + BLOC summed). lib/funding/estimatedFundingTotals.ts owns the derivation: the RB contribution comes from the first of MCA/BLOC that is qualified/qualified_conditional and carries an estimate.
  5. Term loan seam: until the term-loan-estimates project ships, the TL contribution comes only from the operator override (operatorOverrides.termLoanFundingRange). The totals helper takes TL as an input, so engine-computed TL ranges will flow through with no shape change.

Context

The client overview redesign shows a Total Estimated Funding strip and per-product ranges on the Product Decisions card. Product supplied the V1 RB rule (8–12% of annual revenue). Questionnaire revenue is banded (“20,00020,000 - 49,999”), too coarse for a dollar estimate, so operators enter an exact annual figure instead.

Considered options

  • A — Derive from banded avgRevenue midpoints — rejected; bands are too coarse and the top band is open-ended.
  • B — Exact annual revenue input + engine-computed estimate (accepted).
  • C — GHL custom field as the source of truth — rejected for V1; requires per-location field creation (ops burden). Can be added later as a discovery pattern without changing the engine seam.

Consequences

  • Golden persona snapshots: unchanged — personas provide no annualRevenue, so MCA/BLOC estimates stay null.
  • UI must not sum MCA + BLOC into totals; use resolveRevenueBasedContribution.
  • A fresh credit pull (new report) starts without annual revenue until the operator enters it again or a contact-level carry-forward ships; re-underwrites of the same report carry it forward automatically.