← Back to Interaction Rule Set

Clarity Engine — Borrower Profile Skill

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

Table of Contents SKILL PURPOSE INVOCATION EXECUTION SEQUENCE STAGE 1 — INTAKE: COLLECT ALL AVAILABLE DATA STAGE 2 — IDENTITY + FLAGS + CREDIT SCORE NORMALIZATION STAGE 3 — CO-BORROWER COLLECTION STAGE 4 — INCOME NORMALIZATION STAGE 5 — LIABILITY NORMALIZATION STAGE 6 — ASSET NORMALIZATION STAGE 7 — PROPERTY + DEAL NORMALIZATION STAGE 8 — VALIDATION + COMPLETENESS + APPROVAL READINESS SCORE STAGE 9 — OUTPUT: BORROWER PROFILE OBJECT + HANDOFF STATEMENT WORKED EXAMPLE — Full Borrower Run ERROR CODES PROFILE UPDATE PROTOCOL COMPANION SKILLS

Clarity Engine — Borrower Profile Skill

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

Scope: Intake, normalization, and validation of all borrower data into the canonical Borrower Intelligence Ledger schema. The front door of the Clarity Engine. Every other skill receives its input from this skill's output.

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

SKILL PURPOSE

When invoked, this skill:

  1. Accepts raw borrower data in any format (conversational, structured, partial)
  2. Normalizes all fields to the canonical Clarity Engine schema
  3. Validates completeness against MVP required fields
  4. Derives calculated metrics (GMI, total liabilities, liquid assets, approval readiness, preliminary DTI)
  5. Flags missing data, documentation gaps, and routing signals
  6. Outputs a complete, validated BorrowerProfile object ready for handoff to the Program Router Skill

This skill does NOT underwrite. It does NOT determine eligibility. It does NOT generate scenarios.

It produces one thing: a clean, complete, validated profile object that every downstream skill can trust.

INVOCATION

Invoke this skill when:

Trigger phrases:

EXECUTION SEQUENCE

Run all 9 stages in order. Do not skip stages. Do not pass to downstream skills until Stage 7 clears all blocking fields and handoff_ready = true.


Stage 1 — Intake: accept and extract all raw input
Stage 2 — Identity + Flags + Credit Score normalization
Stage 3 — Co-Borrower collection (if present)
Stage 4 — Income normalization
Stage 5 — Liability normalization
Stage 6 — Asset normalization
Stage 7 — Property + Deal normalization
Stage 8 — Validation + Completeness + Approval Readiness Score
Stage 9 — Output: BorrowerProfile object + Handoff Statement

STAGE 1 — INTAKE: COLLECT ALL AVAILABLE DATA

Accept whatever the user provides. Do not require a specific format. Extract every piece of mortgage-relevant information from the input and map it to one of these entity categories:


ENTITY CATEGORIES:
  1. Borrower Identity + Flags + Credit
  2. Co-Borrower (if present)
  3. Income Sources (one record per stream)
  4. Liabilities (one record per debt)
  5. Assets (one record per account)
  6. Property
  7. Deal Intent
  8. Goal Weights (borrower priorities)

Conversational Extraction Examples

Raw InputExtracted Field(s)Extracted Value
"I make $120K a year"income_type=BASE_SALARY, gross_monthly_amount10,000.00
"I get $1,200/month in disability — it's non-taxable"income_type=DISABILITY, gross_monthly_amount, taxable=false1,200.00
"I have a $350 car payment, 26 months left"liability_type=AUTO, monthly_payment=350, months_remaining=26include_in_dti=true
"I'm a veteran"veteran_flagtrue
"I want to keep my payment under $3,000"target_monthly_payment3,000.00
"I have about $45K in checking and $120K in my 401K"asset[CHECKING]=45,000 / asset[RETIREMENT_401K]=120,000
"I owe $28K across three credit cards"3× liability_type=CREDIT_CARD — prompt for individual balances
"My credit score is 718"credit_score718
"My wife will be on the loan too"co_borrower_present=true — trigger Stage 3
"I've been self-employed for 3 years"self_employed_flag=true, history_months=36

After extraction, present a structured summary to the user for confirmation before proceeding to Stage 2.

STAGE 2 — IDENTITY + FLAGS + CREDIT SCORE NORMALIZATION

Map to the Borrower entity. Mark each field: PRESENT | MISSING | INFERRED | ESTIMATED.

Required Fields


borrower_id                 auto-generate: BORR_[YYYYMMDD_HHMMSS]
first_name                  string
last_name                   string
ssn_hash                    hash on intake — NEVER store plaintext SSN
credit_score                integer — see collection protocol below
veteran_flag                boolean — ask directly if not stated
first_time_homebuyer_flag   boolean — ask if not stated
self_employed_flag          boolean — ask if not stated
primary_residence_intent    boolean — derive from deal intent
goal_priority_payment       integer 1–5
goal_priority_cash          integer 1–5
goal_priority_purchase_power integer 1–5
goal_priority_speed         integer 1–5
goal_priority_wealth        integer 1–5

Optional Fields


date_of_birth               date — required for age-sensitive programs
citizenship_status          US_CITIZEN | PERM_RESIDENT | NON_PERM_RESIDENT
marital_status              MARRIED | SINGLE | SEPARATED | DIVORCED
household_size              integer — required for USDA and some DPA income limits
disability_flag             boolean — VA funding fee waiver trigger
target_monthly_payment      decimal
target_cash_to_close        decimal
co_borrower_present         boolean — if true, execute Stage 3

Credit Score Collection Protocol

Ask for credit score if not provided. If the borrower has not pulled credit:

"Do you know your approximate credit score? If not, I can proceed with an estimate, but actual score is needed before any program eligibility can be confirmed."

If score is unknown, set credit_score = null and flag CREDIT_SCORE_MISSING. This is non-blocking — the Program Router will handle it.

If provided, apply the Credit Tier assignment immediately:

Credit Score Tier Table

FICO RangeTierRate Adjustment vs ParPMI TierEngine Routing Action
760+1Par (best pricing)Tier 1 (lowest PMI)No credit optimization needed. Focus other dimensions.
740–7592+0.125% to +0.250%Tier 2Calculate cost of reaching 760. Model savings. Flag ROUTE_CREDIT_TIER_UPGRADE.
720–7393+0.250% to +0.500%Tier 3Credit optimization high ROI. Flag ROUTE_CREDIT_OPTIMIZATION.
700–7194+0.500% to +0.750%Tier 4FHA may be competitive. Model both. Flag ROUTE_CREDIT_OPTIMIZATION.
680–6995+0.750% to +1.000%Tier 5FHA often wins on total cost. Rapid Rescore high priority. Flag ROUTE_FHA_COMPETITIVE.
640–6796+1.000%+Tier 6 (high PMI)FHA primary. VA if eligible. Utilization paydown fastest path up. Flag ROUTE_FHA_PRIMARY.
580–6397Floor onlyN/A conventionalFHA 3.5% or VA only. Priority: get to 640 for better access. Flag ROUTE_FHA_PRIMARY + ROUTE_CREDIT_RECOVERY.
< 5808No standard programN/ANon-QM or portfolio only. Action plan required. Flag ROUTE_CREDIT_RECOVERY + ROUTE_NON_QM.

Assign credit_tier from this table and include in output. The tier is used by the Ranking Skill's rate adjustment logic.

Goal Priority Collection Protocol

If the borrower has not stated priorities, ask:

"On a scale of 1 to 5, how important is each of the following — 1 being least important, 5 being most:

— Keeping your monthly payment as low as possible

— Minimizing cash needed at closing

— Maximizing the price you can qualify for

