← Back to Interaction Rule Set

Clarity Engine — Conventional Mortgage Skill

Version: 1.0 | Status: Implementation-Ready — Gear 1

Table of Contents SKILL PURPOSE INVOCATION EXECUTION SEQUENCE STAGE 2 — EXTRACT QUALIFICATION INPUTS STAGES 3–6 — ELIGIBILITY GATES STAGE 7 — LLPA-ADJUSTED RATE STAGE 8 — P&I PAYMENT STAGE 9 — INCOME QUALIFICATION STAGE 10 — DTI COMPUTATION STAGE 11 — AUS PATH DETERMINATION STAGE 12 — PMI COMPUTATION STAGE 13 — FULL PITI / PITIA COMPUTATION STAGE 14 — RESERVE VERIFICATION STAGE 15 — CASH TO CLOSE STAGE 16 — FINAL QUALIFICATION DETERMINATION STAGE 17 — EMIT ConventionalQualResult WORKED EXAMPLES FORBIDDEN PATTERNS COMPANION SKILLS

Clarity Engine — Conventional Mortgage Skill

Version: 1.0 | Status: Implementation-Ready — Gear 1

Scope: Full Fannie Mae / Freddie Mac conventional loan qualification engine. Executes eligibility gates, income qualification, DTI computation, LLPA rate adjustment, PMI calculation and cancellation, reserve verification, AUS path determination, and final qualification result. Covers purchase, rate/term refinance, and cash-out refinance. Supports PRIMARY, SECOND_HOME, and INVESTMENT occupancy.

Confidential: PreFi, Inc. / Purpose Technology, Inc. d/b/a Purlend

Primary Reference: Fannie Mae Selling Guide (December 2025). All rule citations follow Fannie Mae B-series sections. Freddie Mac LPA mirrors for most standard scenarios — deviations noted explicitly.

SKILL PURPOSE

This skill takes a validated BorrowerProfile and a ProgramEvaluationQueue entry for CONVENTIONAL and produces a ConventionalQualResult — the definitive conventional mortgage qualification determination, with full computation trail, AUS path, DTI, PMI, rate, payment, cash-to-close, reserve status, and constraint flags.

This skill is the first dependency for the Optimization, Scenario Generation, and Ranking skills. It must be numerically correct on every execution. When in doubt, the more conservative underwriting rule applies.

This skill produces:

This skill does NOT produce:

Mortgage family scope: CONVENTIONAL only

Forbidden families: Never apply FHA MIP logic, VA residual income rules, or DSCR rental-income qualification in this skill.

INVOCATION

Invoke this skill when:

Required inputs:

If either input is absent: return CONVENTIONAL_SKILL_BLOCKED with missing input listed.

**If CONVENTIONAL entry has eligibility = INELIGIBLE:** return CONVENTIONAL_INELIGIBLE — [ineligible_reason from queue] and stop. Do not proceed.

EXECUTION SEQUENCE


Stage 1  — Validate inputs
Stage 2  — Extract qualification inputs
Stage 3  — Gate 1: Occupancy eligibility
Stage 4  — Gate 2: Loan amount / conforming limit
Stage 5  — Gate 3: Credit score minimum
Stage 6  — Gate 4: LTV and down payment
Stage 7  — Compute LLPA-adjusted rate
Stage 8  — Compute P&I payment
Stage 9  — Income qualification (GMI verification)
Stage 10 — DTI computation (front-end and back-end)
Stage 11 — AUS path determination
Stage 12 — PMI computation (if LTV > 80%)
Stage 13 — Full PITI / PITIA computation
Stage 14 — Reserve verification
Stage 15 — Cash-to-close computation
Stage 16 — Final qualification determination
Stage 17 — Build and emit ConventionalQualResult

Run all stages in sequence. Do not skip any stage. Every intermediate value must be carried into the lineage trace.

STAGE 2 — EXTRACT QUALIFICATION INPUTS

Extract and hold the following from input objects:


From BorrowerProfile:
  qualifying_credit_score         integer
  credit_tier                     integer (1–8)
  gmi_for_dti                     decimal — grossed-up qualifying income
  total_monthly_dti_obligations   decimal — all qualifying liabilities
  occupancy_type                  PRIMARY | SECOND_HOME | INVESTMENT
  loan_purpose                    PURCHASE | RATE_TERM_REFI | CASH_OUT_REFI
  property_value                  decimal — MIN(purchase_price, appraised_value)
  purchase_price                  decimal
  appraised_value                 decimal (if refi — use if available)
  down_payment_amount             decimal (purchase only)
  self_employed_flag              boolean
  income_combined_flag            boolean
  monthly_tax                     decimal — property tax / 12
  monthly_insurance               decimal — hazard insurance / 12
  hoa_monthly                     decimal (0 if none)
  funds_available_for_closing     decimal
  funds_available_for_reserves    decimal
  income_sources                  list (for rental income extraction)
  liabilities                     list

From ProgramEvaluationQueue CONVENTIONAL entry:
  preliminary_rate                decimal (Router placeholder — overridden by Stage 7)
  preliminary_loan_amount         decimal
  preliminary_ltv                 decimal
  preliminary_mi_amount_monthly   decimal (Router estimate — verified in Stage 12)
  preliminary_ctc                 decimal

Critical: property_value for LTV computation must always be:


property_value = MIN(purchase_price, appraised_value)

Never use purchase_price alone when an appraisal is available. Appraisal may be lower.

STAGES 3–6 — ELIGIBILITY GATES

Gate 1: Occupancy


Eligible occupancy types: PRIMARY | SECOND_HOME | INVESTMENT
Ineligible: INVESTMENT_COMMERCIAL | any commercial or mixed-use classification

IF occupancy_type NOT IN [PRIMARY, SECOND_HOME, INVESTMENT]:
  return GATE_1_FAIL — "Conventional limited to primary, second home, and investment (residential)"
ELSE:
  gate_1 = PASS

Gate 2: Conforming Loan Limit


conforming_limit_2026 = 806,500  (FHFA baseline — continental US)

IF state IN [AK, HI]:
  conforming_limit = 1,209,750  (150% of baseline per statute)
  flag HIGH_COST_STATE

