# 03 — Applicant profile (dataset)

The live **profile pane** is the dataset checklist as a form the customer **sees filling**, not a hidden CRM dump.

Source of field names: `html/vertical-datasets/dataset-mortgage-protection.html`.

## TypeScript shape (v1)

```ts
type CoverageOnWhom = "primary" | "spouse" | "both";

type Impairment = {
  module: string; // cancer | diabetes | heart | kidney | lung | ...
  attributes: Record<string, string | number | boolean>;
  path_answers?: string[];
};

type ApplicantProfile = {
  intent: "mortgage_protection" | null;

  // Demographics (G)
  age?: number;
  date_of_birth?: string;
  sex?: string;
  state?: string;
  citizenship_residency?: string;
  name?: string;
  phone?: string;
  email?: string;

  // BMI / build (G) — filled at process step 3
  height_ft_in?: string;
  weight_lb?: number;
  bmi_computed?: number;
  build_class_label?: string;
  diabetic_build_path?: boolean;

  // Tobacco (G) — step 3
  tobacco_products?: string[];
  months_since_last_use?: number;
  nicotine_class?: string;

  // Diseases (G) — step 4
  impairments?: Impairment[];

  // Income / financial (G)
  annual_income?: number;
  net_worth?: number;
  existing_coverage_amount?: number;
  bankruptcy_years?: number;

  // Spouse / household (G)
  marital_status?: string;
  spouse_age_sex?: string;
  spouse_tobacco?: string;
  spouse_impairments_summary?: string;
  dependent_children_count?: number;
  beneficiary_relationship?: string;

  // Mortgage-only (not G)
  loan_balance?: number;
  loan_term_years?: number;
  property_state?: string;
  co_borrower_flag?: boolean;
  coverage_on_whom?: CoverageOnWhom;
  monthly_payment?: number; // strongly useful; process script collects it
  closing_date?: string;
  property_type?: string;

  family_history?: { fh_cvd_parent_sibling?: string };
  labs?: { a1c_bp_etc?: string };
};
```

## Profile UI groups (match dataset)

Render sections in this order so the customer recognizes the “file” being built:

1. **Mortgage** — `loan_balance`, `loan_term_years`, `coverage_on_whom`, `co_borrower_flag`, `property_state`
2. **Demographics** — age/DOB, sex, state
3. **BMI / build** — height, weight, computed BMI, class (after step 3)
4. **Tobacco**
5. **Diseases** — list of modules + short attributes
6. **Household / spouse**
7. **Income / existing coverage**

Each field badge: **R** required, **S** recommended, **O** optional (from the HTML tags). Missing **R** fields stay visually empty (amber).

## Completeness rules (for the pane)

| Gate | Required to mark complete |
|------|---------------------------|
| Intake | name or phone + `state` |
| Intent | `intent === mortgage_protection` + `coverage_on_whom` |
| Demographics + loan | `age` or `date_of_birth` + `loan_balance` |
| Build | `height_ft_in` + `weight_lb` + tobacco answered |
| Disease | all **R** disease modules asked or explicit none |
| Household | spouse fields if `co_borrower_flag` |
| Soft UW | DecisionResult object present (step 6) |

`bmi_computed` is derived in app code: `703 * lb / inches^2`. Do not ask the customer for BMI as a raw number if height/weight exist.

## Extraction

GPT-4o-mini returns a JSON patch (only keys it is sure about). Server merges with zod. Never overwrite a confirmed field with a weaker guess without asking.

Example patch:

```json
{
  "loan_balance": 240000,
  "loan_term_years": 28,
  "coverage_on_whom": "both",
  "co_borrower_flag": true
}
```

## What the customer should not see as “done”

- Quote given
- “Sounds good”
- Soft `DecisionResult` without disclosures

Those are progress, not sale complete.