— Closing as quickly as possible

— Building long-term wealth (minimizing total interest paid)"

Map responses to goal_priority_[dimension] fields directly.

If borrower declines to prioritize: default all five weights to 3. Set flag GOAL_WEIGHTS_DEFAULT.

STAGE 3 — CO-BORROWER COLLECTION

Execute this stage only if co_borrower_present = true. Otherwise skip to Stage 4.

Collect a full parallel Borrower entity for the co-borrower. All fields mirror Stage 2 with the following differences:


co_borrower_id              auto-generate: COBR_[YYYYMMDD_HHMMSS]
relationship                SPOUSE | PARTNER | FAMILY | OTHER
income_combined_flag        boolean — true if incomes will be combined for qualification
liabilities_combined_flag   boolean — true if co-borrower debts will be included in DTI

Co-Borrower Credit Score Rule

When both borrower and co-borrower have credit scores, the qualifying credit score for program eligibility is:


qualifying_credit_score = LOWER of the two MIDDLE scores across both borrowers

Example:
  Borrower scores from 3 bureaus:  720 / 715 / 708  →  middle = 715
  Co-borrower scores:              680 / 672 / 665  →  middle = 672
  qualifying_credit_score = MIN(715, 672) = 672

Set qualifying_credit_score on the Deal entity. This is the score used for all program eligibility checks — not the primary borrower's score.

Co-Borrower Income Stacking


gmi_coborrower = SUM(qualifying_monthly_amount) across all co-borrower IncomeSource records
gmi_combined   = gmi_total + gmi_coborrower   (if income_combined_flag = true)

If income_combined_flag = false: do not add co-borrower income to DTI numerator, but still include co-borrower liabilities if liabilities_combined_flag = true.

STAGE 4 — INCOME NORMALIZATION

Create one IncomeSource record per income stream per borrower. A borrower with salary + bonus + rental = 3 records.

Required Fields Per Stream


income_id                   auto-generate: INC_[n]
borrower_id                 FK — BORR_ or COBR_ as applicable
income_type                 enum — see table below
gross_monthly_amount        decimal — raw amount before any qualifying treatment
qualifying_monthly_amount   decimal — after treatment rules applied (calculated in this stage)
income_frequency            MONTHLY | BIWEEKLY | WEEKLY | ANNUAL

Optional Fields Per Stream


history_months              required for BONUS, COMMISSION, OVERTIME, SELF_EMPLOYMENT
continuance_likely_flag     required for pension, alimony, disability
documentation_status        STATED | PARTIAL | VERIFIED
add_back_amount             SELF_EMPLOYMENT only
gross_up_applied_flag       boolean — set true when 1.25× applied
averaging_method            CURRENT_ONLY | TWO_YR_AVG | LOWER_OF_TWO_YEARS
taxable_flag                boolean — false triggers gross-up eligibility check

Income Frequency Conversion

Before applying qualifying treatment, normalize all income to monthly:


ANNUAL:    gross_monthly_amount = stated_annual / 12
BIWEEKLY:  gross_monthly_amount = stated_biweekly × 26 / 12
WEEKLY:    gross_monthly_amount = stated_weekly × 52 / 12
MONTHLY:   gross_monthly_amount = as stated

Income Type Qualifying Treatment Table

Income TypeQualifying TreatmentHistory RequiredAveraging MethodKey Rules
BASE_SALARYannual ÷ 12NoneCURRENT_ONLYVerify with paystub + W-2
BONUS24-month average24 monthsTWO_YR_AVGIf YoY declining: use LOWER_OF_TWO_YEARS
COMMISSION24-month average24 monthsTWO_YR_AVGIf < 24mo: flag CONDITIONAL, use available history
OVERTIME24-month average24 monthsTWO_YR_AVGIf YoY declining: use LOWER_OF_TWO_YEARS
SELF_EMPLOYMENTnet profit + Schedule C add-backs, 24-month average24 monthsTWO_YR_AVGIf declining > 10% YoY: use lower year. If < 24mo: CONDITIONAL
RENTALgross_rent × 0.7512 monthsCURRENT_ONLYRequires executed lease or appraiser market rent. Apply 75% vacancy factor.
SOCIAL_SECURITYgross_monthly × 1.25 if non-taxableNoneCURRENT_ONLYSet gross_up_applied_flag=true. See VA Gross-Up Guard below.
PENSIONas receivedNoneCURRENT_ONLYVerify continuance. Set continuance_likely_flag.
DISABILITYgross_monthly × 1.25 if non-taxableNoneCURRENT_ONLYSet gross_up_applied_flag=true. See VA Gross-Up Guard below.
ALIMONY (receiving)as received if ≥ 3 years continuance remaining6 monthsCURRENT_ONLYRequire court order
BOARDERup to $200/mo12 monthsCURRENT_ONLYFHA only. Set flag NOT_ELIGIBLE_CONVENTIONAL
OTHERcase by caseper typeper typeFlag for advisor review

Gross-Up Calculation

When taxable_flag = false for SOCIAL_SECURITY or DISABILITY:


qualifying_monthly_amount = gross_monthly_amount × 1.25
gross_up_applied_flag = true
gross_up_amount = gross_monthly_amount × 0.25

Example:
  SS income = $1,200/month (non-taxable)
  qualifying_monthly_amount = 1,200 × 1.25 = 1,500
  gross_up_amount = 1,200 × 0.25 = 300

VA Gross-Up Guard — Critical Dual-Path Rule

When any VA loan scenario is in scope (veteran_flag = true), income must be stored on two separate paths. These values will differ whenever gross-up income is present. Failure to separate them is the most dangerous income calculation error in the system.


PATH 1 — DTI (uses grossed-up income):
  gmi_for_dti = SUM(qualifying_monthly_amount) for all streams
              = includes 1.25× gross-up on non-taxable streams

PATH 2 — VA Residual Income (uses NET received income, NO gross-up):
  net_income_for_va_residual = SUM(gross_monthly_amount) for all streams
                             = 1.00× — never multiply non-taxable streams

VALIDATION RULE:
  IF any stream has gross_up_applied_flag = true:
    ASSERT gmi_for_dti ≠ net_income_for_va_residual
    IF equal → flag INCOME_SPLIT_ERROR — block handoff

GMI Derivation


qualifying_monthly_amount per stream  = result of qualifying treatment above
gmi_total                             = SUM(qualifying_monthly_amount) — primary borrower all streams
gmi_coborrower                        = SUM(qualifying_monthly_amount) — co-borrower all streams
gmi_combined                          = gmi_total + gmi_coborrower (if income_combined_flag = true)
gmi_for_dti                           = gmi_combined (or gmi_total if no co-borrower)
net_income_for_va_residual            = SUM(gross_monthly_amount) — no gross-up, both borrowers

STAGE 5 — LIABILITY NORMALIZATION

Create one Liability record per debt obligation. Include all debts from credit report and all debts stated by borrower. If credit report shows a debt the borrower did not mention, include it and flag UNDISCLOSED_LIABILITY.

Required Fields Per Liability


liability_id                auto-generate: LIAB_[n]
borrower_id                 FK — BORR_ or COBR_ as applicable
liability_type              enum — CREDIT_CARD | AUTO | STUDENT_LOAN | PERSONAL_LOAN |
                                   MORTGAGE | INSTALLMENT | HELOC | CHILD_SUPPORT |
                                   ALIMONY_PAYING | BUSINESS_DEBT
balance                     decimal
monthly_payment             decimal — minimum payment for revolving; actual for installment
secured_flag                boolean
eligible_for_payoff_flag    boolean — can the engine propose payoff as an optimization move?
include_in_dti_flag         boolean — apply rules below