IF high_cost_area_flag = true:
  flag HIGH_COST_AREA_CHECK
  note: "County-level limit may exceed $806,500. Verify FHFA county limit before applying."
  conforming_limit = county_limit (if provided) OR 806,500 (conservative)

base_loan_amount = property_value - down_payment_amount  (purchase)
                 = current_payoff_balance               (refi)

IF base_loan_amount > conforming_limit:
  gate_2 = FAIL — "Loan amount $[X] exceeds 2026 conforming limit of $[conforming_limit]"
  flag ROUTE_JUMBO
ELSE:
  gate_2 = PASS
  IF base_loan_amount > 0.90 × conforming_limit:
    flag NEAR_LIMIT_CHECK — "Loan is within 10% of conforming limit. Monitor for appraisal shortfall."

Gate 3: Credit Score Minimum


conventional_min_score = 620

IF qualifying_credit_score < 620:
  gate_3 = FAIL — "Conventional minimum score is 620. Current score: [qualifying_credit_score]"
ELSE:
  gate_3 = PASS

Gate 4: LTV and Down Payment


LTV computation:
  conv_ltv = base_loan_amount / property_value
  NOTE: base_loan_amount includes financed fees if any — for conventional, none.

LTV caps by occupancy:
  PRIMARY:     conv_ltv ≤ 0.97  (3% down minimum)
  SECOND_HOME: conv_ltv ≤ 0.90  (10% down minimum)
  INVESTMENT:  conv_ltv ≤ 0.80  (20% down minimum)

IF conv_ltv > ltv_cap[occupancy_type]:
  gate_4 = FAIL — "LTV [X]% exceeds Conventional [occupancy] maximum of [cap]%"
ELSE:
  gate_4 = PASS

Multi-unit LTV caps (if property_type = 2-4 unit):
  2-unit PRIMARY:     ≤ 0.85 (85%)
  2-unit INVESTMENT:  ≤ 0.75 (75%)
  3-4 unit PRIMARY:   ≤ 0.75 (75%)
  3-4 unit INVESTMENT: ≤ 0.70 (70%)
  flag MULTI_UNIT_LTV_APPLIES if property_unit_count > 1

If any gate fails: stop. Set qualification_status = INELIGIBLE. Emit reason. Do not proceed to income/DTI stages.

STAGE 7 — LLPA-ADJUSTED RATE

The Loan Level Price Adjustment (LLPA) converts a base market rate into the borrower's actual note rate based on credit score and LTV. Additional LLPA surcharges apply for occupancy type and property characteristics.

LLPA Table — Credit Score × LTV Band

Use this table to determine the rate adjustment. Values are percentage points added to base market rate.


LTV Band           Score 760+  Score 740-759  Score 720-739  Score 700-719  Score 680-699  Score 660-679  Score 640-659  Score 620-639
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
LTV 95.01–97.00%    0.000%      0.250%         0.500%         0.750%         1.000%         1.500%         2.000%         2.500%
LTV 90.01–95.00%    0.000%      0.250%         0.250%         0.500%         0.750%         1.000%         1.500%         2.000%
LTV 80.01–90.00%    0.000%      0.000%         0.250%         0.250%         0.500%         0.750%         1.000%         1.500%
LTV ≤ 80.00%        0.000%      0.000%         0.000%         0.000%         0.000%         0.250%         0.500%         1.000%

Score Band Lookup


qualifying_credit_score ≥ 760:    use column "Score 760+"
740 ≤ score < 760:                use column "Score 740-759"
720 ≤ score < 740:                use column "Score 720-739"
700 ≤ score < 720:                use column "Score 700-719"
680 ≤ score < 700:                use column "Score 680-699"
660 ≤ score < 680:                use column "Score 660-679"
640 ≤ score < 660:                use column "Score 640-659"
620 ≤ score < 640:                use column "Score 620-639"
score < 620:                      INELIGIBLE — caught at Gate 3

LTV Band Lookup


conv_ltv > 0.9500:  use row "LTV 95.01–97.00%"
conv_ltv > 0.9000:  use row "LTV 90.01–95.00%"
conv_ltv > 0.8000:  use row "LTV 80.01–90.00%"
conv_ltv ≤ 0.8000:  use row "LTV ≤ 80.00%"

Occupancy Surcharge


PRIMARY:      +0.000% (no surcharge)
SECOND_HOME:  +0.125% to +0.375% depending on LTV
              LTV ≤ 75%:   +0.125%
              LTV 75-85%:  +0.250%
              LTV > 85%:   +0.375%
INVESTMENT:   +0.750% for LTV ≤ 75%
              +1.000% for LTV > 75%

Loan Purpose Surcharge


PURCHASE:          +0.000%
RATE_TERM_REFI:    +0.000% (standard)
CASH_OUT_REFI:     +0.375% to +0.750% depending on LTV and score
                   LTV ≤ 60%:  +0.375%
                   LTV 60-70%: +0.500%
                   LTV 70-80%: +0.750%
                   flag CASH_OUT_LLPA_APPLIES

Final Rate Computation


Step 1: llpa_score_ltv = lookup(conv_ltv_band, score_band)
Step 2: llpa_occupancy = lookup(occupancy_type, conv_ltv)
Step 3: llpa_purpose = lookup(loan_purpose, conv_ltv)
Step 4: total_llpa = llpa_score_ltv + llpa_occupancy + llpa_purpose
Step 5: adjusted_rate = base_market_rate + total_llpa

NOTE: base_market_rate is the current market par rate for a primary 30-year fixed.
      Use 6.50% as the system placeholder for Gear 1 (updated from live market data
      when rate feed is connected in Gear 2+).
      total_llpa is ADDED to this base rate.
      Never subtract LLPA. LLPA only adds to rate.

STAGE 8 — P&I PAYMENT


monthly_rate = adjusted_rate / 12
compound     = (1 + monthly_rate)^360
numerator    = monthly_rate × compound
denominator  = compound − 1
pmt_factor   = numerator / denominator
pi_payment   = base_loan_amount × pmt_factor

