Private Wealth Advisory Planning
You are producing a single JSON object that conforms to a provided answer_template.json. All numbers
come from a live read-only API, never from your own tax knowledge. Reproduce the exact conventions
below — they were reverse-engineered from verified gold answers and every formula here was checked to
reproduce real gold numbers to the cent.
0. Workflow
- Read
input/prompt.txt, input/payloads/request_memo.md, and input/payloads/answer_template.json.
The memo gives the client_id, the engagement type, and sometimes a planning horizon year.
The template's analysis_type enum tells you which of the four task families you are in.
- Resolve the API base URL. It is usually the env var
API_BASE; otherwise default to
http://127.0.0.1:8066. The API is GET-only.
- Pull every relevant record for the client (see §1) and resolve conflicting facts (§2).
- Compute the family-specific fields using the formulas in this file (and
references/formulas.md).
Do the math in code (Python), not by hand. A small script eliminates arithmetic and
compounding-order errors and lets you re-run cleanly.
- Fill the template, applying rounding and date rules (§3), and emit only the JSON object — no
prose, no markdown fences.
The four families and their reference sections:
analysis_type |
Family |
Section |
roth_conversion_rmd |
Roth conversion + RMD summary |
§4 |
ilit_crummey_implementation |
ILIT / Crummey funding cycle |
§5 |
trust_comparison |
GRAT vs CRAT comparison |
§6 |
estate_liquidity_action_plan |
Integrated estate-liquidity plan |
§7 |
1. API endpoints
| Endpoint |
Use |
GET /api/clients/{client_id} |
header record (name, age, marital_status, filing_status, estate_value, liquid_assets) |
GET /api/source-documents?client_id=... |
conflicting fact documents (CRM_NOTE, ATTORNEY_MEMO, SIGNED_PROFILE) |
GET /api/retirement-accounts?client_id=... |
IRA export (CUSTODIAN_EXPORT): traditional/roth balances, expected_return, rmd_start_age, recommended_conversion_years |
GET /api/life-insurance?client_id=... |
policy: death_benefit, annual_premium, planned_contribution_date, is_existing_policy_transfer |
GET /api/trust-candidates?client_id=... |
GRAT/CRAT params: asset_value, expected_growth_rate, grat_term_years, grat_annuity_rate, crat_term_years, crat_payout_rate |
GET /api/policies/tax |
planning constants (see below) |
GET /api/rmd-factors |
RMD divisor by age (integer-keyed) |
Always read tax constants and RMD divisors from the API, never from memory. The constants object
includes: annual_gift_exclusion (by year), estate_tax_exemption (by year), estate_tax_rate,
conversion_bracket_targets (by filing status: MFJ/SINGLE/HOH), max_crat_term_years,
charitable_deduction_rate. Use the planning year (typically 2026) to index the year-keyed maps.
2. Source-of-truth resolution (critical)
The same fact can appear in several source-documents with different values because they were imported
from different systems at different times. Resolution is by the type of fact, not simply "most
recent wins". Each fact category has a designated authoritative source type:
- Client goals & profile facts (philanthropic_intent, family_transfer_priority, beneficiary_count,
marginal_tax_rate, annual_non_ira_income, age, filing_status, marital_status, liquid_assets) →
SIGNED_PROFILE. It is the most recent (2026-02-06), it is signed, and it is the only document
carrying the full tax/beneficiary detail. It overrides the older CRM_NOTE (2025-11-20, treat as
stale) and the ATTORNEY_MEMO for these fields.
- Estate / asset valuations (estate_value and other asset figures) → ATTORNEY_MEMO. The
attorney is the authority for estate valuation. Record the controlling asset/estate source as
ATTORNEY_MEMO even when the signed profile happens to agree on the number.
- Retirement / IRA accounts → CUSTODIAN_EXPORT (the
retirement-accounts endpoint).
- Insurance policy facts → the
life-insurance endpoint, reported as SIGNED_PROFILE for the
controlling_policy_source field (the signed profile governs the household's policy/beneficiary
intent in these tasks).
- CRM_NOTE is always stale — never select it as a controlling source.
Fill the source_resolution.* enum fields accordingly. Observed gold pattern across families:
controlling_profile_source/controlling_goal_source/controlling_beneficiary_source/
controlling_policy_source = SIGNED_PROFILE; controlling_account_source = CUSTODIAN_EXPORT;
controlling_asset_source = ATTORNEY_MEMO.
When a numeric input has both a client-header value and a signed-profile value and they agree, either
works; if they disagree, use the signed-profile value for profile facts and the attorney-memo value
for estate/asset facts.
3. Output conventions
- Money: JSON numbers (not strings), rounded to 2 decimals (cents). Round once at the end of
each field's computation. Integer-valued dollars still render with
.0 (e.g. 80000.0).
- Years / counts / beneficiary_count / notices_required: integers.
- Dates: ISO
YYYY-MM-DD strings.
- Booleans: real JSON booleans.
task_id: use the task id implied by the harness (e.g. train_00N / test_00N). If the input
folder name encodes it, mirror it; otherwise echo what the prompt/memo gives.
- Echo
client_id and the template's fixed analysis_type literal verbatim.
action_set (family §7) must be sorted alphabetically.
- Emit only the JSON object. No surrounding prose or code fences.
4. Roth conversion + RMD (roth_conversion_rmd)
Inputs: signed profile (annual_non_ira_income, marginal_tax_rate, age, filing_status,
planning_year); IRA export (traditional_balance, roth_balance, expected_return,
rmd_start_age, recommended_conversion_years); conversion_bracket_targets[filing_status];
rmd-factors; horizon year from the memo.
Conversion sizing
annual_conversion_amount = conversion_bracket_targets[filing_status] − annual_non_ira_income
(fill the top of the bracket each year).
conversion_years = conversion_years_positive = recommended_conversion_years (from the IRA export).
first_conversion_year = planning_year.
total_converted = annual_conversion_amount × conversion_years.
total_conversion_tax = total_converted × marginal_tax_rate.
first_rmd_year = planning_year + (rmd_start_age − current_age).
Year-by-year simulation (planning_year … horizon, inclusive). This exact order of operations
matters — it was the only ordering that reproduced gold to the cent. For each year, with
age = start_age + (year − planning_year):
- Conversion (conversion scenario only, and only while
year < planning_year + conversion_years):
amt = min(annual_conversion_amount, traditional); traditional −= amt; roth += amt.
- RMD (only if
age ≥ rmd_start_age and the age exists in the factor table):
rmd = traditional / rmd_factor[age]; traditional −= rmd;
rmd_tax += rmd × marginal_tax_rate.
- Growth (apply last):
traditional ×= (1 + expected_return); roth ×= (1 + expected_return).
Run the simulation twice:
- Baseline (no conversions) →
baseline_rmd_tax_through_horizon = accumulated rmd_tax.
- Conversion (with conversions) →
conversion_rmd_tax_through_horizon = accumulated rmd_tax,
and the ending balances are projected_traditional_balance_horizon and
projected_roth_balance_horizon.
rmd_tax_savings_through_horizon = baseline − conversion.
The projected balances reported are from the conversion scenario.
Enums
primary_action: STAGED_ROTH_CONVERSION when annual_conversion_amount > 0 and conversions reduce
RMD tax (savings > 0) — the normal case. Use DEFER if filling the bracket leaves no room
(annual_conversion_amount ≤ 0) but conversion may help later; NO_CONVERSION if conversion gives
no benefit.
suitability: SUITABLE when staged conversion is recommended with positive savings; BORDERLINE
if savings are marginal or liquidity is tight; DEFER to wait.
risk_flag: TAX_BRACKET_MANAGEMENT (default — the plan is about filling brackets);
RMD_NEAR_TERM if the client is already at/over RMD age with little runway;
LIQUIDITY_CONSTRAINT if paying conversion tax strains liquid assets.
heir_tax_profile from the ending balance mix share = roth / (roth + traditional):
MOSTLY_TAX_FREE if share ≥ 0.7, MOSTLY_TAXABLE if share ≤ 0.3, else
MIXED_TAXABLE_AND_TAX_FREE.
5. ILIT / Crummey implementation (ilit_crummey_implementation)
Inputs: gift exclusion for the planning year; signed-profile beneficiary_count; life-insurance
record (death_benefit, annual_premium, planned_contribution_date, is_existing_policy_transfer);
estate constants for the estate-inclusion side.
Gift plan
annual_exclusion_per_beneficiary = annual_gift_exclusion[planning_year].
beneficiary_count = signed profile value.
annual_exclusion_capacity = annual_exclusion_per_beneficiary × beneficiary_count.
annual_premium = policy value.
premium_gap = max(0, annual_premium − annual_exclusion_capacity).
Administration / Crummey dates (start from policy planned_contribution_date):
contribution_date = planned_contribution_date.
notice_due_date = contribution_date + 7 days (notices go out within a week).
withdrawal_window_end = notice_due_date + 30 days (30-day Crummey withdrawal window).
earliest_premium_payment_date = withdrawal_window_end + 1 day (pay only after the window closes).
notices_required = beneficiary_count (one Crummey notice per beneficiary).
dedicated_bank_account_required = true (ILIT formalities require a dedicated account).
Estate result
death_benefit = policy value.
projected_outside_estate_if_implemented = death_benefit (a properly funded ILIT keeps the proceeds
out of the estate).
tax_liquidity_support = death_benefit × estate_tax_rate (the estate-tax-equivalent liquidity the
policy provides).
estate_inclusion_risk = the same value as recommendation.risk_flag (see below).
Enums
risk_flag / estate_inclusion_risk logic:
- Start from
LOW_IF_FORMALITIES_MET.
- If
is_existing_policy_transfer is true → THREE_YEAR_LOOKBACK (transferring an existing policy
triggers the IRC §2035 three-year lookback).
- If
premium_gap > 0 → EXCLUSION_SHORTFALL (premium exceeds annual-exclusion capacity).
- If both apply →
THREE_YEAR_LOOKBACK_AND_EXCLUSION_SHORTFALL.
primary_action:
FUND_WITH_CRUMMEY_NOTICES when premium_gap == 0 and not a transfer (clean new-policy funding).
USE_LIFETIME_EXEMPTION_FOR_SHORTFALL when premium_gap > 0 only.
USE_NEW_POLICY_OR_ACCEPT_LOOKBACK when it is an existing-policy transfer (lookback) only.
DISCLOSE_LOOKBACK_AND_USE_EXEMPTION when both shortfall and lookback apply.
suitability: SUITABLE_WITH_ADMINISTRATION in the clean case (workable if formalities are kept);
BORDERLINE if there is a shortfall or lookback wrinkle to manage; NOT_SUITABLE only if the plan
fundamentally fails.
6. GRAT vs CRAT comparison (trust_comparison)
Inputs: trust candidate (asset_value A, expected_growth_rate g, grat_term_years,
grat_annuity_rate, crat_term_years, crat_payout_rate); estate constants; signed-profile goals.
Estate context (estate_value from attorney memo; marital status from signed profile):
exemption_used = estate_tax_exemption[planning_year] × (2 if married else 1).
taxable_estate = max(0, estate_value − exemption_used).
estate_tax_exposure = taxable_estate × estate_tax_rate.
liquid_assets_available = signed-profile liquid_assets.
liquidity_gap_before_planning = max(0, estate_tax_exposure − liquid_assets_available).
- Include
planning_year and these fields per the template (some templates list them under
estate_context).
GRAT (zeroed-out-style annuity, nominal annuity payments — not future-valued):
projected_remainder_to_heirs = A × (1 + g)^grat_term − A × grat_annuity_rate × grat_term.
estimated_estate_tax_reduction = projected_remainder_to_heirs × estate_tax_rate.
mortality_inclusion_risk = TERM_SURVIVAL_REQUIRED (grantor must outlive the term).
grat.term_years = grat_term_years.
CRAT (same nominal-payout structure):
projected_charitable_remainder = A × (1 + g)^crat_term − A × crat_payout_rate × crat_term.
estimated_income_tax_deduction = projected_charitable_remainder × charitable_deduction_rate.
crat.term_years = crat_term_years (use the candidate's term, typically capped at max_crat_term_years).
family_transfer_fit: LOW when family transfer is the priority (a CRAT gives nothing to heirs),
MODERATE/HIGH only if the goals lean charitable enough that a CRAT serves the family too.
Recommendation (driven by signed-profile goals):
- If
family_transfer_priority outranks philanthropic_intent (high vs lower) →
preferred_strategy = GRAT, rationale_code = CHILDREN_TRANSFER_PRIORITY,
alternate_role = SECONDARY_CHARITABLE_TOOL.
- If
philanthropic_intent outranks family transfer → preferred_strategy = CRAT,
rationale_code = PHILANTHROPIC_PRIORITY, alternate_role = SECONDARY_FAMILY_TRANSFER_TOOL.
- Treat the ordinal scale
low < moderate < high. A tie defaults to the family-transfer (GRAT) reading
unless the engagement clearly emphasizes philanthropy.
7. Integrated estate-liquidity action plan (estate_liquidity_action_plan)
Combine the estate context (§6), the ILIT (§5), and the trust transfer (§6) for one client.
- estate_context: same formulas as §6 (
exemption_used, taxable_estate, estate_tax_exposure,
liquid_assets_available, liquidity_gap_before_planning, planning_year).
- ilit block:
annual_exclusion_capacity and premium_gap from §5; estate_inclusion_risk from
§5 risk logic; projected_outside_estate_if_implemented = death_benefit.
- trust_transfer block: pick the preferred strategy with §6's goal rule, then report
preferred_strategy, projected_remainder_to_heirs (GRAT remainder), estimated_estate_tax_reduction
(GRAT remainder × estate_tax_rate), and projected_charitable_remainder (CRAT remainder). All three
trust figures are reported regardless of which strategy is preferred.
- recommendation:
primary_action: COMBINE_ILIT_AND_GRAT when an ILIT plus a GRAT both fit (family-transfer
priority, manageable ILIT); CRAT_WITH_LIQUIDITY_REVIEW when philanthropy leads;
ILIT_WITH_EXEMPTION_REVIEW when a premium/exemption shortfall dominates.
sequencing: ILIT_FIRST_THEN_GRAT in the combined case (stand up the ILIT, then the GRAT);
TRUST_DECISION_FIRST when the GRAT/CRAT choice gates everything;
ILIT_FIRST_THEN_ATTORNEY_REVIEW when the ILIT is clear but the rest needs counsel.
risk_flag: the ILIT estate-inclusion risk (§5 logic) — LOW_IF_FORMALITIES_MET in the clean case.
- action_set: build from these enums and sort alphabetically:
ATTORNEY_DRAFT_REVIEW — essentially always (trust/ILIT docs need counsel).
ILIT_CRUMMEY_NOTICE_CYCLE — when an ILIT/policy is in play.
GRAT_FOR_APPRECIATING_SHARES — when the preferred trust strategy is GRAT.
CRAT_FOR_CHARITABLE_REMAINDER — when the preferred trust strategy is CRAT.
LIFETIME_EXEMPTION_ALLOCATION — when there is a premium_gap > 0 (or exemption must absorb a
shortfall). Include only the items the case actually calls for.
8. Pitfalls
- Do not future-value the GRAT/CRAT annuity/payout stream. The verified formula subtracts the
nominal sum of payments (
A × rate × term), not an annuity future value. An annuity-FV formula
produces numbers that look plausible but are wrong.
- RMD order is conversion → RMD → growth, every year. Growing first, or taking the RMD before
growth in the wrong order, changes every downstream balance. Apply growth last.
- Conversions stop after
recommended_conversion_years but the simulation continues to the horizon.
- Projected balances come from the conversion scenario, not the baseline.
- Married estate exemption is doubled (
× 2); single/HOH is not.
- CRM_NOTE never controls. Estate/asset facts come from the attorney memo; goals/profile from the
signed profile; accounts from the custodian export.
estate_inclusion_risk mirrors recommendation.risk_flag in the ILIT family.
- Round to cents at the end, keep numbers as JSON numbers, and emit only the JSON object.
See references/formulas.md for compact formula cards and a worked numeric check you can compare your
script against, and references/worked_examples.md for end-to-end traces of each family.
1---2name: private-wealth-advisory-planning-33description: Produce structured JSON planning outputs for a private-wealth advisory benchmark backed by a read-only advisory API (Roth-conversion/RMD tax summaries, ILIT/Crummey funding cycles, GRAT-vs-CRAT trust comparisons, and integrated estate-liquidity action plans). Use this skill whenever a task asks for a structured advisory planning JSON for a client ID (e.g. CLT-xxxx), references an answer_template.json with fields like conversion_plan, rmd_projection, gift_plan, administration, grat/crat, estate_context, ilit, trust_transfer, action_set, or source_resolution, or mentions Roth conversions, RMDs, ILIT Crummey notices, GRAT, CRAT, estate-tax exemption, or estate liquidity. It encodes the exact source-conflict resolution rules, numeric formulas, RMD year-by-year simulation order, date arithmetic, enum decision rules, rounding, and output schema the gold answers require, so apply it even when the prompt does not name a specific strategy by name.4---56# Private Wealth Advisory Planning78You are producing a single JSON object that conforms to a provided `answer_template.json`. All numbers9come from a live read-only API, never from your own tax knowledge. Reproduce the exact conventions10below — they were reverse-engineered from verified gold answers and every formula here was checked to11reproduce real gold numbers to the cent.1213## 0. Workflow14151. Read `input/prompt.txt`, `input/payloads/request_memo.md`, and `input/payloads/answer_template.json`.16 The memo gives the `client_id`, the engagement type, and sometimes a **planning horizon year**.17 The template's `analysis_type` enum tells you which of the four task families you are in.182. Resolve the API base URL. It is usually the env var `API_BASE`; otherwise default to19 `http://127.0.0.1:8066`. The API is GET-only.203. Pull every relevant record for the client (see §1) and resolve conflicting facts (§2).214. Compute the family-specific fields using the formulas in this file (and `references/formulas.md`).22 **Do the math in code (Python), not by hand.** A small script eliminates arithmetic and23 compounding-order errors and lets you re-run cleanly.245. Fill the template, applying rounding and date rules (§3), and emit **only** the JSON object — no25 prose, no markdown fences.2627The four families and their reference sections:2829| `analysis_type` | Family | Section |30| ----------------------------- | ------------------------------- | ------- |31| `roth_conversion_rmd` | Roth conversion + RMD summary | §4 |32| `ilit_crummey_implementation` | ILIT / Crummey funding cycle | §5 |33| `trust_comparison` | GRAT vs CRAT comparison | §6 |34| `estate_liquidity_action_plan`| Integrated estate-liquidity plan| §7 |3536## 1. API endpoints3738| Endpoint | Use |39| --- | --- |40| `GET /api/clients/{client_id}` | header record (name, age, marital_status, filing_status, estate_value, liquid_assets) |41| `GET /api/source-documents?client_id=...` | conflicting fact documents (CRM_NOTE, ATTORNEY_MEMO, SIGNED_PROFILE) |42| `GET /api/retirement-accounts?client_id=...` | IRA export (CUSTODIAN_EXPORT): traditional/roth balances, expected_return, rmd_start_age, recommended_conversion_years |43| `GET /api/life-insurance?client_id=...` | policy: death_benefit, annual_premium, planned_contribution_date, is_existing_policy_transfer |44| `GET /api/trust-candidates?client_id=...` | GRAT/CRAT params: asset_value, expected_growth_rate, grat_term_years, grat_annuity_rate, crat_term_years, crat_payout_rate |45| `GET /api/policies/tax` | planning constants (see below) |46| `GET /api/rmd-factors` | RMD divisor by age (integer-keyed) |4748Always read tax constants and RMD divisors **from the API**, never from memory. The constants object49includes: `annual_gift_exclusion` (by year), `estate_tax_exemption` (by year), `estate_tax_rate`,50`conversion_bracket_targets` (by filing status: MFJ/SINGLE/HOH), `max_crat_term_years`,51`charitable_deduction_rate`. Use the planning year (typically 2026) to index the year-keyed maps.5253## 2. Source-of-truth resolution (critical)5455The same fact can appear in several `source-documents` with different values because they were imported56from different systems at different times. Resolution is **by the type of fact**, not simply "most57recent wins". Each fact category has a designated authoritative source type:5859- **Client goals & profile facts** (philanthropic_intent, family_transfer_priority, beneficiary_count,60 marginal_tax_rate, annual_non_ira_income, age, filing_status, marital_status, liquid_assets) →61 **SIGNED_PROFILE**. It is the most recent (2026-02-06), it is signed, and it is the only document62 carrying the full tax/beneficiary detail. It overrides the older CRM_NOTE (2025-11-20, treat as63 stale) and the ATTORNEY_MEMO for these fields.64- **Estate / asset valuations** (estate_value and other asset figures) → **ATTORNEY_MEMO**. The65 attorney is the authority for estate valuation. Record the controlling asset/estate source as66 `ATTORNEY_MEMO` even when the signed profile happens to agree on the number.67- **Retirement / IRA accounts** → **CUSTODIAN_EXPORT** (the `retirement-accounts` endpoint).68- **Insurance policy facts** → the `life-insurance` endpoint, reported as **SIGNED_PROFILE** for the69 `controlling_policy_source` field (the signed profile governs the household's policy/beneficiary70 intent in these tasks).71- **CRM_NOTE is always stale** — never select it as a controlling source.7273Fill the `source_resolution.*` enum fields accordingly. Observed gold pattern across families:74`controlling_profile_source`/`controlling_goal_source`/`controlling_beneficiary_source`/75`controlling_policy_source` = `SIGNED_PROFILE`; `controlling_account_source` = `CUSTODIAN_EXPORT`;76`controlling_asset_source` = `ATTORNEY_MEMO`.7778When a numeric input has both a client-header value and a signed-profile value and they agree, either79works; if they disagree, use the signed-profile value for profile facts and the attorney-memo value80for estate/asset facts.8182## 3. Output conventions8384- **Money**: JSON numbers (not strings), rounded to **2 decimals (cents)**. Round once at the end of85 each field's computation. Integer-valued dollars still render with `.0` (e.g. `80000.0`).86- **Years / counts / beneficiary_count / notices_required**: integers.87- **Dates**: ISO `YYYY-MM-DD` strings.88- **Booleans**: real JSON booleans.89- **`task_id`**: use the task id implied by the harness (e.g. `train_00N` / `test_00N`). If the input90 folder name encodes it, mirror it; otherwise echo what the prompt/memo gives.91- Echo `client_id` and the template's fixed `analysis_type` literal verbatim.92- `action_set` (family §7) must be **sorted alphabetically**.93- Emit only the JSON object. No surrounding prose or code fences.9495## 4. Roth conversion + RMD (`roth_conversion_rmd`)9697Inputs: signed profile (`annual_non_ira_income`, `marginal_tax_rate`, `age`, `filing_status`,98`planning_year`); IRA export (`traditional_balance`, `roth_balance`, `expected_return`,99`rmd_start_age`, `recommended_conversion_years`); `conversion_bracket_targets[filing_status]`;100`rmd-factors`; horizon year from the memo.101102**Conversion sizing**103- `annual_conversion_amount = conversion_bracket_targets[filing_status] − annual_non_ira_income`104 (fill the top of the bracket each year).105- `conversion_years = conversion_years_positive = recommended_conversion_years` (from the IRA export).106- `first_conversion_year = planning_year`.107- `total_converted = annual_conversion_amount × conversion_years`.108- `total_conversion_tax = total_converted × marginal_tax_rate`.109- `first_rmd_year = planning_year + (rmd_start_age − current_age)`.110111**Year-by-year simulation (planning_year … horizon, inclusive).** This exact order of operations112matters — it was the only ordering that reproduced gold to the cent. For each year, with113`age = start_age + (year − planning_year)`:1141151. **Conversion** (conversion scenario only, and only while `year < planning_year + conversion_years`):116 `amt = min(annual_conversion_amount, traditional)`; `traditional −= amt`; `roth += amt`.1172. **RMD** (only if `age ≥ rmd_start_age` and the age exists in the factor table):118 `rmd = traditional / rmd_factor[age]`; `traditional −= rmd`;119 `rmd_tax += rmd × marginal_tax_rate`.1203. **Growth** (apply last): `traditional ×= (1 + expected_return)`; `roth ×= (1 + expected_return)`.121122Run the simulation twice:123- **Baseline** (no conversions) → `baseline_rmd_tax_through_horizon` = accumulated `rmd_tax`.124- **Conversion** (with conversions) → `conversion_rmd_tax_through_horizon` = accumulated `rmd_tax`,125 and the ending balances are `projected_traditional_balance_horizon` and126 `projected_roth_balance_horizon`.127- `rmd_tax_savings_through_horizon = baseline − conversion`.128129The projected balances reported are from the **conversion** scenario.130131**Enums**132- `primary_action`: `STAGED_ROTH_CONVERSION` when `annual_conversion_amount > 0` and conversions reduce133 RMD tax (savings > 0) — the normal case. Use `DEFER` if filling the bracket leaves no room134 (`annual_conversion_amount ≤ 0`) but conversion may help later; `NO_CONVERSION` if conversion gives135 no benefit.136- `suitability`: `SUITABLE` when staged conversion is recommended with positive savings; `BORDERLINE`137 if savings are marginal or liquidity is tight; `DEFER` to wait.138- `risk_flag`: `TAX_BRACKET_MANAGEMENT` (default — the plan is about filling brackets);139 `RMD_NEAR_TERM` if the client is already at/over RMD age with little runway;140 `LIQUIDITY_CONSTRAINT` if paying conversion tax strains liquid assets.141- `heir_tax_profile` from the ending balance mix `share = roth / (roth + traditional)`:142 `MOSTLY_TAX_FREE` if `share ≥ 0.7`, `MOSTLY_TAXABLE` if `share ≤ 0.3`, else143 `MIXED_TAXABLE_AND_TAX_FREE`.144145## 5. ILIT / Crummey implementation (`ilit_crummey_implementation`)146147Inputs: gift exclusion for the planning year; signed-profile `beneficiary_count`; life-insurance148record (`death_benefit`, `annual_premium`, `planned_contribution_date`, `is_existing_policy_transfer`);149estate constants for the estate-inclusion side.150151**Gift plan**152- `annual_exclusion_per_beneficiary = annual_gift_exclusion[planning_year]`.153- `beneficiary_count` = signed profile value.154- `annual_exclusion_capacity = annual_exclusion_per_beneficiary × beneficiary_count`.155- `annual_premium` = policy value.156- `premium_gap = max(0, annual_premium − annual_exclusion_capacity)`.157158**Administration / Crummey dates** (start from policy `planned_contribution_date`):159- `contribution_date = planned_contribution_date`.160- `notice_due_date = contribution_date + 7 days` (notices go out within a week).161- `withdrawal_window_end = notice_due_date + 30 days` (30-day Crummey withdrawal window).162- `earliest_premium_payment_date = withdrawal_window_end + 1 day` (pay only after the window closes).163- `notices_required = beneficiary_count` (one Crummey notice per beneficiary).164- `dedicated_bank_account_required = true` (ILIT formalities require a dedicated account).165166**Estate result**167- `death_benefit` = policy value.168- `projected_outside_estate_if_implemented = death_benefit` (a properly funded ILIT keeps the proceeds169 out of the estate).170- `tax_liquidity_support = death_benefit × estate_tax_rate` (the estate-tax-equivalent liquidity the171 policy provides).172- `estate_inclusion_risk` = the same value as `recommendation.risk_flag` (see below).173174**Enums**175- `risk_flag` / `estate_inclusion_risk` logic:176 - Start from `LOW_IF_FORMALITIES_MET`.177 - If `is_existing_policy_transfer` is true → `THREE_YEAR_LOOKBACK` (transferring an existing policy178 triggers the IRC §2035 three-year lookback).179 - If `premium_gap > 0` → `EXCLUSION_SHORTFALL` (premium exceeds annual-exclusion capacity).180 - If both apply → `THREE_YEAR_LOOKBACK_AND_EXCLUSION_SHORTFALL`.181- `primary_action`:182 - `FUND_WITH_CRUMMEY_NOTICES` when `premium_gap == 0` and not a transfer (clean new-policy funding).183 - `USE_LIFETIME_EXEMPTION_FOR_SHORTFALL` when `premium_gap > 0` only.184 - `USE_NEW_POLICY_OR_ACCEPT_LOOKBACK` when it is an existing-policy transfer (lookback) only.185 - `DISCLOSE_LOOKBACK_AND_USE_EXEMPTION` when both shortfall and lookback apply.186- `suitability`: `SUITABLE_WITH_ADMINISTRATION` in the clean case (workable if formalities are kept);187 `BORDERLINE` if there is a shortfall or lookback wrinkle to manage; `NOT_SUITABLE` only if the plan188 fundamentally fails.189190## 6. GRAT vs CRAT comparison (`trust_comparison`)191192Inputs: trust candidate (`asset_value` A, `expected_growth_rate` g, `grat_term_years`,193`grat_annuity_rate`, `crat_term_years`, `crat_payout_rate`); estate constants; signed-profile goals.194195**Estate context** (estate_value from attorney memo; marital status from signed profile):196- `exemption_used = estate_tax_exemption[planning_year] × (2 if married else 1)`.197- `taxable_estate = max(0, estate_value − exemption_used)`.198- `estate_tax_exposure = taxable_estate × estate_tax_rate`.199- `liquid_assets_available` = signed-profile `liquid_assets`.200- `liquidity_gap_before_planning = max(0, estate_tax_exposure − liquid_assets_available)`.201- Include `planning_year` and these fields per the template (some templates list them under202 `estate_context`).203204**GRAT** (zeroed-out-style annuity, nominal annuity payments — *not* future-valued):205- `projected_remainder_to_heirs = A × (1 + g)^grat_term − A × grat_annuity_rate × grat_term`.206- `estimated_estate_tax_reduction = projected_remainder_to_heirs × estate_tax_rate`.207- `mortality_inclusion_risk = TERM_SURVIVAL_REQUIRED` (grantor must outlive the term).208- `grat.term_years = grat_term_years`.209210**CRAT** (same nominal-payout structure):211- `projected_charitable_remainder = A × (1 + g)^crat_term − A × crat_payout_rate × crat_term`.212- `estimated_income_tax_deduction = projected_charitable_remainder × charitable_deduction_rate`.213- `crat.term_years = crat_term_years` (use the candidate's term, typically capped at `max_crat_term_years`).214- `family_transfer_fit`: `LOW` when family transfer is the priority (a CRAT gives nothing to heirs),215 `MODERATE`/`HIGH` only if the goals lean charitable enough that a CRAT serves the family too.216217**Recommendation** (driven by signed-profile goals):218- If `family_transfer_priority` outranks `philanthropic_intent` (high vs lower) →219 `preferred_strategy = GRAT`, `rationale_code = CHILDREN_TRANSFER_PRIORITY`,220 `alternate_role = SECONDARY_CHARITABLE_TOOL`.221- If `philanthropic_intent` outranks family transfer → `preferred_strategy = CRAT`,222 `rationale_code = PHILANTHROPIC_PRIORITY`, `alternate_role = SECONDARY_FAMILY_TRANSFER_TOOL`.223- Treat the ordinal scale `low < moderate < high`. A tie defaults to the family-transfer (GRAT) reading224 unless the engagement clearly emphasizes philanthropy.225226## 7. Integrated estate-liquidity action plan (`estate_liquidity_action_plan`)227228Combine the estate context (§6), the ILIT (§5), and the trust transfer (§6) for one client.229230- **estate_context**: same formulas as §6 (`exemption_used`, `taxable_estate`, `estate_tax_exposure`,231 `liquid_assets_available`, `liquidity_gap_before_planning`, `planning_year`).232- **ilit** block: `annual_exclusion_capacity` and `premium_gap` from §5; `estate_inclusion_risk` from233 §5 risk logic; `projected_outside_estate_if_implemented = death_benefit`.234- **trust_transfer** block: pick the preferred strategy with §6's goal rule, then report235 `preferred_strategy`, `projected_remainder_to_heirs` (GRAT remainder), `estimated_estate_tax_reduction`236 (GRAT remainder × estate_tax_rate), and `projected_charitable_remainder` (CRAT remainder). All three237 trust figures are reported regardless of which strategy is preferred.238- **recommendation**:239 - `primary_action`: `COMBINE_ILIT_AND_GRAT` when an ILIT plus a GRAT both fit (family-transfer240 priority, manageable ILIT); `CRAT_WITH_LIQUIDITY_REVIEW` when philanthropy leads;241 `ILIT_WITH_EXEMPTION_REVIEW` when a premium/exemption shortfall dominates.242 - `sequencing`: `ILIT_FIRST_THEN_GRAT` in the combined case (stand up the ILIT, then the GRAT);243 `TRUST_DECISION_FIRST` when the GRAT/CRAT choice gates everything;244 `ILIT_FIRST_THEN_ATTORNEY_REVIEW` when the ILIT is clear but the rest needs counsel.245 - `risk_flag`: the ILIT estate-inclusion risk (§5 logic) — `LOW_IF_FORMALITIES_MET` in the clean case.246- **action_set**: build from these enums and **sort alphabetically**:247 - `ATTORNEY_DRAFT_REVIEW` — essentially always (trust/ILIT docs need counsel).248 - `ILIT_CRUMMEY_NOTICE_CYCLE` — when an ILIT/policy is in play.249 - `GRAT_FOR_APPRECIATING_SHARES` — when the preferred trust strategy is GRAT.250 - `CRAT_FOR_CHARITABLE_REMAINDER` — when the preferred trust strategy is CRAT.251 - `LIFETIME_EXEMPTION_ALLOCATION` — when there is a `premium_gap > 0` (or exemption must absorb a252 shortfall). Include only the items the case actually calls for.253254## 8. Pitfalls255256- **Do not future-value the GRAT/CRAT annuity/payout stream.** The verified formula subtracts the257 *nominal* sum of payments (`A × rate × term`), not an annuity future value. An annuity-FV formula258 produces numbers that look plausible but are wrong.259- **RMD order is conversion → RMD → growth, every year.** Growing first, or taking the RMD before260 growth in the wrong order, changes every downstream balance. Apply growth last.261- **Conversions stop after `recommended_conversion_years`** but the simulation continues to the horizon.262- **Projected balances come from the conversion scenario**, not the baseline.263- **Married estate exemption is doubled** (`× 2`); single/HOH is not.264- **CRM_NOTE never controls.** Estate/asset facts come from the attorney memo; goals/profile from the265 signed profile; accounts from the custodian export.266- **`estate_inclusion_risk` mirrors `recommendation.risk_flag`** in the ILIT family.267- **Round to cents at the end**, keep numbers as JSON numbers, and emit only the JSON object.268269See `references/formulas.md` for compact formula cards and a worked numeric check you can compare your270script against, and `references/worked_examples.md` for end-to-end traces of each family.