Optional Fields Per Liability


creditor_name               string
interest_rate               decimal APR — needed for consolidation ranking
credit_limit                decimal — required for all revolving accounts (utilization calc)
months_remaining            integer — required for installment exclusion eligibility check
cosigned_flag               boolean
business_debt_flag          boolean
student_loan_repayment_type STANDARD | DEFERRED | IDR | GRADUATED

DTI Inclusion Rules

Apply in order. First matching rule wins.

PriorityConditioninclude_in_dti_flagRequired Documentation
1GMI = 0 after income processingBLOCK — ERR-PROFILE-001N/A
2Installment loan, months_remaining ≤ 10FALSEDocument months_remaining
3Co-signed, 12+ months third-party payment historyFALSEBank statements proving third party pays
4Business debt, documented on business returnFALSECPA letter
5HELOC with $0 drawn balanceFALSE for conventional; TRUE for FHA/VANote: program-specific. Default FALSE unless FHA/VA in scope
6Child support / alimony payingTRUEAlways include — no exclusion
7Student loan, deferred or $0 paymentTRUEUse 0.5% of balance as dti_monthly_payment
8Student loan, income-driven repaymentTRUEdti_monthly_payment = MAX(actual_payment, balance × 0.005)
9All other standard debtsTRUEDefault

Student Loan DTI Payment Calculation


IF liability_type = STUDENT_LOAN:

  IF student_loan_repayment_type = DEFERRED OR monthly_payment = 0:
    dti_monthly_payment = balance × 0.005
    averaging_note = "Deferred — using 0.5% of balance per Fannie Mae B3-6-05"

  ELIF student_loan_repayment_type = IDR:
    dti_monthly_payment = MAX(monthly_payment, balance × 0.005)
    averaging_note = "IDR — using greater of actual payment or 0.5% of balance"

  ELSE:
    dti_monthly_payment = monthly_payment

Example:
  Student loan balance = $45,000, deferred
  dti_monthly_payment = 45,000 × 0.005 = 225.00/month

Derived Liability Metrics


total_monthly_dti_obligations  = SUM(dti_monthly_payment WHERE include_in_dti_flag = true)
total_revolving_balance        = SUM(balance WHERE liability_type IN [CREDIT_CARD, HELOC])
total_revolving_credit_limit   = SUM(credit_limit WHERE liability_type IN [CREDIT_CARD, HELOC])
total_revolving_utilization    = total_revolving_balance / total_revolving_credit_limit
                                 (return 0 if total_revolving_credit_limit = 0)
high_interest_debt_total       = SUM(balance WHERE interest_rate >= 15.0%)
months_to_exclusion_list       = [liability_id, creditor, months_remaining, monthly_payment]
                                  WHERE months_remaining <= 10 AND include_in_dti_flag = true
                                 (these are debt-timing optimization opportunities)

STAGE 6 — ASSET NORMALIZATION

Create one Asset record per account.

Required Fields Per Asset


asset_id                    auto-generate: AST_[n]
borrower_id                 FK
asset_type                  enum — CHECKING | SAVINGS | BROKERAGE | RETIREMENT_401K |
                                   RETIREMENT_IRA | CRYPTO | GIFT | REAL_ESTATE_EQUITY |
                                   BUSINESS | OTHER
balance                     decimal — current balance
liquid_flag                 boolean
eligible_for_closing_flag   boolean
eligible_for_reserves_flag  boolean
haircut_pct                 decimal — see table below

Optional Fields Per Asset


vested_pct                  decimal — retirement accounts (default 1.00 if not stated)
source_verified_flag        boolean — 60-day statement required
seasoning_days              integer — days funds have been in account
gift_letter_received_flag   boolean — required for GIFT type

Asset Classification and Haircut Table

Asset Typeliquid_flageligible_for_closingeligible_for_reserveshaircut_pctNotes
CHECKINGtruetruetrue0.00Full value
SAVINGStruetruetrue0.00Full value
BROKERAGEtruetruetrue0.3030% haircut per Fannie Mae B3-4.3-09 — use 70% of documented value
RETIREMENT_401Kfalsefalsetrue0.4060% of vested balance for reserves only — never for closing
RETIREMENT_IRAfalsefalsetrue0.40Same as 401K
CRYPTOfalsefalsefalse1.00Must liquidate AND season 60 days post-liquidation — $0 eligible until then
GIFTtruetruefalse0.00Requires gift letter. Not eligible for reserves.
REAL_ESTATE_EQUITYfalsefalsefalsevariesOnly eligible if cash-out refi proceeds — deal-specific
BUSINESSfalsefalsefalsevariesRequires CPA letter. Rarely eligible. Flag for advisor.

Reserve Hold Calculation

The engine must reserve a minimum post-close cushion before allocating assets to closing. This prevents the common error of counting all assets as available for closing when part must remain post-close.


reserve_months_required     = program.reserve_requirement_months (default 2 if unknown)
estimated_piti_for_reserve  = monthly_piti_estimate from Stage 7 (calculated after property/deal)
required_reserves_hold      = reserve_months_required × estimated_piti_for_reserve

funds_available_for_closing = net_eligible_assets - required_reserves_hold
                              (floor at 0 — cannot be negative)

NOTE: required_reserves_hold is recalculated per scenario in downstream skills.
      Use 2-month hold as conservative default at profile stage.

Derived Asset Metrics


net_eligible_assets          = SUM(balance × (1 - haircut_pct)) WHERE eligible_for_closing_flag = true
retirement_reserve_credit    = SUM(balance × vested_pct × 0.60) WHERE asset_type IN [RETIREMENT_401K, RETIREMENT_IRA]
funds_available_for_closing  = net_eligible_assets - required_reserves_hold  (floor at 0)
funds_available_for_reserves = net_eligible_assets - funds_available_for_closing + retirement_reserve_credit
total_asset_strength         = funds_available_for_closing + funds_available_for_reserves

STAGE 7 — PROPERTY + DEAL NORMALIZATION

Property Entity — Required Fields


property_id                 auto-generate: PROP_[YYYYMMDD_HHMMSS]
address                     string — full street address
city                        string
state                       string — two-letter USPS code
zip_code                    string
property_type               SFR | CONDO | TOWNHOME | 2_UNIT | 3_UNIT | 4_UNIT | PUD | MANUFACTURED
occupancy_type              PRIMARY | SECOND_HOME | INVESTMENT
unit_count                  integer 1–4

Property Entity — Optional Fields


county                      string — derive from zip if not provided
purchase_price              decimal — required for PURCHASE deals
estimated_value             decimal — required for REFI deals
annual_property_tax         decimal — if not provided, estimate below
annual_insurance            decimal — if not provided, estimate below
hoa_monthly                 decimal — 0 if none
flood_zone_flag             boolean — default false; set true if known
appraisal_status            ESTIMATED | ORDERED | COMPLETED | WAIVED
condo_project_status        NOT_APPLICABLE | APPROVED | PENDING_REVIEW | NON_WARRANTABLE

Property Tax and Insurance Estimation

Apply when borrower cannot provide actual amounts. Flag all estimates.


IF annual_property_tax not provided:
  annual_property_tax_estimate = purchase_price × 0.0125
  monthly_tax = annual_property_tax_estimate / 12
  flag: TAX_ESTIMATED

IF annual_insurance not provided:
  annual_insurance_estimate = purchase_price × 0.005
  monthly_insurance = annual_insurance_estimate / 12
  flag: INSURANCE_ESTIMATED

Deal Entity — Required Fields