CRITICAL RULES:
  1. monthly_rate = adjusted_rate / 12  (divide annual rate by 12)
     NEVER use adjusted_rate directly in the compound calculation
  2. Base of exponent: (1 + monthly_rate) — NOT (1 + adjusted_rate)
  3. NEVER round monthly_rate, compound, numerator, or denominator
     Round pi_payment only at final output (2 decimal places)

PMT Factor Reference Table

Pre-computed for verification. All factors independently verified.


Rate    monthly_r    (1+r)^360    factor
6.00%   0.0050000    6.02258      0.0059955
6.25%   0.0052083    6.48917      0.0061572
6.50%   0.0054167    6.99180      0.0063207
6.75%   0.0056250    7.53325      0.0064860
7.00%   0.0058333    8.11650      0.0066530
7.25%   0.0060417    8.74477      0.0068218
7.50%   0.0062500    9.42153      0.0069921
7.75%   0.0064583   10.15051      0.0071641
8.00%   0.0066667   10.93573      0.0073376

STAGE 9 — INCOME QUALIFICATION

The Conventional skill trusts the gmi_for_dti value computed by the Borrower Profile Skill. It does not recompute income from raw sources. It verifies that key income rules are honored and flags any issues.

Income Verification Checks


CHECK 1 — Self-employment documentation:
  IF self_employed_flag = true:
    Require: 2 years personal tax returns + 2 years business tax returns
    Require: CPA letter or P&L for current year
    flag SE_DOCS_REQUIRED
    IF income history_months < 24: flag SE_INCOME_CONDITIONAL
      note: "Self-employment income requires 24-month history per Fannie Mae B3-3.4-01"

CHECK 2 — Variable income history:
  FOR each IncomeSource WHERE income_type IN [BONUS, COMMISSION, OVERTIME]:
    IF history_months < 24: flag VARIABLE_INCOME_CONDITIONAL
      note: "[income_type] requires 24-month history per Fannie Mae B3-3.1-09"

CHECK 3 — Rental income offset for investment properties:
  IF occupancy_type = INVESTMENT:
    rental_income_gross = SUM(qualifying_monthly_amount) from IncomeSource WHERE income_type = RENTAL
    rental_income_net = rental_income_gross × 0.75  (75% gross rent rule, Fannie B3-3.1-08)
    
    IF rental_income_gross > 0:
      subject_property_piti = pi_payment + monthly_tax + monthly_insurance + hoa_monthly
      net_rental_result = rental_income_net - subject_property_piti
      
      IF net_rental_result ≥ 0:
        rental_offset_type = POSITIVE_CASHFLOW
        rental_income_for_dti = net_rental_result  (added to GMI as income)
        gmi_adjusted = gmi_for_dti + rental_income_for_dti
        note: "Positive rental cashflow $[net_rental_result] added to qualifying income"
      ELSE:
        rental_offset_type = NEGATIVE_CASHFLOW
        rental_loss_for_dti = ABS(net_rental_result)  (added to monthly obligations)
        gmi_adjusted = gmi_for_dti  (no change to GMI)
        note: "Negative rental cashflow $[rental_loss_for_dti] added to monthly obligations"
    ELSE:
      rental_income_for_dti = 0
      gmi_adjusted = gmi_for_dti

CHECK 4 — Income continuance (Fannie Mae B3-3.1-01):
  Income must be expected to continue for at least 3 years from note date.
  Flag INCOME_CONTINUANCE_RISK if:
    - Retirement income or pension ends within 3 years
    - Alimony/child support expires within 3 years
    - Non-taxable income source lacks documented continuation
  For Gear 1: document requirement only — flag for human review

CHECK 5 — Student loan IDR rule (Fannie Mae B3-6-05):
  FOR each liability WHERE liability_type = STUDENT_LOAN:
    IF repayment_type = IDR AND monthly_payment < loan_balance × 0.005:
      qualifying_payment = loan_balance × 0.005
      flag STUDENT_LOAN_IDR_OVERRIDE
      note: "Student loan IDR: using 0.5% rule ($[qualifying_payment])"
    ELSE:
      qualifying_payment = actual_monthly_payment

PROHIBITED: Do NOT apply VA gross-up guard rules here.
            VA residual income calculation is confined to VA Module Skill.
            gmi_for_dti from BorrowerProfile already includes gross-up where applicable.

Final Qualifying GMI


IF occupancy_type = INVESTMENT AND rental_offset_type = POSITIVE_CASHFLOW:
  gmi_qualifying = gmi_adjusted  (includes rental positive cashflow)
ELSE:
  gmi_qualifying = gmi_for_dti

Round gmi_qualifying to 2 decimal places at final output only.
All DTI computations use unrounded gmi_qualifying.

STAGE 10 — DTI COMPUTATION


STEP 1 — Housing expense (front-end):
  front_end_housing_expense = pi_payment + monthly_tax + monthly_insurance + hoa_monthly
  NOTE: Do NOT include PMI in front-end DTI numerator.
        PMI is included in back-end only (it is a housing cost, not a housing payment).
        Front-end DTI uses: principal + interest + tax + insurance + HOA

  EXCEPTION: Some lenders include PMI in front-end. Flag FRONT_END_PMI_TREATMENT_VARIES
             for human review when front-end DTI is close to threshold.
  For Clarity Engine Gear 1: exclude PMI from front-end DTI.

  front_end_dti = front_end_housing_expense / gmi_qualifying

STEP 2 — Monthly obligations for back-end DTI:
  monthly_obligations = total_monthly_dti_obligations  (from BorrowerProfile)
  NOTE: This already includes student loan override if CHECK 5 was applied.
  
  IF occupancy_type = INVESTMENT AND rental_offset_type = NEGATIVE_CASHFLOW:
    monthly_obligations = monthly_obligations + rental_loss_for_dti
    flag RENTAL_LOSS_ADDED_TO_DTI

STEP 3 — Back-end DTI:
  total_monthly_debt = front_end_housing_expense + monthly_obligations
  back_end_dti = total_monthly_debt / gmi_qualifying

STEP 4 — PMI impact on PITIA (for informational display, not DTI):
  monthly_pmi = computed in Stage 12 (if LTV > 80%)
  pitia = front_end_housing_expense + monthly_pmi
  total_with_pmi = pitia + monthly_obligations
  back_end_dti_with_pmi = total_with_pmi / gmi_qualifying
  NOTE: back_end_dti_with_pmi is the more complete representation.
        Report BOTH front_end_dti and back_end_dti_with_pmi in ConventionalQualResult.

