SKILL: Private Wealth Advisory Structured Output
Personal financial advisory planning over a remote advisory API. Each task asks for a
strict JSON object (per an answer template) summarizing one of four analysis types:
roth_conversion_rmd, ilit_crummey_implementation, trust_comparison, or
estate_liquidity_action_plan. The advisory environment holds CONFLICTING source records
imported from different systems; the core skill is resolving which source controls each
fact, then computing precisely (USD to cents, ISO dates, sorted lists, exact formulas).
1. Remote API Workflow (endpoint order)
Base URL is supplied by the harness (API_BASE). All endpoints are GET; data is JSON.
GET /api/health -> confirm {"ok": true}.
GET /api/policies/tax -> planning constants (read once, cache):
annual_gift_exclusion (by year; 2026 = 20000)
estate_tax_exemption (by year; 2026 = 13610000)
estate_tax_rate (0.4)
conversion_bracket_targets by filing status (MFJ=394600, SINGLE=197300, HOH=263500)
max_crat_term_years (20)
charitable_deduction_rate (0.35)
GET /api/rmd-factors -> age -> RMD divisor table (keys are ages 73..99 as strings).
GET /api/clients/<client_id> -> base record (household, age, marital/filing status,
planning_year, estate_value, liquid_assets).
GET /api/source-documents?client_id=<id> -> the conflicting sources (CRM_NOTE,
ATTORNEY_MEMO, SIGNED_PROFILE, sometimes STALE_MARKETING_INTAKE), each with an
effective_date and a facts map. ALWAYS fetch this before deciding any contested fact.
GET /api/retirement-accounts?client_id=<id> -> traditional/Roth balances, expected
return, rmd_start_age, recommended_conversion_years (source_type = CUSTODIAN_EXPORT).
GET /api/life-insurance?client_id=<id> -> ILIT policy: death_benefit, annual_premium,
planned_contribution_date, is_existing_policy_transfer, proposed_owner.
GET /api/trust-candidates?client_id=<id> -> asset_value, expected_growth_rate,
grat_term_years, grat_annuity_rate, crat_term_years, crat_payout_rate.
Fetch 2+3 once; fetch 4-8 per client. The local request_memo.md gives the engagement
type and the planning HORIZON YEAR (when relevant) — read it first.
2. Source-Resolution Precedence (the central skill)
Source records disagree after an older CRM import. Resolve by this precedence (later,
signed, system-of-record sources win over stale/marketing ones):
- SIGNED_PROFILE controls client-stated facts (it is the most recent, client-signed
record). Use it for:
annual_non_ira_income, marginal_tax_rate, beneficiary_count,
age, planning_year, filing_status, marital_status, liquid_assets,
estate_value, AND client goals (family_transfer_priority, philanthropic_intent),
AND life-insurance policy determinations. So controlling_profile_source,
controlling_beneficiary_source, controlling_policy_source, and
controlling_goal_source are all SIGNED_PROFILE.
- CUSTODIAN_EXPORT controls account balances — traditional_balance, roth_balance,
expected_return, rmd_start_age, recommended_conversion_years.
controlling_account_source = CUSTODIAN_EXPORT.
- ATTORNEY_MEMO controls trust / estate-asset facts — the trust funding asset_value
and estate-asset determinations.
controlling_asset_source = ATTORNEY_MEMO.
- CRM_NOTE and STALE_MARKETING_INTAKE never control — they are the stale import;
ignore their numbers (e.g., older income, older beneficiary_count) when a signed/
custodian/attorney record exists for the same fact.
Default the source_resolution output fields accordingly. When SIGNED_PROFILE and
ATTORNEY_MEMO agree on a goal, the controlling source is still SIGNED_PROFILE (client
goals), NOT the attorney memo. Policy source is SIGNED_PROFILE, not ATTORNEY_MEMO.
3. Analysis Type: roth_conversion_rmd
Source values: income/marginal_rate/age/beneficiary from SIGNED_PROFILE; balances and
recommended_conversion_years from CUSTODIAN_EXPORT; horizon_year from the request memo.
Formulas:
bracket_room = conversion_bracket_targets[filing_status] - annual_non_ira_income.
(Uses SIGNED_PROFILE income; do not subtract RMD or any other income.)
annual_conversion_amount = min(bracket_room, traditional_balance / recommended_conversion_years).
first_conversion_year = planning_year; conversion_years = recommended_conversion_years;
conversion_years_positive = count of years with positive conversion (all of them when
the balance outlasts the plan — the usual case).
total_converted = annual_conversion_amount * conversion_years.
total_conversion_tax = total_converted * marginal_tax_rate.
first_rmd_year = planning_year + (rmd_start_age - age).
(rmd_start_age is 73 in this environment.)
horizon_year = the year stated in the request memo.
Year-by-year projection (planning_year .. horizon_year INCLUSIVE). Maintain a traditional
balance (start = traditional_balance) and a Roth balance (start = roth_balance, which may
already be > 0). For each year Y in that range, age = age0 + (Y - planning_year):
- If Y is a conversion year (planning_year .. planning_year+conversion_years-1):
traditional -= annual_conversion_amount; roth += annual_conversion_amount.
(Conversions can overlap RMD years — apply the conversion first.)
- If age >= rmd_start_age and Y >= first_rmd_year and age is in the factor table:
rmd = traditional / rmd_factor[age]; rmd_tax += rmd * marginal_tax_rate; traditional -= rmd.
- Grow:
traditional *= (1 + expected_return); roth *= (1 + expected_return).
Apply growth AFTER the year's transactions, in every year including the horizon year.
baseline_rmd_tax_through_horizon = rmd_tax from the simulation with NO conversions
(balance just grows, RMDs from 73..horizon).
conversion_rmd_tax_through_horizon = rmd_tax from the simulation WITH conversions.
rmd_tax_savings_through_horizon = baseline - conversion.
projected_roth_balance_horizon = Roth balance at horizon (conversion case; includes any
pre-existing roth_balance grown plus conversions grown).
projected_traditional_balance_horizon = traditional balance at horizon (conversion case).
heir_tax_profile: compare the two horizon balances. If Roth is clearly larger than
Traditional (roughly >1.5x) -> MOSTLY_TAX_FREE. If Traditional is clearly larger than
Roth -> MOSTLY_TAXABLE. If they are close/balanced (e.g., ~55/45 split) ->
MIXED_TAXABLE_AND_TAX_FREE.
Recommendation:
primary_action = STAGED_ROTH_CONVERSION when a conversion plan is being run.
suitability = SUITABLE whenever conversions are viable (bracket room > 0 and balance
- — including near-RMD cases. Keep SUITABLE; do NOT downgrade to BORDERLINE just
because RMDs are close.
risk_flag: TAX_BRACKET_MANAGEMENT when RMDs are far off (multiple years before
rmd_start_age); RMD_NEAR_TERM when the client is at/within ~1 year of rmd_start_age.
The near-RMD signal lives in risk_flag, NOT in suitability.
Round every USD field to cents. Use JSON numbers, never strings.
4. Analysis Type: ilit_crummey_implementation
Source values: beneficiary_count from SIGNED_PROFILE; annual_premium, death_benefit,
planned_contribution_date, is_existing_policy_transfer from life-insurance; gift
exclusion from tax policy for the planning year.
Formulas:
planning_year = SIGNED_PROFILE planning_year.
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 annual_premium.
premium_gap = max(0, annual_premium - annual_exclusion_capacity).
CLAMP to 0 — when the premium is below exclusion capacity there is no shortfall, so the
gap is 0 (do NOT report a raw negative number).
notices_required = beneficiary_count (one Crummey notice per beneficiary).
- Administration dates — all offsets from
planned_contribution_date (the contribution_date):
contribution_date = planned_contribution_date (ISO).
notice_due_date = contribution_date + 7 days.
withdrawal_window_end = contribution_date + 30 days.
earliest_premium_payment_date = contribution_date + 1 day.
Compute with real calendar arithmetic; the +7/+30/+1 are all measured from the
contribution_date (do NOT chain them).
dedicated_bank_account_required = true.
estate_result:
death_benefit = policy death_benefit.
estate_inclusion_risk: LOW_IF_FORMALITIES_MET if the policy is new
(is_existing_policy_transfer = false) AND premium <= capacity; else EXCLUSION_SHORTFALL
if premium > capacity; THREE_YEAR_LOOKBACK if it is an existing-policy transfer;
THREE_YEAR_LOOKBACK_AND_EXCLUSION_SHORTFALL if both.
projected_outside_estate_if_implemented = death_benefit (the ILIT death benefit passes
outside the gross estate when formalities are met).
tax_liquidity_support = death_benefit (the liquidity the ILIT provides). Do NOT replace
this with the computed estate-tax liability.
Recommendation:
primary_action: FUND_WITH_CRUMMEY_NOTICES when premium <= capacity and new policy;
USE_LIFETIME_EXEMPTION_FOR_SHORTFALL when premium > capacity; lookback variants when
is_existing_policy_transfer.
suitability = SUITABLE_WITH_ADMINISTRATION.
risk_flag = LOW_IF_FORMALITIES_MET for the clean new-policy case.
source_resolution: controlling_beneficiary_source = SIGNED_PROFILE,
controlling_policy_source = SIGNED_PROFILE.
5. Analysis Type: trust_comparison (GRAT vs CRAT)
Source values: asset_value, growth rate, GRAT/CRAT terms and rates from trust-candidates;
family_transfer_priority / philanthropic_intent (goals) from SIGNED_PROFILE; estate_value
and liquid_assets from SIGNED_PROFILE (matches attorney memo); death_benefit from
life-insurance.
estate_context (this model applies wherever estate_context appears):
taxable_estate = estate_value (the GROSS estate_value; do NOT subtract the exemption here).
estate_tax_exposure = (estate_value - estate_tax_exemption[planning_year]) * estate_tax_rate.
(Exemption is applied in THIS step.)
liquidity_gap_before_planning = estate_tax_exposure - liquid_assets - death_benefit.
INCLUDE the life-insurance death benefit as available liquidity, and report the RAW
result (it may be negative — do not clamp to 0).
GRAT:
term_years = grat_term_years.
- `projected_remainder_to_heirs = asset_value * (1 + expected_growth_rate)^grat_term_years
- asset_value * grat_annuity_rate * grat_term_years`.
Use this SIMPLE formula (projected growth minus nominal flat payouts). Do NOT use a
year-by-year corpus-reducing annuity model — that over-withdraws and loses score.
estimated_estate_tax_reduction = projected_remainder_to_heirs * estate_tax_rate.
mortality_inclusion_risk = TERM_SURVIVAL_REQUIRED.
CRAT:
term_years = crat_term_years (clamp to max_crat_term_years if needed; here it is 20).
- `projected_charitable_remainder = asset_value * (1 + expected_growth_rate)^crat_term_years
- asset_value * crat_payout_rate * crat_term_years` (same simple formula).
estimated_income_tax_deduction = asset_value * charitable_deduction_rate.
family_transfer_fit = LOW (a CRAT sends the remainder to charity; principal does not
transfer to family).
Recommendation:
preferred_strategy: GRAT when family_transfer_priority is high (family transfer wins);
CRAT when philanthropic_intent is high.
rationale_code: CHILDREN_TRANSFER_PRIORITY (GRAT) or PHILANTHROPIC_PRIORITY (CRAT).
alternate_role: the non-preferred strategy's role —
SECONDARY_CHARITABLE_TOOL when GRAT is preferred (CRAT serves as secondary charitable);
SECONDARY_FAMILY_TRANSFER_TOOL when CRAT is preferred.
source_resolution: controlling_goal_source = SIGNED_PROFILE,
controlling_asset_source = ATTORNEY_MEMO.
6. Analysis Type: estate_liquidity_action_plan
Combines estate_context, an ILIT block, a trust_transfer block, and an action_set.
- estate_context: same model as section 5 (taxable_estate = gross; estate_tax_exposure =
(gross - exemption)*rate; liquidity_gap = estate_tax_exposure - liquid - death_benefit, raw).
- ilit:
annual_exclusion_capacity, premium_gap = max(0, premium - capacity),
estate_inclusion_risk (as in section 4), projected_outside_estate_if_implemented = death_benefit.
- trust_transfer:
preferred_strategy (GRAT if family_transfer_priority=high), with the
SIMPLE-formula projected_remainder_to_heirs and projected_charitable_remainder
(CRAT), and estimated_estate_tax_reduction = projected_remainder_to_heirs * estate_tax_rate.
action_set: a JSON array of action enums, SORTED ALPHABETICALLY. Available enums:
ATTORNEY_DRAFT_REVIEW, CRAT_FOR_CHARITABLE_REMAINDER, GRAT_FOR_APPRECIATING_SHARES,
ILIT_CRUMMEY_NOTICE_CYCLE, LIFETIME_EXEMPTION_ALLOCATION.
For a COMBINE_ILIT_AND_GRAT recommendation (family transfer priority high, ILIT
premium within exclusion capacity), the set is exactly:
["ATTORNEY_DRAFT_REVIEW", "GRAT_FOR_APPRECIATING_SHARES", "ILIT_CRUMMEY_NOTICE_CYCLE"].
Do NOT add LIFETIME_EXEMPTION_ALLOCATION when the ILIT premium is already covered by
annual exclusion (no shortfall). Do NOT add CRAT_FOR_CHARITABLE_REMAINDER when the
chosen trust strategy is GRAT (philanthropic intent is low).
- Recommendation:
primary_action = COMBINE_ILIT_AND_GRAT;
sequencing = ILIT_FIRST_THEN_GRAT; risk_flag = LOW_IF_FORMALITIES_MET
(clean new-policy ILIT, premium within capacity).
- source_resolution:
controlling_goal_source = SIGNED_PROFILE,
controlling_policy_source = SIGNED_PROFILE.
7. Precision and formatting rules (apply to every analysis type)
- Every USD field is a JSON number rounded to CENTS (2 decimals). No string numbers.
- Dates are ISO
YYYY-MM-DD strings; compute with real calendar-day arithmetic.
action_set must be sorted alphabetically (lexicographic).
- Enum values must match the answer template exactly (case and underscores).
task_id mirrors the task identifier; client_id is the stable client id; analysis_type
is the per-task enum.
- top-level required keys must all be present.
8. Common mistakes to avoid
- Reporting
premium_gap as a raw negative when premium < capacity: clamp to 0.
- Setting
tax_liquidity_support to the estate-tax liability: it is the death_benefit.
- Using a year-by-year corpus-reducing annuity model for GRAT/CRAT remainders: use the
simple
projected - nominal_payouts formula.
- Setting
earliest_premium_payment_date to withdrawal_window_end + 1: it is
contribution_date + 1 (all Crummey offsets +7/+30/+1 are from the contribution_date).
- Subtracting the estate-tax exemption from
taxable_estate: taxable_estate is the gross
estate_value; the exemption is applied only in estate_tax_exposure.
- Forgetting the life-insurance death_benefit in
liquidity_gap_before_planning, or
clamping a negative gap to 0: include the death benefit and report the raw value.
- Adding
LIFETIME_EXEMPTION_ALLOCATION to action_set when the ILIT premium is within
annual exclusion capacity.
- Downgrading
suitability to BORDERLINE for near-RMD conversions: keep SUITABLE and
signal the near-term RMD via risk_flag = RMD_NEAR_TERM.
- Using
ATTORNEY_MEMO for policy or goal sources: policy and goals are controlled by
SIGNED_PROFILE. ATTORNEY_MEMO controls trust/estate ASSET facts only
(controlling_asset_source).
- Trusting stale CRM/marketing numbers (income, beneficiary_count, goals) over the
signed/custodian/attorney records.
9. Numbered SOP per task
- Read the local
request_memo.md and prompt.txt to get the client id, engagement
(analysis_type), and planning horizon_year.
- Read
answer_template.json to learn the exact required keys and enum values.
- Fetch tax policy and RMD factors (cache).
- Fetch client base record, source-documents, retirement-accounts, life-insurance,
trust-candidates for the client.
- Resolve every contested fact by the section-2 precedence; set the
source_resolution
fields.
- Run the formulas for the analysis_type (sections 3-6). Compute with calendar-day
arithmetic for dates and full floating-point for money, then round to cents.
- Assemble the JSON object with all required top-level keys and enums matching the template.
- Output ONLY the final JSON object — no prose, no trailing text.
1---2name: reflect-3-attempt-03-153description: SKILL: Private Wealth Advisory Structured Output4---5# SKILL: Private Wealth Advisory Structured Output67Personal financial advisory planning over a remote advisory API. Each task asks for a8strict JSON object (per an answer template) summarizing one of four analysis types:9roth_conversion_rmd, ilit_crummey_implementation, trust_comparison, or10estate_liquidity_action_plan. The advisory environment holds CONFLICTING source records11imported from different systems; the core skill is resolving which source controls each12fact, then computing precisely (USD to cents, ISO dates, sorted lists, exact formulas).1314## 1. Remote API Workflow (endpoint order)1516Base URL is supplied by the harness (`API_BASE`). All endpoints are GET; data is JSON.17181. `GET /api/health` -> confirm `{"ok": true}`.192. `GET /api/policies/tax` -> planning constants (read once, cache):20 - `annual_gift_exclusion` (by year; 2026 = 20000)21 - `estate_tax_exemption` (by year; 2026 = 13610000)22 - `estate_tax_rate` (0.4)23 - `conversion_bracket_targets` by filing status (MFJ=394600, SINGLE=197300, HOH=263500)24 - `max_crat_term_years` (20)25 - `charitable_deduction_rate` (0.35)263. `GET /api/rmd-factors` -> age -> RMD divisor table (keys are ages 73..99 as strings).274. `GET /api/clients/<client_id>` -> base record (household, age, marital/filing status,28 planning_year, estate_value, liquid_assets).295. `GET /api/source-documents?client_id=<id>` -> the conflicting sources (CRM_NOTE,30 ATTORNEY_MEMO, SIGNED_PROFILE, sometimes STALE_MARKETING_INTAKE), each with an31 `effective_date` and a `facts` map. ALWAYS fetch this before deciding any contested fact.326. `GET /api/retirement-accounts?client_id=<id>` -> traditional/Roth balances, expected33 return, rmd_start_age, recommended_conversion_years (source_type = CUSTODIAN_EXPORT).347. `GET /api/life-insurance?client_id=<id>` -> ILIT policy: death_benefit, annual_premium,35 planned_contribution_date, is_existing_policy_transfer, proposed_owner.368. `GET /api/trust-candidates?client_id=<id>` -> asset_value, expected_growth_rate,37 grat_term_years, grat_annuity_rate, crat_term_years, crat_payout_rate.3839Fetch 2+3 once; fetch 4-8 per client. The local `request_memo.md` gives the engagement40type and the planning HORIZON YEAR (when relevant) — read it first.4142## 2. Source-Resolution Precedence (the central skill)4344Source records disagree after an older CRM import. Resolve by this precedence (later,45signed, system-of-record sources win over stale/marketing ones):4647- **SIGNED_PROFILE controls client-stated facts** (it is the most recent, client-signed48 record). Use it for: `annual_non_ira_income`, `marginal_tax_rate`, `beneficiary_count`,49 `age`, `planning_year`, `filing_status`, `marital_status`, `liquid_assets`,50 `estate_value`, AND client goals (`family_transfer_priority`, `philanthropic_intent`),51 AND life-insurance policy determinations. So `controlling_profile_source`,52 `controlling_beneficiary_source`, `controlling_policy_source`, and53 `controlling_goal_source` are all `SIGNED_PROFILE`.54- **CUSTODIAN_EXPORT controls account balances** — traditional_balance, roth_balance,55 expected_return, rmd_start_age, recommended_conversion_years.56 `controlling_account_source` = `CUSTODIAN_EXPORT`.57- **ATTORNEY_MEMO controls trust / estate-asset facts** — the trust funding asset_value58 and estate-asset determinations. `controlling_asset_source` = `ATTORNEY_MEMO`.59- **CRM_NOTE and STALE_MARKETING_INTAKE never control** — they are the stale import;60 ignore their numbers (e.g., older income, older beneficiary_count) when a signed/61 custodian/attorney record exists for the same fact.6263Default the `source_resolution` output fields accordingly. When SIGNED_PROFILE and64ATTORNEY_MEMO agree on a goal, the controlling source is still SIGNED_PROFILE (client65goals), NOT the attorney memo. Policy source is SIGNED_PROFILE, not ATTORNEY_MEMO.6667## 3. Analysis Type: roth_conversion_rmd6869Source values: income/marginal_rate/age/beneficiary from SIGNED_PROFILE; balances and70recommended_conversion_years from CUSTODIAN_EXPORT; horizon_year from the request memo.7172Formulas:73- `bracket_room = conversion_bracket_targets[filing_status] - annual_non_ira_income`.74 (Uses SIGNED_PROFILE income; do not subtract RMD or any other income.)75- `annual_conversion_amount = min(bracket_room, traditional_balance / recommended_conversion_years)`.76- `first_conversion_year = planning_year`; `conversion_years = recommended_conversion_years`;77 `conversion_years_positive` = count of years with positive conversion (all of them when78 the balance outlasts the plan — the usual case).79- `total_converted = annual_conversion_amount * conversion_years`.80- `total_conversion_tax = total_converted * marginal_tax_rate`.81- `first_rmd_year = planning_year + (rmd_start_age - age)`.82 (rmd_start_age is 73 in this environment.)83- `horizon_year` = the year stated in the request memo.8485Year-by-year projection (planning_year .. horizon_year INCLUSIVE). Maintain a traditional86balance (start = traditional_balance) and a Roth balance (start = roth_balance, which may87already be > 0). For each year Y in that range, age = age0 + (Y - planning_year):88 1. If Y is a conversion year (planning_year .. planning_year+conversion_years-1):89 `traditional -= annual_conversion_amount; roth += annual_conversion_amount`.90 (Conversions can overlap RMD years — apply the conversion first.)91 2. If age >= rmd_start_age and Y >= first_rmd_year and age is in the factor table:92 `rmd = traditional / rmd_factor[age]; rmd_tax += rmd * marginal_tax_rate;93 traditional -= rmd`.94 3. Grow: `traditional *= (1 + expected_return); roth *= (1 + expected_return)`.95 Apply growth AFTER the year's transactions, in every year including the horizon year.96- `baseline_rmd_tax_through_horizon` = rmd_tax from the simulation with NO conversions97 (balance just grows, RMDs from 73..horizon).98- `conversion_rmd_tax_through_horizon` = rmd_tax from the simulation WITH conversions.99- `rmd_tax_savings_through_horizon = baseline - conversion`.100- `projected_roth_balance_horizon` = Roth balance at horizon (conversion case; includes any101 pre-existing roth_balance grown plus conversions grown).102- `projected_traditional_balance_horizon` = traditional balance at horizon (conversion case).103- `heir_tax_profile`: compare the two horizon balances. If Roth is clearly larger than104 Traditional (roughly >1.5x) -> `MOSTLY_TAX_FREE`. If Traditional is clearly larger than105 Roth -> `MOSTLY_TAXABLE`. If they are close/balanced (e.g., ~55/45 split) ->106 `MIXED_TAXABLE_AND_TAX_FREE`.107108Recommendation:109- `primary_action` = `STAGED_ROTH_CONVERSION` when a conversion plan is being run.110- `suitability` = `SUITABLE` whenever conversions are viable (bracket room > 0 and balance111 > 0) — including near-RMD cases. Keep SUITABLE; do NOT downgrade to BORDERLINE just112 because RMDs are close.113- `risk_flag`: `TAX_BRACKET_MANAGEMENT` when RMDs are far off (multiple years before114 rmd_start_age); `RMD_NEAR_TERM` when the client is at/within ~1 year of rmd_start_age.115 The near-RMD signal lives in `risk_flag`, NOT in `suitability`.116117Round every USD field to cents. Use JSON numbers, never strings.118119## 4. Analysis Type: ilit_crummey_implementation120121Source values: beneficiary_count from SIGNED_PROFILE; annual_premium, death_benefit,122planned_contribution_date, is_existing_policy_transfer from life-insurance; gift123exclusion from tax policy for the planning year.124125Formulas:126- `planning_year` = SIGNED_PROFILE planning_year.127- `annual_exclusion_per_beneficiary = annual_gift_exclusion[planning_year]`.128- `beneficiary_count` = SIGNED_PROFILE value.129- `annual_exclusion_capacity = annual_exclusion_per_beneficiary * beneficiary_count`.130- `annual_premium` = policy annual_premium.131- `premium_gap = max(0, annual_premium - annual_exclusion_capacity)`.132 CLAMP to 0 — when the premium is below exclusion capacity there is no shortfall, so the133 gap is 0 (do NOT report a raw negative number).134- `notices_required = beneficiary_count` (one Crummey notice per beneficiary).135- Administration dates — all offsets from `planned_contribution_date` (the contribution_date):136 - `contribution_date` = planned_contribution_date (ISO).137 - `notice_due_date` = contribution_date + 7 days.138 - `withdrawal_window_end` = contribution_date + 30 days.139 - `earliest_premium_payment_date` = contribution_date + 1 day.140 Compute with real calendar arithmetic; the +7/+30/+1 are all measured from the141 contribution_date (do NOT chain them).142- `dedicated_bank_account_required = true`.143144estate_result:145- `death_benefit` = policy death_benefit.146- `estate_inclusion_risk`: `LOW_IF_FORMALITIES_MET` if the policy is new147 (is_existing_policy_transfer = false) AND premium <= capacity; else `EXCLUSION_SHORTFALL`148 if premium > capacity; `THREE_YEAR_LOOKBACK` if it is an existing-policy transfer;149 `THREE_YEAR_LOOKBACK_AND_EXCLUSION_SHORTFALL` if both.150- `projected_outside_estate_if_implemented = death_benefit` (the ILIT death benefit passes151 outside the gross estate when formalities are met).152- `tax_liquidity_support = death_benefit` (the liquidity the ILIT provides). Do NOT replace153 this with the computed estate-tax liability.154155Recommendation:156- `primary_action`: `FUND_WITH_CRUMMEY_NOTICES` when premium <= capacity and new policy;157 `USE_LIFETIME_EXEMPTION_FOR_SHORTFALL` when premium > capacity; lookback variants when158 is_existing_policy_transfer.159- `suitability` = `SUITABLE_WITH_ADMINISTRATION`.160- `risk_flag` = `LOW_IF_FORMALITIES_MET` for the clean new-policy case.161162source_resolution: `controlling_beneficiary_source = SIGNED_PROFILE`,163`controlling_policy_source = SIGNED_PROFILE`.164165## 5. Analysis Type: trust_comparison (GRAT vs CRAT)166167Source values: asset_value, growth rate, GRAT/CRAT terms and rates from trust-candidates;168family_transfer_priority / philanthropic_intent (goals) from SIGNED_PROFILE; estate_value169and liquid_assets from SIGNED_PROFILE (matches attorney memo); death_benefit from170life-insurance.171172estate_context (this model applies wherever estate_context appears):173- `taxable_estate = estate_value` (the GROSS estate_value; do NOT subtract the exemption here).174- `estate_tax_exposure = (estate_value - estate_tax_exemption[planning_year]) * estate_tax_rate`.175 (Exemption is applied in THIS step.)176- `liquidity_gap_before_planning = estate_tax_exposure - liquid_assets - death_benefit`.177 INCLUDE the life-insurance death benefit as available liquidity, and report the RAW178 result (it may be negative — do not clamp to 0).179180GRAT:181- `term_years` = grat_term_years.182- `projected_remainder_to_heirs = asset_value * (1 + expected_growth_rate)^grat_term_years183 - asset_value * grat_annuity_rate * grat_term_years`.184 Use this SIMPLE formula (projected growth minus nominal flat payouts). Do NOT use a185 year-by-year corpus-reducing annuity model — that over-withdraws and loses score.186- `estimated_estate_tax_reduction = projected_remainder_to_heirs * estate_tax_rate`.187- `mortality_inclusion_risk = TERM_SURVIVAL_REQUIRED`.188189CRAT:190- `term_years` = crat_term_years (clamp to max_crat_term_years if needed; here it is 20).191- `projected_charitable_remainder = asset_value * (1 + expected_growth_rate)^crat_term_years192 - asset_value * crat_payout_rate * crat_term_years` (same simple formula).193- `estimated_income_tax_deduction = asset_value * charitable_deduction_rate`.194- `family_transfer_fit = LOW` (a CRAT sends the remainder to charity; principal does not195 transfer to family).196197Recommendation:198- `preferred_strategy`: `GRAT` when family_transfer_priority is high (family transfer wins);199 `CRAT` when philanthropic_intent is high.200- `rationale_code`: `CHILDREN_TRANSFER_PRIORITY` (GRAT) or `PHILANTHROPIC_PRIORITY` (CRAT).201- `alternate_role`: the non-preferred strategy's role —202 `SECONDARY_CHARITABLE_TOOL` when GRAT is preferred (CRAT serves as secondary charitable);203 `SECONDARY_FAMILY_TRANSFER_TOOL` when CRAT is preferred.204205source_resolution: `controlling_goal_source = SIGNED_PROFILE`,206`controlling_asset_source = ATTORNEY_MEMO`.207208## 6. Analysis Type: estate_liquidity_action_plan209210Combines estate_context, an ILIT block, a trust_transfer block, and an action_set.211212- estate_context: same model as section 5 (taxable_estate = gross; estate_tax_exposure =213 (gross - exemption)*rate; liquidity_gap = estate_tax_exposure - liquid - death_benefit, raw).214- ilit: `annual_exclusion_capacity`, `premium_gap = max(0, premium - capacity)`,215 `estate_inclusion_risk` (as in section 4), `projected_outside_estate_if_implemented = death_benefit`.216- trust_transfer: `preferred_strategy` (GRAT if family_transfer_priority=high), with the217 SIMPLE-formula `projected_remainder_to_heirs` and `projected_charitable_remainder`218 (CRAT), and `estimated_estate_tax_reduction = projected_remainder_to_heirs * estate_tax_rate`.219- `action_set`: a JSON array of action enums, SORTED ALPHABETICALLY. Available enums:220 `ATTORNEY_DRAFT_REVIEW`, `CRAT_FOR_CHARITABLE_REMAINDER`, `GRAT_FOR_APPRECIATING_SHARES`,221 `ILIT_CRUMMEY_NOTICE_CYCLE`, `LIFETIME_EXEMPTION_ALLOCATION`.222 For a `COMBINE_ILIT_AND_GRAT` recommendation (family transfer priority high, ILIT223 premium within exclusion capacity), the set is exactly:224 `["ATTORNEY_DRAFT_REVIEW", "GRAT_FOR_APPRECIATING_SHARES", "ILIT_CRUMMEY_NOTICE_CYCLE"]`.225 Do NOT add `LIFETIME_EXEMPTION_ALLOCATION` when the ILIT premium is already covered by226 annual exclusion (no shortfall). Do NOT add `CRAT_FOR_CHARITABLE_REMAINDER` when the227 chosen trust strategy is GRAT (philanthropic intent is low).228- Recommendation: `primary_action = COMBINE_ILIT_AND_GRAT`;229 `sequencing = ILIT_FIRST_THEN_GRAT`; `risk_flag = LOW_IF_FORMALITIES_MET`230 (clean new-policy ILIT, premium within capacity).231- source_resolution: `controlling_goal_source = SIGNED_PROFILE`,232 `controlling_policy_source = SIGNED_PROFILE`.233234## 7. Precision and formatting rules (apply to every analysis type)235236- Every USD field is a JSON number rounded to CENTS (2 decimals). No string numbers.237- Dates are ISO `YYYY-MM-DD` strings; compute with real calendar-day arithmetic.238- `action_set` must be sorted alphabetically (lexicographic).239- Enum values must match the answer template exactly (case and underscores).240- `task_id` mirrors the task identifier; `client_id` is the stable client id; `analysis_type`241 is the per-task enum.242- top-level required keys must all be present.243244## 8. Common mistakes to avoid245246- Reporting `premium_gap` as a raw negative when premium < capacity: clamp to 0.247- Setting `tax_liquidity_support` to the estate-tax liability: it is the death_benefit.248- Using a year-by-year corpus-reducing annuity model for GRAT/CRAT remainders: use the249 simple `projected - nominal_payouts` formula.250- Setting `earliest_premium_payment_date` to `withdrawal_window_end + 1`: it is251 `contribution_date + 1` (all Crummey offsets +7/+30/+1 are from the contribution_date).252- Subtracting the estate-tax exemption from `taxable_estate`: `taxable_estate` is the gross253 estate_value; the exemption is applied only in `estate_tax_exposure`.254- Forgetting the life-insurance death_benefit in `liquidity_gap_before_planning`, or255 clamping a negative gap to 0: include the death benefit and report the raw value.256- Adding `LIFETIME_EXEMPTION_ALLOCATION` to `action_set` when the ILIT premium is within257 annual exclusion capacity.258- Downgrading `suitability` to `BORDERLINE` for near-RMD conversions: keep `SUITABLE` and259 signal the near-term RMD via `risk_flag = RMD_NEAR_TERM`.260- Using `ATTORNEY_MEMO` for policy or goal sources: policy and goals are controlled by261 `SIGNED_PROFILE`. `ATTORNEY_MEMO` controls trust/estate ASSET facts only262 (`controlling_asset_source`).263- Trusting stale CRM/marketing numbers (income, beneficiary_count, goals) over the264 signed/custodian/attorney records.265266## 9. Numbered SOP per task2672681. Read the local `request_memo.md` and `prompt.txt` to get the client id, engagement269 (analysis_type), and planning horizon_year.2702. Read `answer_template.json` to learn the exact required keys and enum values.2713. Fetch tax policy and RMD factors (cache).2724. Fetch client base record, source-documents, retirement-accounts, life-insurance,273 trust-candidates for the client.2745. Resolve every contested fact by the section-2 precedence; set the `source_resolution`275 fields.2766. Run the formulas for the analysis_type (sections 3-6). Compute with calendar-day277 arithmetic for dates and full floating-point for money, then round to cents.2787. Assemble the JSON object with all required top-level keys and enums matching the template.2798. Output ONLY the final JSON object — no prose, no trailing text.