deal_id                     auto-generate: DEAL_[YYYYMMDD_HHMMSS]
deal_type                   PURCHASE | RATE_REFI | CASH_OUT_REFI | DEBT_CONSOLIDATION_REFI | TERM_REFI
borrower_id                 FK
property_id                 FK
intent_type                 PURCHASE | REFINANCE | EQUITY_ACCESS | UNCERTAINTY
deal_state                  ACTIVE (on creation)
qualifying_credit_score     from Stage 2 (or Stage 3 if co-borrower present)
created_at                  ISO 8601 UTC
last_updated_at             ISO 8601 UTC

Deal Entity — Conditional Fields (required by deal type)


PURCHASE deals:
  down_payment_amount         decimal — required
  requested_loan_amount       decimal — if null: loan = purchase_price - down_payment
  estimated_closing_costs     decimal — if null: estimate = requested_loan_amount × 0.03
  seller_concession_amount    decimal — default 0

REFI deals:
  current_mortgage_balance    decimal — required
  current_rate                decimal — required
  current_payment_pi          decimal — required for savings calculation
  remaining_term_months       integer — required
  estimated_closing_costs     decimal — if null: estimate = current_mortgage_balance × 0.03

CASH-OUT REFI deals:
  desired_cash_out_amount     decimal — required
  (inherits all REFI fields above)

Derived Deal Metrics (preliminary — recalculated per scenario in downstream skills)


IF PURCHASE:
  requested_loan_amount       = purchase_price - down_payment_amount
  ltv_estimate                = requested_loan_amount / purchase_price
  cash_to_close_estimate      = down_payment_amount + estimated_closing_costs - seller_concession_amount

IF REFI:
  ltv_estimate                = current_mortgage_balance / estimated_value
  cash_to_close_estimate      = estimated_closing_costs  (no down payment on refi)

IF CASH_OUT_REFI:
  requested_loan_amount       = current_mortgage_balance + desired_cash_out_amount + estimated_closing_costs
  ltv_estimate                = requested_loan_amount / estimated_value

monthly_piti_estimate         = rough P&I at 7.00% / 30yr on requested_loan_amount
                                + monthly_tax + monthly_insurance + hoa_monthly
                                (7.00% is a neutral placeholder — actual rate computed per scenario)

NOTE on monthly_piti_estimate:
  P&I at 7.00% = requested_loan_amount × (0.07/12 × (1+0.07/12)^360) / ((1+0.07/12)^360 - 1)
               = requested_loan_amount × 0.006653

  Example: loan = $400,000
  P&I = 400,000 × 0.006653 = 2,661.20
  If tax=$800, ins=$200, hoa=$0: monthly_piti_estimate = 3,661.20

STAGE 8 — VALIDATION + COMPLETENESS + APPROVAL READINESS SCORE

8A — Blocking Field Audit

The following fields are BLOCKING — if any are missing, set handoff_ready = false and request them before proceeding.

Blocking FieldEntityReason
income_type + qualifying_monthly_amount (≥1 stream)IncomeSourceCannot compute GMI or DTI
credit_score (or qualifying_credit_score)Borrower / DealCannot run eligibility on any program
property_typePropertyCannot determine eligible programs
occupancy_typePropertyCannot determine eligible programs
deal_typeDealCannot route to correct processing path
veteran_flagBorrowerCannot determine VA eligibility
purchase_price (PURCHASE) OR estimated_value (REFI)PropertyCannot compute LTV
down_payment_amount (PURCHASE only)DealCannot compute LTV or cash to close

8B — Soft Missing Fields (Non-Blocking — flag and continue)


INCOME_HISTORY_SHORT          variable income with < 24 months history
SELF_EMPLOYED_SHORT_HISTORY   self-employed < 24 months
INCOME_SPLIT_ERROR            gmi_for_dti = net_income_for_va_residual when gross-up present — BLOCK
ASSETS_UNVERIFIED             no source_verified_flag = true on any asset
TAX_ESTIMATED                 property tax was estimated at 1.25%
INSURANCE_ESTIMATED           insurance was estimated at 0.5%
CLOSING_COSTS_ESTIMATED       closing costs estimated at 3%
CO_BORROWER_NOT_EVALUATED     co_borrower_present not asked or not confirmed
GOAL_WEIGHTS_DEFAULT          borrower declined to state priorities
CREDIT_SCORE_MISSING          credit_score = null — non-blocking but limits routing
UNDISCLOSED_LIABILITY         debt on credit report not mentioned by borrower

8C — Routing Flags (passed to Program Router)


ROUTE_CHECK_VA                veteran_flag = true
ROUTE_CHECK_DPA               first_time_homebuyer_flag = true
ROUTE_INCOME_COMPLEXITY       self_employed_flag = true OR multiple variable income streams
ROUTE_CREDIT_RECOVERY         credit_score < 580
ROUTE_FHA_PRIMARY             credit_score 580–639 OR (credit_score 640–679 AND ltv > 0.80)
ROUTE_FHA_COMPETITIVE         credit_score 680–699
ROUTE_CREDIT_OPTIMIZATION     credit_score 700–759 OR total_revolving_utilization > 0.30
ROUTE_CREDIT_TIER_UPGRADE     credit_score 740–759 (one tier from par pricing)
ROUTE_DOWN_PAYMENT_CONSTRAINT ltv_estimate > 0.97
ROUTE_DEBT_TIMING_OPPORTUNITY months_to_exclusion_list is non-empty
ROUTE_HIGH_DTI                preliminary_dti_signal = ELEVATED or CONCERN
ROUTE_CTC_SHORTFALL           funds_available_for_closing < cash_to_close_estimate

8D — Preliminary DTI Preview

Signal only — not a qualifying DTI. Actual DTI computed per program and rate by family skills.


preliminary_dti = (monthly_piti_estimate + total_monthly_dti_obligations) / gmi_for_dti

Signals:
  CLEAR    < 36%     All standard programs viable
  WATCH    36%–45%   Most programs viable; review carefully
  ELEVATED 45%–50%   Limited programs; optimization likely needed
  CONCERN  > 50%     Significant constraint; action plan likely required

Example:
  monthly_piti_estimate = 3,200
  total_monthly_dti_obligations = 750
  gmi_for_dti = 9,500
  preliminary_dti = (3,200 + 750) / 9,500 = 3,950 / 9,500 = 41.6% → WATCH

8E — Approval Readiness Score

A single 0.0–1.0 composite signal summarizing the borrower's current qualification strength. Used for session prioritization and Nova framing. Computed from four components, each scored 0.0–1.0, then weighted.


COMPONENT 1 — Credit Score Margin (weight: 0.30)
  credit_margin_score = MIN(1.0, MAX(0.0, (credit_score - 580) / (760 - 580)))
  Anchors: 580 = 0.0 (floor), 760 = 1.0 (ceiling), linear between

  Example: credit_score = 718
  credit_margin_score = (718 - 580) / (760 - 580) = 138 / 180 = 0.767

COMPONENT 2 — DTI Margin (weight: 0.30)
  dti_margin = 0.45 - preliminary_dti   (positive = room remaining; negative = over limit)
  dti_margin_score = MIN(1.0, MAX(0.0, (dti_margin + 0.09) / 0.18))
  Anchors: -0.09 (9% over limit) = 0.0, +0.09 (9% under limit) = 1.0, linear between

  Example: preliminary_dti = 0.416
  dti_margin = 0.45 - 0.416 = 0.034
  dti_margin_score = (0.034 + 0.09) / 0.18 = 0.124 / 0.18 = 0.689