CRITICAL ROUNDING RULE:
  Use full floating-point precision for gmi_qualifying, front_end_housing_expense,
  and monthly_obligations throughout all DTI computations.
  Round DTI only at final output (4 decimal places for computation, 2 for display).

STAGE 11 — AUS PATH DETERMINATION


DU APPROVE PATH (Fannie Mae Desktop Underwriter):
  back_end_dti_with_pmi ≤ 0.50 (50%):
    aus_path = DU_APPROVE_ELIGIBLE
    note: "Back-end DTI ≤ 50% — eligible for DU Approve/Eligible finding"
    DTI_limit_applied = 0.50

  NOTE: DU may approve DTIs above 45% with compensating factors:
    - 12+ months reserves post-close
    - Significant liquid assets (20%+ down payment)
    - Minimal DTI increase from prior loan
    - Strong residual income (not a formal VA test)
    The Clarity Engine flags these compensating factors but does not guarantee DU Approve.

DU REFER PATH:
  back_end_dti_with_pmi > 0.50:
    aus_path = DU_REFER
    note: "Back-end DTI [X]% exceeds DU 50% limit — DU will likely Refer"

MANUAL UNDERWRITE PATH:
  IF aus_path = DU_REFER:
    manual_eligible = back_end_dti_with_pmi ≤ 0.45
    IF manual_eligible:
      aus_path = DU_REFER_MANUAL_ELIGIBLE
      manual_dti_limit = 0.45
      note: "DTI within manual UW limit (45%). Manual underwrite path available."
      flag MANUAL_UW_COMPENSATING_FACTORS_REQUIRED
    ELSE:
      aus_path = DU_REFER_MANUAL_INELIGIBLE
      note: "DTI [X]% exceeds both DU 50% and manual 45% limits. Conventional ineligible."
      qualification_status = INELIGIBLE_DTI

FREDDIE MAC LPA PATH:
  LPA mirrors DU for most scenarios in Gear 1.
  Flag LPA_PATH_AVAILABLE for advisor review if:
    - DU Refer received
    - Back-end DTI ≤ 45%
    note: "LPA may return Accept where DU issues Refer. Advisor evaluation required."

STAGE 12 — PMI COMPUTATION

PMI Requirement


PMI required:  conv_ltv > 0.80 (80.00%)
PMI not required: conv_ltv ≤ 0.80

If PMI required:
  Determine LTV band:
    conv_ltv > 0.9000 AND conv_ltv ≤ 0.9700: ltv_band = "90.01-97.00"
    conv_ltv > 0.8500 AND conv_ltv ≤ 0.9000: ltv_band = "85.01-90.00"
    conv_ltv > 0.8000 AND conv_ltv ≤ 0.8500: ltv_band = "80.01-85.00"

  Determine score band:
    qualifying_credit_score ≥ 740: pmi_score_band = "740+"
    720 ≤ score < 740:             pmi_score_band = "720-739"
    680 ≤ score < 720:             pmi_score_band = "680-719"
    620 ≤ score < 680:             pmi_score_band = "620-679"

PMI Rate Table (Annual, BPMI — Borrower-Paid Mortgage Insurance)


LTV Band         Score 740+   Score 720-739   Score 680-719   Score 620-679
────────────────────────────────────────────────────────────────────────────
90.01%–97.00%    0.55%        0.75%           1.00%           1.25%
85.01%–90.00%    0.40%        0.55%           0.80%           1.00%
80.01%–85.00%    0.28%        0.40%           0.60%           0.80%

PMI Computation


annual_pmi_rate = pmi_table[ltv_band][pmi_score_band]
monthly_pmi = base_loan_amount × annual_pmi_rate / 12

NOTE: Use unrounded base_loan_amount.
      Round monthly_pmi to 2 decimal places at output only.

PMI Cancellation

Per the Homeowners Protection Act (HPA):


TARGET BALANCES:
  pmi_cancel_request_target = property_value × 0.80
  pmi_auto_cancel_target    = property_value × 0.78

AMORTIZATION LOOP:
  balance = base_loan_amount
  monthly_rate = adjusted_rate / 12
  pmt = base_loan_amount × pmt_factor(adjusted_rate)
  pmi_cancel_request_month = null
  pmi_auto_cancel_month    = null

  FOR n = 1 TO 360:
    interest   = balance × monthly_rate    [full precision — never round]
    principal  = pmt − interest             [full precision — never round]
    balance    = balance − principal        [full precision — never round]

    IF balance ≤ pmi_cancel_request_target AND pmi_cancel_request_month = null:
      pmi_cancel_request_month = n

    IF balance ≤ pmi_auto_cancel_target AND pmi_auto_cancel_month = null:
      pmi_auto_cancel_month = n
      BREAK

CRITICAL: monthly_rate = adjusted_rate / 12
          Do NOT use adjusted_rate directly in the loop.
          Do NOT round balance, interest, or principal at any step.
          Round only final presentation output.

lifetime_pmi = monthly_pmi × pmi_auto_cancel_month

STAGE 13 — FULL PITI / PITIA COMPUTATION


pi_payment       = base_loan_amount × pmt_factor(adjusted_rate)
monthly_tax      = from BorrowerProfile
monthly_insurance = from BorrowerProfile
hoa_monthly      = from BorrowerProfile (0 if none)
monthly_pmi      = from Stage 12 (0 if LTV ≤ 80%)

piti  = pi_payment + monthly_tax + monthly_insurance + hoa_monthly
pitia = piti + monthly_pmi

NOTE: piti = standard housing expense without MI
      pitia = total housing expense including MI
      DTI uses pitia in the back-end calculation (Stage 10, Step 4)
      Display both in ConventionalQualResult

Round piti and pitia to 2 decimal places at output only.

STAGE 14 — RESERVE VERIFICATION


RESERVE REQUIREMENTS BY OCCUPANCY:
  PRIMARY:     2 months PITIA (preferred by DU — not hard required on all files)
               0 months hard minimum for DU Approve
  SECOND_HOME: 2 months PITIA
  INVESTMENT:  6 months PITIA

required_reserves = reserve_months[occupancy_type] × pitia

AVAILABLE RESERVES:
  funds_available_for_reserves = from BorrowerProfile
  (Already net of closing funds and includes 60% retirement credit)

reserve_status:
  IF funds_available_for_reserves ≥ required_reserves:
    reserve_status = MEETS_REQUIREMENT
    reserve_surplus = funds_available_for_reserves - required_reserves
  ELSE:
    reserve_status = SHORTFALL
    reserve_gap = required_reserves - funds_available_for_reserves
    flag RESERVE_SHORTFALL
    note: "Reserve gap: $[reserve_gap]. Required: $[required_reserves]."

GIFT FUND RULE:
  Gift funds may be used for down payment on PRIMARY only.
  Gift funds may NOT be used for investment property down payment.
  Gift funds may NOT be used for reserves.
  IF gift_funds_amount > 0 AND occupancy_type = INVESTMENT:
    flag GIFT_NOT_ELIGIBLE_INVESTMENT
    note: "Gift funds are not eligible for investment property down payment."

STAGE 15 — CASH TO CLOSE


PURCHASE:
  cash_to_close = down_payment_amount
               + estimated_closing_costs
               + prepaids_and_escrow
               − seller_concession_amount
               − lender_credit_amount

  Seller concession limits (Fannie Mae B3-4.1-02):
    PRIMARY, LTV > 90%:    3% of lesser of purchase price or appraised value
    PRIMARY, LTV 75-90%:   6%
    PRIMARY, LTV < 75%:    9%
    SECOND_HOME, any LTV:  6%
    INVESTMENT, any LTV:   2%
    flag SELLER_CONCESSION_LIMIT if seller_concession_amount approaches limit

  Estimated closing costs (Gear 1 estimate — replaced by actual LE in Gear 2):
    1-4% of loan amount depending on state and lender
    Use 2.0% of base_loan_amount as system estimate unless actual provided

  Prepaids and escrow estimate:
    Prepaid interest: (adjusted_rate / 365) × base_loan_amount × 15 days
    Escrow setup: typically 2–3 months of taxes and insurance
    Use (monthly_tax + monthly_insurance) × 3 as Gear 1 estimate

RATE/TERM REFINANCE:
  cash_to_close = estimated_closing_costs + prepaids_and_escrow − lender_credit_amount
  (No down payment — existing equity covers LTV requirement)

CASH-OUT REFINANCE:
  cash_to_close = estimated_closing_costs + prepaids_and_escrow − lender_credit_amount
  cash_received = new_loan_amount − current_payoff_balance − closing_costs
  (Borrower receives cash_received at closing)

CTC FEASIBILITY CHECK:
  IF funds_available_for_closing ≥ cash_to_close:
    ctc_status = MEETS_REQUIREMENT
    ctc_surplus = funds_available_for_closing - cash_to_close
  ELSE:
    ctc_status = SHORTFALL
    ctc_shortfall = cash_to_close - funds_available_for_closing
    flag CTC_SHORTFALL

Prepaid Interest Computation


daily_rate = adjusted_rate / 365
prepaid_interest = daily_rate × base_loan_amount × days_to_close
  (use 15 days as default estimate for Gear 1)

NOTE: Use unrounded daily_rate and base_loan_amount.
      Round prepaid_interest to 2 decimal places at output.

STAGE 16 — FINAL QUALIFICATION DETERMINATION


qualification_status:

  QUALIFIED_DU_APPROVE:
    All gates passed AND aus_path = DU_APPROVE_ELIGIBLE

  QUALIFIED_MANUAL_UW:
    All gates passed AND aus_path = DU_REFER_MANUAL_ELIGIBLE
    Requires compensating factors documentation

  CONDITIONAL:
    All gates passed AND one or more of:
    - SE_INCOME_CONDITIONAL
    - VARIABLE_INCOME_CONDITIONAL
    - LPA_PATH_AVAILABLE (DU Refer, LPA may approve)

  INELIGIBLE:
    Any gate failed OR aus_path = DU_REFER_MANUAL_INELIGIBLE

  If QUALIFIED or CONDITIONAL:
    approved_loan_amount = base_loan_amount
    note: "Approved at this loan amount subject to full underwrite and appraisal"

STAGE 17 — EMIT ConventionalQualResult


{
  "schema_version": "clarity_engine_v1.0",
  "skill": "CONVENTIONAL",
  "skill_version": "1.0",
  "deal_id": "string",
  "borrower_id": "string",
  "created_at": "ISO 8601 UTC",

  "qualification_status": "QUALIFIED_DU_APPROVE | QUALIFIED_MANUAL_UW | CONDITIONAL | INELIGIBLE",
  "ineligible_reason": "string | null",
  "aus_path": "DU_APPROVE_ELIGIBLE | DU_REFER | DU_REFER_MANUAL_ELIGIBLE | DU_REFER_MANUAL_INELIGIBLE",

  "loan": {
    "base_loan_amount": 0.00,
    "occupancy_type": "PRIMARY | SECOND_HOME | INVESTMENT",
    "loan_purpose": "PURCHASE | RATE_TERM_REFI | CASH_OUT_REFI",
    "property_value": 0.00,
    "conv_ltv": 0.0000,
    "down_payment_amount": 0.00
  },

  "rate": {
    "base_market_rate": 0.0000,
    "llpa_score_ltv": 0.0000,
    "llpa_occupancy": 0.0000,
    "llpa_purpose": 0.0000,
    "total_llpa": 0.0000,
    "adjusted_rate": 0.0000
  },

  "payment": {
    "pi_payment": 0.00,
    "monthly_tax": 0.00,
    "monthly_insurance": 0.00,
    "hoa_monthly": 0.00,
    "monthly_pmi": 0.00,
    "piti": 0.00,
    "pitia": 0.00
  },

  "pmi": {
    "pmi_required": false,
    "annual_pmi_rate": 0.0000,
    "monthly_pmi": 0.00,
    "pmi_cancel_request_month": null,
    "pmi_auto_cancel_month": null,
    "lifetime_pmi": 0.00
  },

  "dti": {
    "gmi_qualifying": 0.00,
    "front_end_dti": 0.0000,
    "back_end_dti": 0.0000,
    "back_end_dti_with_pmi": 0.0000,
    "dtu_limit": 0.50,
    "manual_limit": 0.45,
    "dti_status": "WITHIN_DU | WITHIN_MANUAL | EXCEEDS_ALL"
  },

  "cash_to_close": {
    "down_payment": 0.00,
    "estimated_closing_costs": 0.00,
    "prepaids_and_escrow": 0.00,
    "seller_concession": 0.00,
    "lender_credit": 0.00,
    "total_cash_to_close": 0.00,
    "funds_available": 0.00,
    "ctc_status": "MEETS_REQUIREMENT | SHORTFALL",
    "ctc_surplus_or_gap": 0.00
  },

  "reserves": {
    "reserve_months_required": 0,
    "pitia_for_reserve": 0.00,
    "required_reserves": 0.00,
    "funds_available_for_reserves": 0.00,
    "reserve_status": "MEETS_REQUIREMENT | SHORTFALL",
    "reserve_surplus_or_gap": 0.00
  },

  "flags": [],
  "constraint_signals": [],
  "human_review_required": false,
  "human_review_reasons": [],

  "lineage_trace": {
    "gate_1_result": "string",
    "gate_2_result": "string",
    "gate_3_result": "string",
    "gate_4_result": "string",
    "llpa_computation": {},
    "dti_computation": {},
    "pmi_computation": {},
    "reserve_computation": {},
    "ctc_computation": {}
  }
}