COMPONENT 3 — Reserve Depth (weight: 0.20)
  reserves_months = funds_available_for_reserves / monthly_piti_estimate
  reserve_score = MIN(1.0, MAX(0.0, reserves_months / 6))
  Anchors: 0 months = 0.0, 6+ months = 1.0, linear between

  Example: funds_available_for_reserves = $28,000, monthly_piti = $3,200
  reserves_months = 28,000 / 3,200 = 8.75 months
  reserve_score = MIN(1.0, 8.75 / 6) = MIN(1.0, 1.458) = 1.0

COMPONENT 4 — Documentation Completeness (weight: 0.20)
  blocking_flags_present = count of BLOCKING fields still missing (0 at handoff)
  soft_flags_present = count of soft_missing_fields
  doc_score = MAX(0.0, 1.0 - (soft_flags_present × 0.10))
  Cap deduction at 1.0 (floor at 0.0)

  Example: 2 soft flags (ASSETS_UNVERIFIED, TAX_ESTIMATED)
  doc_score = MAX(0.0, 1.0 - (2 × 0.10)) = 0.80

FINAL SCORE:
  approval_readiness_score = (credit_margin_score × 0.30)
                           + (dti_margin_score × 0.30)
                           + (reserve_score × 0.20)
                           + (doc_score × 0.20)

  Example (continuing above):
  = (0.767 × 0.30) + (0.689 × 0.30) + (1.0 × 0.20) + (0.80 × 0.20)
  = 0.230 + 0.207 + 0.200 + 0.160
  = 0.797

SIGNAL BANDS:
  0.85–1.00  STRONG     High confidence. Proceed to scenario generation.
  0.70–0.84  MODERATE   Viable with current profile. Some optimization available.
  0.50–0.69  DEVELOPING Constraints present. Optimization moves likely needed.
  0.00–0.49  ACTION     Significant gap. Constraint detection priority before routing.

8F — Profile Completeness Score


completeness_score = count(PRESENT + ESTIMATED + INFERRED fields) / count(total required fields)

Example: 47 of 52 required fields present/estimated → completeness_score = 0.904

STAGE 9 — OUTPUT: BORROWER PROFILE OBJECT + HANDOFF STATEMENT

9A — Full BorrowerProfile JSON Schema


{
  "schema_version": "clarity_engine_v1.1",
  "profile_created_at": "2026-03-08T09:00:00Z",
  "last_updated_at": "2026-03-08T09:00:00Z",
  "completeness_score": 0.904,
  "handoff_ready": true,

  "validation": {
    "blocking_missing_fields": [],
    "soft_missing_fields": ["ASSETS_UNVERIFIED", "TAX_ESTIMATED"],
    "documentation_flags": ["TAX_ESTIMATED", "INSURANCE_ESTIMATED"],
    "income_split_error": false
  },

  "routing": {
    "routing_flags": ["ROUTE_CHECK_VA", "ROUTE_CHECK_DPA", "ROUTE_CREDIT_OPTIMIZATION"],
    "preliminary_dti_value": 0.416,
    "preliminary_dti_signal": "WATCH",
    "approval_readiness_score": 0.797,
    "approval_readiness_signal": "MODERATE"
  },

  "borrower": {
    "borrower_id": "BORR_20260308_090000",
    "first_name": "string",
    "last_name": "string",
    "ssn_hash": "string — hashed only",
    "credit_score": 718,
    "credit_tier": 4,
    "veteran_flag": true,
    "disability_flag": false,
    "first_time_homebuyer_flag": true,
    "self_employed_flag": false,
    "primary_residence_intent": true,
    "household_size": 3,
    "citizenship_status": "US_CITIZEN",
    "marital_status": "MARRIED",
    "date_of_birth": "YYYY-MM-DD",
    "target_monthly_payment": 3000.00,
    "target_cash_to_close": 15000.00,
    "goal_weights": {
      "payment": 5,
      "cash": 4,
      "purchase_power": 5,
      "speed": 3,
      "wealth": 4
    }
  },

  "co_borrower": {
    "co_borrower_id": "COBR_20260308_090000",
    "first_name": "string",
    "last_name": "string",
    "credit_score": 0,
    "income_combined_flag": true,
    "liabilities_combined_flag": true,
    "relationship": "SPOUSE | PARTNER | FAMILY | OTHER"
  },

  "income": {
    "sources": [
      {
        "income_id": "INC_1",
        "borrower_id": "BORR_20260308_090000",
        "income_type": "BASE_SALARY",
        "gross_monthly_amount": 0.00,
        "qualifying_monthly_amount": 0.00,
        "income_frequency": "MONTHLY | BIWEEKLY | WEEKLY | ANNUAL",
        "history_months": 0,
        "documentation_status": "STATED | PARTIAL | VERIFIED",
        "gross_up_applied_flag": false,
        "gross_up_amount": 0.00,
        "taxable_flag": true,
        "averaging_method": "CURRENT_ONLY | TWO_YR_AVG | LOWER_OF_TWO_YEARS",
        "continuance_likely_flag": true,
        "add_back_amount": 0.00
      }
    ],
    "gmi_total": 0.00,
    "gmi_coborrower": 0.00,
    "gmi_combined": 0.00,
    "gmi_for_dti": 0.00,
    "net_income_for_va_residual": 0.00,
    "gross_up_streams": []
  },

  "liabilities": {
    "accounts": [
      {
        "liability_id": "LIAB_1",
        "borrower_id": "BORR_20260308_090000",
        "liability_type": "CREDIT_CARD | AUTO | STUDENT_LOAN | ...",
        "creditor_name": "string",
        "balance": 0.00,
        "monthly_payment": 0.00,
        "dti_monthly_payment": 0.00,
        "interest_rate": 0.00,
        "credit_limit": 0.00,
        "months_remaining": 0,
        "secured_flag": false,
        "include_in_dti_flag": true,
        "eligible_for_payoff_flag": true,
        "cosigned_flag": false,
        "business_debt_flag": false,
        "student_loan_repayment_type": "STANDARD | DEFERRED | IDR | GRADUATED"
      }
    ],
    "total_monthly_dti_obligations": 0.00,
    "total_revolving_balance": 0.00,
    "total_revolving_credit_limit": 0.00,
    "total_revolving_utilization": 0.00,
    "high_interest_debt_total": 0.00,
    "months_to_exclusion_list": []
  },

  "assets": {
    "accounts": [
      {
        "asset_id": "AST_1",
        "borrower_id": "BORR_20260308_090000",
        "asset_type": "CHECKING | SAVINGS | BROKERAGE | ...",
        "balance": 0.00,
        "vested_pct": 1.00,
        "liquid_flag": true,
        "eligible_for_closing_flag": true,
        "eligible_for_reserves_flag": true,
        "haircut_pct": 0.00,
        "net_eligible_balance": 0.00,
        "source_verified_flag": false,
        "seasoning_days": 0,
        "gift_letter_received_flag": false
      }
    ],
    "net_eligible_assets": 0.00,
    "retirement_reserve_credit": 0.00,
    "required_reserves_hold": 0.00,
    "funds_available_for_closing": 0.00,
    "funds_available_for_reserves": 0.00,
    "total_asset_strength": 0.00
  },

  "property": {
    "property_id": "PROP_20260308_090000",
    "address": "string",
    "city": "string",
    "state": "string",
    "zip_code": "string",
    "county": "string",
    "property_type": "SFR | CONDO | TOWNHOME | 2_UNIT | 3_UNIT | 4_UNIT | PUD | MANUFACTURED",
    "occupancy_type": "PRIMARY | SECOND_HOME | INVESTMENT",
    "unit_count": 1,
    "purchase_price": 0.00,
    "estimated_value": 0.00,
    "annual_property_tax": 0.00,
    "monthly_tax": 0.00,
    "tax_estimated_flag": false,
    "annual_insurance": 0.00,
    "monthly_insurance": 0.00,
    "insurance_estimated_flag": false,
    "hoa_monthly": 0.00,
    "flood_zone_flag": false,
    "appraisal_status": "ESTIMATED | ORDERED | COMPLETED | WAIVED",
    "condo_project_status": "NOT_APPLICABLE | APPROVED | PENDING_REVIEW | NON_WARRANTABLE"
  },

  "deal": {
    "deal_id": "DEAL_20260308_090000",
    "deal_type": "PURCHASE | RATE_REFI | CASH_OUT_REFI | DEBT_CONSOLIDATION_REFI | TERM_REFI",
    "borrower_id": "BORR_20260308_090000",
    "co_borrower_id": "COBR_20260308_090000",
    "property_id": "PROP_20260308_090000",
    "intent_type": "PURCHASE | REFINANCE | EQUITY_ACCESS | UNCERTAINTY",
    "qualifying_credit_score": 0,
    "requested_loan_amount": 0.00,
    "down_payment_amount": 0.00,
    "estimated_closing_costs": 0.00,
    "closing_costs_estimated_flag": false,
    "seller_concession_amount": 0.00,
    "current_mortgage_balance": 0.00,
    "current_rate": 0.00,
    "current_payment_pi": 0.00,
    "remaining_term_months": 0,
    "desired_cash_out_amount": 0.00,
    "deal_state": "ACTIVE",
    "created_at": "ISO 8601 UTC",
    "last_updated_at": "ISO 8601 UTC"
  },

  "preliminary_signals": {
    "ltv_estimate": 0.00,
    "cash_to_close_estimate": 0.00,
    "monthly_piti_estimate": 0.00,
    "preliminary_dti_value": 0.00,
    "preliminary_dti_signal": "CLEAR | WATCH | ELEVATED | CONCERN",
    "approval_readiness_score": 0.00,
    "approval_readiness_signal": "STRONG | MODERATE | DEVELOPING | ACTION",
    "approval_readiness_components": {
      "credit_margin_score": 0.00,
      "dti_margin_score": 0.00,
      "reserve_score": 0.00,
      "doc_score": 0.00
    }
  }
}