WORKED EXAMPLES

Example A — Marcus & Diana Webb (PRIMARY, score 698, 3% down, $425,000)

Inputs from BorrowerProfile and ProgramEvaluationQueue:


qualifying_credit_score: 698
credit_tier:             5
occupancy_type:          PRIMARY
loan_purpose:            PURCHASE
purchase_price:          425,000
appraised_value:         425,000 (assume = purchase price)
down_payment_amount:     12,750 (3%)
gmi_for_dti:             8,458.33
total_monthly_dti_obligations: 785.00
monthly_tax:             531.25
monthly_insurance:       100.00
hoa_monthly:             0.00
funds_available_for_closing:  28,105.36
funds_available_for_reserves: 60,894.64

Stage 4 — Gate 4: LTV


property_value = MIN(425,000, 425,000) = 425,000
base_loan_amount = 425,000 - 12,750 = 412,250
conv_ltv = 412,250 / 425,000 = 0.9700 = 97.00%
LTV cap (PRIMARY) = 97.00% → gate_4 = PASS (exactly at limit)

Stage 7 — LLPA Rate


conv_ltv = 97.00% → LTV band: 95.01–97.00%
score = 698 → score band: 680-699

llpa_score_ltv = table[95.01-97.00][680-699] = 1.000%
llpa_occupancy = 0.000% (primary)
llpa_purpose   = 0.000% (purchase)
total_llpa     = 1.000%
adjusted_rate  = 6.50% + 1.00% = 7.50%

Stage 8 — P&I Payment


monthly_rate = 0.075 / 12 = 0.0062500
compound     = (1.0062500)^360 = 9.42153
numerator    = 0.0062500 × 9.42153 = 0.058885
denominator  = 9.42153 - 1 = 8.42153
pmt_factor   = 0.058885 / 8.42153 = 0.0069921
pi_payment   = 412,250 × 0.0069921 = 2,882.51

Stage 12 — PMI


conv_ltv = 97.00% > 80% → PMI required
ltv_band = 90.01–97.00%
pmi_score_band = 680-719 (score 698)

annual_pmi_rate = pmi_table[90.01-97.00][680-719] = 1.00%
monthly_pmi = 412,250 × 0.0100 / 12 = 343.54

PMI cancellation loop (rate 7.50%, loan 412,250, property 425,000):
  pmi_cancel_request_target = 425,000 × 0.80 = 340,000
  pmi_auto_cancel_target    = 425,000 × 0.78 = 331,500
  monthly_rate = 0.075 / 12 = 0.0062500
  pmt = 412,250 × 0.0069921 = 2,882.51

  Amortization loop:
    Month 146: balance crosses below 340,000 → pmi_cancel_request_month = 146
    Month 157: balance crosses below 331,500 → pmi_auto_cancel_month = 157
    [verified by Python: cancel_80 = 146, cancel_78 = 157]

lifetime_pmi = 343.54 × 157 = 53,935.78

Stage 13 — PITI / PITIA


piti  = 2,882.51 + 531.25 + 100.00 + 0.00 = 3,513.76
pitia = 3,513.76 + 343.54 = 3,857.30

Stage 10 — DTI


front_end_dti = (pi_payment + tax + ins + HOA) / gmi
              = (2,882.51 + 531.25 + 100 + 0) / 8,458.33
              = 3,513.76 / 8,458.33
              = 0.4154 = 41.54%

back_end_dti_with_pmi = (pitia + obligations) / gmi
  total = 3,857.30 + 785.00 = 4,642.30
  back_end_dti_with_pmi = 4,642.30 / 8,458.33 = 0.5489 = 54.89%

DU limit (50%): 54.89% > 50% → DU REFER
Manual limit (45%): 54.89% > 45% → MANUAL INELIGIBLE

dti_status = EXCEEDS_ALL
aus_path   = DU_REFER_MANUAL_INELIGIBLE
qualification_status = INELIGIBLE_DTI

Stage 15 — Cash to Close


closing_costs_estimate = 412,250 × 0.020 = 8,245.00
daily_rate = 0.075 / 365 = 0.00020548
prepaid_interest = 0.00020548 × 412,250 × 15 = 1,270.63
escrow_setup = (531.25 + 100.00) × 3 = 1,893.75
prepaids = 1,270.63 + 1,893.75 = 3,164.38

cash_to_close = 12,750.00 + 8,245.00 + 3,164.38 - 0 - 0 = 24,159.38
funds_available = 28,105.36
ctc_status = MEETS_REQUIREMENT (surplus $3,946.00)

Stage 16 — Final Result


qualification_status: INELIGIBLE_DTI
reason: Back-end DTI 54.89% exceeds DU 50% limit and manual 45% limit.
Conventional is not viable at this configuration without DTI reduction.

Constraint signals emitted:
  CONV_DTI_BLOCKING — back-end DTI 54.89% (DU 50%, Manual 45%)
  CONV_PMI_COST — $343.54/month, $53,935.78 lifetime, cancels month 157
  CONV_RATE_PENALTY — LLPA 1.00% → 7.50% rate (vs 6.50% base)

Example B — Jennifer Park (PRIMARY, score 755, 10% down, $550,000)

Inputs:


qualifying_credit_score: 755
occupancy_type:          PRIMARY
loan_purpose:            PURCHASE
purchase_price:          550,000
down_payment_amount:     55,000 (10%)
gmi_for_dti:             12,500.00
total_monthly_dti_obligations: 650.00
monthly_tax:             687.50
monthly_insurance:       120.00
hoa_monthly:             0.00
funds_available_for_closing:  80,000.00
funds_available_for_reserves: 50,000.00

Gate 2: loan = 495,000 < 806,500 ✓

Gate 3: score 755 ≥ 620 ✓

Gate 4:


conv_ltv = 495,000 / 550,000 = 0.9000 = 90.00%
LTV cap (PRIMARY) = 97% → PASS (90% ≤ 97%)

Stage 7 — LLPA Rate


conv_ltv = 90.00% → LTV band: 80.01–90.00%
score = 755 → score band: 740-759

llpa_score_ltv = table[80.01-90.00][740-759] = 0.000%
llpa_occupancy = 0.000% (primary)
llpa_purpose   = 0.000% (purchase)
total_llpa     = 0.000%
adjusted_rate  = 6.50% + 0.00% = 6.50%

Stage 8 — P&I


monthly_rate = 0.065 / 12 = 0.0054167
compound     = (1.0054167)^360 = 6.99180
numerator    = 0.0054167 × 6.99180 = 0.037872
denominator  = 6.99180 - 1 = 5.99180
pmt_factor   = 0.037872 / 5.99180 = 0.0063207
pi_payment   = 495,000 × 0.0063207 = 3,128.74

Stage 12 — PMI


conv_ltv = 90.00% → PMI required (> 80%)
ltv_band = 85.01–90.00% (90.00% ≤ 90.00% → use 85.01-90.00 band)

BOUNDARY RULE: LTV exactly 90.00% — use band 85.01-90.00% (≤ 90.00)

pmi_score_band = 740+ (score 755)
annual_pmi_rate = pmi_table[85.01-90.00][740+] = 0.40%
monthly_pmi = 495,000 × 0.0040 / 12 = 165.00

PMI cancellation (rate 6.50%, loan 495,000, property 550,000):
  pmi_cancel_request_target = 550,000 × 0.80 = 440,000
  pmi_auto_cancel_target    = 550,000 × 0.78 = 429,000
  monthly_rate = 0.065 / 12 = 0.0054167
  pmt = 495,000 × 0.0063207 = 3,128.74

  Amortization loop:
    Month 95: balance crosses below 440,000 → pmi_cancel_request_month = 95
    Month 109: balance crosses below 429,000 → pmi_auto_cancel_month = 109
    [verified by Python]

lifetime_pmi = 165.00 × 109 = 17,985.00

Stage 13 — PITI / PITIA


piti  = 3,128.74 + 687.50 + 120.00 + 0.00 = 3,936.24
pitia = 3,936.24 + 165.00 = 4,101.24

Stage 10 — DTI


front_end_dti = 3,936.24 / 12,500.00 = 0.3149 = 31.49%
back_end_dti_with_pmi = (4,101.24 + 650.00) / 12,500.00
                      = 4,751.24 / 12,500.00
                      = 0.3801 = 38.01%

DU limit (50%): 38.01% ≤ 50% → DU APPROVE ELIGIBLE ✓
Manual limit (45%): 38.01% ≤ 45% → MANUAL ELIGIBLE ✓
aus_path = DU_APPROVE_ELIGIBLE

Stage 15 — Cash to Close


closing_costs_estimate = 495,000 × 0.020 = 9,900.00
daily_rate = 0.065 / 365 = 0.00017808
prepaid_interest = 0.00017808 × 495,000 × 15 = 1,322.26
escrow_setup = (687.50 + 120.00) × 3 = 2,422.50
prepaids = 1,322.26 + 2,422.50 = 3,744.76

cash_to_close = 55,000 + 9,900 + 3,744.76 = 68,644.76
funds_available = 80,000.00
ctc_status = MEETS_REQUIREMENT (surplus $11,355.24)

Stage 16 — Final Result


qualification_status: QUALIFIED_DU_APPROVE
approved_loan_amount: 495,000
adjusted_rate: 6.50%
pi_payment: 3,128.74
pitia: 4,101.24
front_end_dti: 31.49%
back_end_dti: 38.01%
monthly_pmi: $165.00 (cancels month 109, lifetime $17,985.00)
cash_to_close: 68,644.76
reserve_status: MEETS_REQUIREMENT

Example C — Investment Property (score 720, 25% down, $380,000)

Inputs:


qualifying_credit_score: 720
occupancy_type:          INVESTMENT
loan_purpose:            PURCHASE
purchase_price:          380,000
down_payment_amount:     95,000 (25%)
gmi_for_dti:             9,000.00
total_monthly_dti_obligations: 500.00
monthly_tax:             475.00
monthly_insurance:       90.00
hoa_monthly:             0.00
rental_income_gross:     2,400.00
funds_available_for_closing:  115,000.00
funds_available_for_reserves: 60,000.00

Gate 4:


conv_ltv = 285,000 / 380,000 = 0.7500 = 75.00%
LTV cap (INVESTMENT) = 80% → PASS (75% ≤ 80%)

Stage 7 — LLPA Rate


conv_ltv = 75.00% → LTV band: ≤ 80.00%
score = 720 → score band: 720-739

llpa_score_ltv  = table[≤80.00][720-739] = 0.000%
llpa_occupancy  = +0.750% (investment, LTV ≤ 75%)
llpa_purpose    = 0.000% (purchase)
total_llpa      = 0.750%
adjusted_rate   = 6.50% + 0.75% = 7.25%