handoff_ready = true only when blocking_missing_fields array is empty AND income_split_error = false.

9B — Handoff Statement

Emit this summary when handoff_ready = true:


BORROWER PROFILE COMPLETE — v1.1
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Borrower:             [Name]  (+ Co-Borrower: [Name] if present)
Deal Type:            [Type]  |  Property: [City, State]
Credit Score:         [XXX]  →  Tier [N]  ([rate adj description])
Qualifying Score:     [XXX]  (lowest middle score if co-borrower)

GMI:                  $[X,XXX]/month  (primary)
                      $[X,XXX]/month  (co-borrower, if present)
                      $[X,XXX]/month  (combined)
Total DTI Debts:      $[X,XXX]/month
Preliminary DTI:      [XX.X%]  →  [CLEAR / WATCH / ELEVATED / CONCERN]

Available for Closing: $[XX,XXX]
Available for Reserves: $[XX,XXX]  ([X.X] months PITI)

LTV Estimate:         [XX.X%]
Cash to Close Est.:   $[XX,XXX]

Approval Readiness:   [0.XXX]  →  [STRONG / MODERATE / DEVELOPING / ACTION]
  Credit margin:      [X.XXX]  (weight 0.30)
  DTI margin:         [X.XXX]  (weight 0.30)
  Reserve depth:      [X.XXX]  (weight 0.20)
  Documentation:      [X.XXX]  (weight 0.20)

Routing Flags:        [list]
Documentation Flags:  [list]
Completeness:         [XX%]  |  Blocking Fields: NONE

→ Profile ready for Program Router
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

WORKED EXAMPLE — Full Borrower Run

This example runs a complete borrower through all 9 stages. Validate every number.

Raw Input

"Marcus and Diana Webb. Marcus is a W-2 employee making $85,000/year. Diana gets $1,100/month in VA disability — non-taxable. They're veterans. First-time buyers. Looking to purchase around $425,000, they have $35,000 in checking and $90,000 in Marcus's 401K. Their debts: $380 car payment with 14 months left, $220 credit card minimum on $8,500 balance ($12,000 limit), $185 student loan (IDR, balance $22,000). Marcus's score is 722, Diana's is 698. They want to keep their payment under $3,200 and need to minimize cash at closing. Property is an SFR in Austin, TX — primary."

Stage 1 — Extracted Data Summary

ItemExtracted Value
Primary borrowerMarcus Webb
Co-borrowerDiana Webb
Income 1BASE_SALARY, $85,000/year, W-2
Income 2DISABILITY, $1,100/month, non-taxable
veteran_flagtrue (both)
first_time_homebuyer_flagtrue
Purchase price$425,000
Asset 1CHECKING $35,000
Asset 2RETIREMENT_401K $90,000
Liability 1AUTO $380/month, 14 months remaining
Liability 2CREDIT_CARD $220 minimum, $8,500 balance, $12,000 limit
Liability 3STUDENT_LOAN IDR, $185/month actual, $22,000 balance
Marcus credit score722
Diana credit score698
target_monthly_payment$3,200
goal_priority_cashhigh (stated "minimize cash at closing") → 5
Property typeSFR, PRIMARY, Austin TX

Stage 2 — Identity + Credit Score


borrower_id:              BORR_20260308_090000
credit_score (Marcus):    722
credit_tier:              3  (720–739)
credit_tier_note:         "+0.25% to +0.50% vs par. Credit optimization high ROI."
veteran_flag:             true
first_time_homebuyer_flag: true
self_employed_flag:       false
primary_residence_intent: true
target_monthly_payment:   3,200.00
goal_priority_cash:       5  (stated: minimize cash at closing)
remaining goal weights:   default 3 (not stated — flag GOAL_WEIGHTS_PARTIAL)

Stage 3 — Co-Borrower


co_borrower_id:           COBR_20260308_090000
first_name:               Diana
credit_score (Diana):     698
credit_tier (Diana):      5  (680–699)
income_combined_flag:     true
liabilities_combined_flag: true

Qualifying Credit Score:
  Marcus middle score:    722
  Diana middle score:     698
  qualifying_credit_score = MIN(722, 698) = 698
  → credit_tier for program eligibility = 5 (Diana's score controls)
  → flag ROUTE_FHA_COMPETITIVE

Stage 4 — Income Normalization

Stream 1 — Marcus BASE_SALARY


gross_monthly_amount      = 85,000 / 12 = 7,083.33
qualifying_monthly_amount = 7,083.33  (no treatment — salary)
income_frequency:         ANNUAL → converted to MONTHLY
gross_up_applied_flag:    false
taxable_flag:             true

Stream 2 — Diana DISABILITY (non-taxable)


gross_monthly_amount      = 1,100.00
taxable_flag              = false  → gross-up applies
qualifying_monthly_amount = 1,100 × 1.25 = 1,375.00
gross_up_applied_flag     = true
gross_up_amount           = 1,100 × 0.25 = 275.00

GMI Derivation


gmi_total (Marcus):       7,083.33
gmi_coborrower (Diana):   1,375.00  (grossed up for DTI)
gmi_combined:             7,083.33 + 1,375.00 = 8,458.33
gmi_for_dti:              8,458.33

VA Gross-Up Guard (veteran_flag = true — guard must execute):
  net_income_for_va_residual = 7,083.33 + 1,100.00 = 8,183.33
  (Diana's disability: 1,100.00 — NOT grossed up on residual path)

Validation:
  gmi_for_dti (8,458.33) ≠ net_income_for_va_residual (8,183.33) ✓
  gross_up_streams: [INC_2 — DISABILITY — gross_up_amount=275.00]
  income_split_error: false ✓

Stage 5 — Liability Normalization

Liability 1 — AUTO


balance:                  not stated — flag BALANCE_UNKNOWN
monthly_payment:          380.00
months_remaining:         14
include_in_dti_flag:      FALSE  (months_remaining = 14 > 10... wait)
                          14 > 10 → rule says ≤ 10 for exclusion
                          14 months remaining → DOES NOT qualify for exclusion
include_in_dti_flag:      TRUE
dti_monthly_payment:      380.00
months_to_exclusion:      14 - 10 = 4 months until exclusion eligible
→ flag ROUTE_DEBT_TIMING_OPPORTUNITY (4 months from exclusion)
eligible_for_payoff_flag: true

Liability 2 — CREDIT_CARD


balance:                  8,500.00
monthly_payment:          220.00
credit_limit:             12,000.00
interest_rate:            not stated
include_in_dti_flag:      TRUE
dti_monthly_payment:      220.00
utilization_pct:          8,500 / 12,000 = 70.8%  → flag ROUTE_CREDIT_OPTIMIZATION
eligible_for_payoff_flag: true

Liability 3 — STUDENT_LOAN (IDR)


balance:                  22,000.00
monthly_payment:          185.00 (actual IDR payment)
student_loan_repayment_type: IDR
dti_monthly_payment:      MAX(185.00, 22,000 × 0.005) = MAX(185.00, 110.00) = 185.00
  Note: actual payment (185) > 0.5% of balance (110) → use actual
include_in_dti_flag:      TRUE
eligible_for_payoff_flag: true

Derived Liability Metrics


total_monthly_dti_obligations  = 380.00 + 220.00 + 185.00 = 785.00
total_revolving_balance        = 8,500.00
total_revolving_credit_limit   = 12,000.00
total_revolving_utilization    = 8,500 / 12,000 = 0.708  (70.8%)
high_interest_debt_total       = unknown (interest_rate not stated)
months_to_exclusion_list       = [{LIAB_1, AUTO, 14 months remaining, $380/month}]

Stage 6 — Asset Normalization

Asset 1 — CHECKING


balance:                  35,000.00
liquid_flag:              true
eligible_for_closing:     true
eligible_for_reserves:    true
haircut_pct:              0.00
net_eligible_balance:     35,000.00 × (1 - 0.00) = 35,000.00

Asset 2 — RETIREMENT_401K


balance:                  90,000.00
vested_pct:               1.00 (assumed — not stated, flag VESTED_PCT_ASSUMED)
liquid_flag:              false
eligible_for_closing:     false
eligible_for_reserves:    true
haircut_pct:              0.40
net_eligible_balance:     0.00 (not eligible for closing)

Reserve Hold Calculation


reserve_months_required:  2 (default — actual program requirement computed per scenario)
monthly_piti_estimate:    3,447.32  (calculated in Stage 7 — see below)
required_reserves_hold:   2 × 3,447.32 = 6,894.64

NOTE: $3,200 is the borrower's target_monthly_payment — NOT the PITI estimate.
      Always use monthly_piti_estimate for the reserve hold, never the target payment.

Derived Asset Metrics


net_eligible_assets:            35,000.00  (CHECKING only — 401K not eligible for closing)
retirement_reserve_credit:      90,000 × 1.00 × 0.60 = 54,000.00
required_reserves_hold:         6,894.64
funds_available_for_closing:    35,000.00 - 6,894.64 = 28,105.36
funds_available_for_reserves:   35,000.00 - 28,105.36 + 54,000.00 = 60,894.64
total_asset_strength:           28,105.36 + 60,894.64 = 89,000.00

Stage 7 — Property + Deal Normalization

Property


property_id:              PROP_20260308_090000
address:                  Austin, TX (full address not provided — flag ADDRESS_INCOMPLETE)
city:                     Austin
state:                    TX
zip_code:                 not provided — flag ZIP_MISSING (non-blocking)
property_type:            SFR
occupancy_type:           PRIMARY
unit_count:               1

annual_property_tax:      not provided
  → estimate: 425,000 × 0.0125 = 5,312.50/year → 442.71/month
  → flag TAX_ESTIMATED

annual_insurance:         not provided
  → estimate: 425,000 × 0.005 = 2,125.00/year → 177.08/month
  → flag INSURANCE_ESTIMATED

hoa_monthly:              0.00 (SFR, not stated)

Deal


deal_id:                  DEAL_20260308_090000
deal_type:                PURCHASE
qualifying_credit_score:  698  (Diana's score — lower of two middle scores)
purchase_price:           425,000.00
down_payment_amount:      not stated — flag DOWN_PAYMENT_MISSING (BLOCKING)

DOWN_PAYMENT_MISSING is blocking for a PURCHASE deal. Ask before continuing:

"How much are Marcus and Diana planning to put down? If they're considering 0% down (VA loan), I can proceed on that basis."

Assuming borrower confirms 0% down (VA loan, no down payment required):


down_payment_amount:      0.00
requested_loan_amount:    425,000 - 0 = 425,000.00
estimated_closing_costs:  425,000 × 0.03 = 12,750.00  → flag CLOSING_COSTS_ESTIMATED
seller_concession_amount: 0.00

ltv_estimate:             425,000 / 425,000 = 1.000  (100%)
  → VA loan — LTV > 1.00 is normal with funding fee financed
  → flag ROUTE_CHECK_VA

cash_to_close_estimate:   0 + 12,750 - 0 = 12,750.00
  → check vs funds_available_for_closing (28,105.36) → 28,105.36 > 12,750 ✓

Monthly PITI Estimate (7.00% placeholder)


P&I factor at 7.00%/30yr:  0.006653
  Formula: (r × (1+r)^n) / ((1+r)^n - 1)  where r = 0.07/12,  n = 360

Step 1:  monthly_rate r = 0.07 / 12 = 0.0058333
Step 2:  (1 + r)^360 = (1.0058333)^360 = 8.1161
Step 3:  numerator   = 0.0058333 × 8.1161 = 0.047344
Step 4:  denominator = 8.1161 − 1 = 7.1161
Step 5:  factor      = 0.047344 / 7.1161 = 0.0066530

P&I:                      425,000 × 0.006653 = 2,827.53
monthly_tax:              442.71  (estimated)
monthly_insurance:        177.08  (estimated)
hoa_monthly:              0.00
MI (unknown at profile):  0.00  (calculated per program/scenario)
monthly_piti_estimate:    2,827.53 + 442.71 + 177.08 = 3,447.32
  → note: actual PITI will vary by program, rate, and VA funding fee

Stage 8 — Validation + Approval Readiness Score

8A — Blocking Fields


After collecting 0% down (VA), all blocking fields present:
  ✓ income (INC_1 + INC_2)
  ✓ qualifying_credit_score = 698
  ✓ property_type = SFR
  ✓ occupancy_type = PRIMARY
  ✓ deal_type = PURCHASE
  ✓ veteran_flag = true
  ✓ purchase_price = 425,000
  ✓ down_payment_amount = 0

blocking_missing_fields: []

8B — Soft Flags


ASSETS_UNVERIFIED           (no source_verified_flag set)
TAX_ESTIMATED
INSURANCE_ESTIMATED
CLOSING_COSTS_ESTIMATED
GOAL_WEIGHTS_PARTIAL        (only cash priority stated; rest defaulted to 3)
VESTED_PCT_ASSUMED          (401K vesting not confirmed)
ADDRESS_INCOMPLETE          (full address not provided)
ZIP_MISSING

8C — Routing Flags


ROUTE_CHECK_VA              ✓ veteran_flag = true
ROUTE_CHECK_DPA             ✓ first_time_homebuyer_flag = true
ROUTE_FHA_COMPETITIVE       ✓ qualifying_credit_score = 698 (Diana controls)
ROUTE_CREDIT_OPTIMIZATION   ✓ total_revolving_utilization = 70.8% > 30%
ROUTE_DEBT_TIMING_OPPORTUNITY ✓ AUTO loan excludable in 4 months

8D — Preliminary DTI


preliminary_dti = (monthly_piti_estimate + total_monthly_dti_obligations) / gmi_for_dti
                = (3,447.32 + 785.00) / 8,458.33
                = 4,232.32 / 8,458.33
                = 0.5003  →  50.03%  →  ELEVATED

Note: This is at 7.00% placeholder. VA actual rate likely lower.
      VA has no hard DTI stop — residual income governs.
      Routing flag ROUTE_HIGH_DTI set — VA residual income test will likely apply.

8E — Approval Readiness Score


COMPONENT 1 — Credit Score Margin (weight 0.30)
  qualifying_credit_score = 698
  credit_margin_score = (698 - 580) / (760 - 580) = 118 / 180 = 0.656

COMPONENT 2 — DTI Margin (weight 0.30)
  preliminary_dti = 0.5003
  dti_margin = 0.45 - 0.5003 = -0.0503  (over limit)
  dti_margin_score = MAX(0.0, (-0.0503 + 0.09) / 0.18) = (0.0397) / 0.18 = 0.221

COMPONENT 3 — Reserve Depth (weight 0.20)
  reserves_months = funds_available_for_reserves / monthly_piti_estimate
                  = 60,894.64 / 3,447.32 = 17.66 months
  reserve_score = MIN(1.0, 17.66 / 6) = MIN(1.0, 2.944) = 1.000

COMPONENT 4 — Documentation Completeness (weight 0.20)
  soft_flags_present = 8
  doc_score = MAX(0.0, 1.0 - (8 × 0.10)) = MAX(0.0, 0.20) = 0.200

FINAL:
  approval_readiness_score = (0.656 × 0.30) + (0.221 × 0.30) + (1.000 × 0.20) + (0.200 × 0.20)
                           = 0.197 + 0.066 + 0.200 + 0.040
                           = 0.503  →  DEVELOPING

Interpretation: DTI signal is elevated at placeholder rate — but VA has no hard DTI stop.
Reserve depth is exceptional (17.7 months). Credit is Tier 5 on Diana's score.
VA is the right primary path. Profile is viable, not strong on the generic score —
the score is suppressed by the DTI at a neutral 7% rate.
At a realistic VA rate (~6.5%), DTI will drop and score will improve materially.

Stage 9 — Handoff Statement


BORROWER PROFILE COMPLETE — v1.2
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Borrowers:            Marcus Webb  +  Diana Webb (co-borrower)
Deal Type:            PURCHASE  |  SFR, Austin TX  |  $425,000
Credit Scores:        Marcus 722 (Tier 3)  /  Diana 698 (Tier 5)
Qualifying Score:     698  (Diana's score controls — lower of two middles)

GMI (Marcus):         $7,083.33/month
GMI (Diana):          $1,375.00/month  (disability grossed up 1.25× for DTI)
GMI Combined:         $8,458.33/month
VA Residual Income:   $8,183.33/month  (Diana: $1,100 — no gross-up on residual path)
Total DTI Debts:      $785.00/month
Preliminary DTI:      50.0%  →  ELEVATED  (7% placeholder rate — will improve at VA rate)

Available for Closing: $28,105.36
Available for Reserves: $60,894.64  (17.7 months PITI — exceptional)

LTV Estimate:         100.0%  (VA 0% down — normal)
Cash to Close Est.:   $12,750.00  (closing costs estimated at 3%)

Approval Readiness:   0.503  →  DEVELOPING
  Credit margin:      0.656  (weight 0.30)
  DTI margin:         0.221  (weight 0.30) ← suppressed by 7% placeholder
  Reserve depth:      1.000  (weight 0.20) ← exceptional
  Documentation:      0.200  (weight 0.20) ← 8 soft flags

Routing Flags:
  ROUTE_CHECK_VA              ← primary path
  ROUTE_CHECK_DPA             ← first-time buyer — check TX DPA programs
  ROUTE_FHA_COMPETITIVE       ← run FHA comparison (Diana's score 698)
  ROUTE_CREDIT_OPTIMIZATION   ← CC utilization 70.8% — paydown opportunity
  ROUTE_DEBT_TIMING_OPPORTUNITY ← AUTO excludable in 4 months ($380/month freed)
  ROUTE_HIGH_DTI              ← VA residual income test will apply

Documentation Flags:
  ASSETS_UNVERIFIED, TAX_ESTIMATED, INSURANCE_ESTIMATED,
  CLOSING_COSTS_ESTIMATED, GOAL_WEIGHTS_PARTIAL,
  VESTED_PCT_ASSUMED, ADDRESS_INCOMPLETE, ZIP_MISSING

Completeness:         41/50 = 82%  |  Blocking Fields: NONE

→ Profile ready for Program Router
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

ERROR CODES

CodeTrigger ConditionBlocking?Response
ERR-PROFILE-001GMI = 0 after all income processingYESCannot proceed. Request income information.
ERR-PROFILE-002income_split_error = true (VA gross-up paths identical)YESFlag INCOME_SPLIT_ERROR. Rebuild income stage.
ERR-PROFILE-003Credit score provided but out of range (< 300 or > 850)YESReject value. Request correction.
ERR-PROFILE-004Conflicting income values for same streamNOAsk borrower to clarify. Do not average without permission.
ERR-PROFILE-005total_revolving_credit_limit = 0 when revolving balances presentNOSet utilization = null. Flag UTILIZATION_UNKNOWN.
WARN-PROFILE-001Debt on record not mentioned by borrowerNOInclude debt. Flag UNDISCLOSED_LIABILITY.
WARN-PROFILE-002Crypto assets presentNOSet eligible = $0 until 60-day seasoning confirmed.
WARN-PROFILE-003HELOC present on refi with $0 balanceNOInclude in CLTV/HCLTV. Note lien position. Default include_in_dti = false for conventional, true for FHA/VA.

PROFILE UPDATE PROTOCOL

When a user provides updated information mid-session:


1. Identify which entity and field is changing
2. Update that field only — do not rebuild the entire profile
3. Recalculate all derived metrics in the affected stage and all downstream stages
4. Re-run Stage 8 validation
5. Re-emit Handoff Statement showing delta: [field changed: old → new] and new signal values
6. Emit AuditEvent: event_type=PROFILE_UPDATED, fields_changed=[list], timestamp=now

COMPANION SKILLS

SkillTrigger Condition
Clarity_Engine_Program_Router_SKILL.mdhandoff_ready = true — primary handoff
Clarity_Engine_VA_Module_SKILL.mdROUTE_CHECK_VA flag set
Clarity_Engine_Math_SKILL.mdAny computation needed during intake (PMT, DTI preview, etc.)
Clarity_Engine_Constraint_Detection_SKILL.mdpreliminary_dti_signal = ELEVATED or CONCERN

Clarity Engine — Borrower Profile Skill v1.2 | CONFIDENTIAL — PreFi, Inc. / Purpose Technology, Inc. d/b/a Purlend