Stage 8 — P&I


monthly_rate = 0.0725 / 12 = 0.0060417
compound     = (1.0060417)^360 = 8.74477
numerator    = 0.0060417 × 8.74477 = 0.052833
denominator  = 8.74477 - 1 = 7.74477
pmt_factor   = 0.052833 / 7.74477 = 0.0068218
pi_payment   = 285,000 × 0.0068218 = 1,944.20

Stage 9 — Rental Income


rental_income_gross = 2,400.00
rental_income_net   = 2,400 × 0.75 = 1,800.00
subject_piti        = 1,944.20 + 475 + 90 + 0 = 2,509.20
net_rental_result   = 1,800.00 - 2,509.20 = -709.20

rental_offset_type = NEGATIVE_CASHFLOW
rental_loss_for_dti = 709.20  (added to monthly obligations)
gmi_adjusted = 9,000.00  (no change)

Stage 12 — PMI


conv_ltv = 75.00% ≤ 80% → PMI NOT required
monthly_pmi = 0.00

Stage 13 — PITI


piti  = 1,944.20 + 475.00 + 90.00 + 0.00 = 2,509.20
pitia = 2,509.20 + 0.00 = 2,509.20  (no PMI)

Stage 10 — DTI


front_end_dti = piti / gmi = 2,509.20 / 9,000.00 = 0.2788 = 27.88%

monthly_obligations_adjusted = 500.00 + 709.20 = 1,209.20
  (rental loss added per Stage 9)

back_end_dti = (piti + monthly_obligations_adjusted) / gmi
             = (2,509.20 + 1,209.20) / 9,000.00
             = 3,718.40 / 9,000.00
             = 0.4132 = 41.32%

DU limit (50%): 41.32% ≤ 50% → DU APPROVE ELIGIBLE ✓
Manual limit (45%): 41.32% ≤ 45% ✓
aus_path = DU_APPROVE_ELIGIBLE

Stage 14 — Reserves


reserve_months (INVESTMENT) = 6
required_reserves = 6 × 2,509.20 = 15,055.20
funds_available_for_reserves = 60,000.00
reserve_status = MEETS_REQUIREMENT (surplus $44,944.80)

Stage 15 — CTC


closing_costs_estimate = 285,000 × 0.020 = 5,700.00
daily_rate = 0.0725 / 365 = 0.00019863
prepaid_interest = 0.00019863 × 285,000 × 15 = 849.14
escrow_setup = (475.00 + 90.00) × 3 = 1,695.00
prepaids = 849.14 + 1,695.00 = 2,544.14
cash_to_close = 95,000 + 5,700 + 2,544.14 = 103,244.14
funds_available = 115,000.00
ctc_status = MEETS_REQUIREMENT (surplus $11,755.86)

Stage 16 — Final Result


qualification_status: QUALIFIED_DU_APPROVE
approved_loan_amount: 285,000
adjusted_rate: 7.25%
pi_payment: 1,944.20
pitia: 2,509.20
front_end_dti: 27.88%
back_end_dti: 41.32% (with rental loss)
monthly_pmi: $0 (not required at 75% LTV)
cash_to_close: 103,244.14
reserve_status: MEETS_REQUIREMENT
flags: [RENTAL_LOSS_ADDED_TO_DTI]

FORBIDDEN PATTERNS


CF-01: Applying FHA MIP to conventional loans
  FHA UFMIP and annual MIP are FHA-specific. PMI is conventional-specific.
  Never use FHA MIP rates, duration rules, or UFMIP in this skill.

CF-02: Using VA residual income for conventional qualification
  VA residual income is a VA-only test. Not applicable here.
  Back-end DTI governs conventional qualification.

CF-03: Rounding intermediate values before final output
  All intermediate values (balance, interest, principal, factors, rates)
  use full floating-point precision throughout computation.
  Round only final presentation outputs (2 decimal places for dollars,
  4 decimal places for rates, 4 for DTI computation, 2 for display).

CF-04: Applying DSCR logic to conventional investment
  DSCR uses property income only and has no borrower DTI.
  Conventional investment uses borrower GMI + rental offset.
  These are fundamentally different qualification methods.

CF-05: Using annual rate directly in amortization loop
  monthly_rate = annual_rate / 12.
  Never use annual_rate in the balance computation loop.

CF-06: Using purchase_price as LTV denominator when appraisal is lower
  property_value = MIN(purchase_price, appraised_value).
  Always apply this comparison before computing LTV.

CF-07: PMI not required check off-by-one
  PMI required when conv_ltv > 0.80 (strictly greater than).
  LTV exactly 80.00% does NOT require PMI.
  Apply as > 0.80, not ≥ 0.80.

CF-08: Gift funds for investment down payment
  Gift funds are NOT eligible for investment property down payment.
  Primary and second home only (Fannie Mae B3-4.3-04).
  Flag GIFT_NOT_ELIGIBLE_INVESTMENT and block if investment + gift.

CF-09: Seller concessions exceeding program limits
  Seller concessions have LTV-based caps. Excess concessions are subtracted
  from purchase price or returned — not applied dollar-for-dollar.
  Flag SELLER_CONCESSION_LIMIT if approaching cap.

COMPANION SKILLS

SkillRelationship
Clarity_Engine_Borrower_Profile_SKILL.mdRequired input — provides BorrowerProfile
Clarity_Engine_Program_Router_SKILL.mdRequired input — provides ProgramEvaluationQueue CONVENTIONAL entry
Clarity_Engine_Math_SKILL.mdReference — PMT factor computation
Clarity_Engine_Constraint_Detection_SKILL.mdReceives ConventionalConstraintFlags
Clarity_Engine_FHA_SKILL.mdSibling skill — runs in parallel for FHA comparison
Clarity_Engine_Optimization_SKILL.mdDownstream — receives ConventionalQualResult as baseline
Clarity_Engine_Audit_Trace_SKILL.mdDownstream — receives ConventionalLineageTrace

Clarity Engine — Conventional Mortgage Skill v1.0 | CONFIDENTIAL — PreFi, Inc. / Purpose Technology, Inc. d/b/a Purlend