### Modeling Capabilities

This document summarizes all modeling components in Owl (Optimal Wealth Lab), how each is implemented, and the assumptions and limitations that apply. It serves as a quick reference for understanding the scope and boundaries of the optimizer.

| Component | Modeling approach | Assumptions & limitations |
|------------|--------------------|---------------------------|
| **Objectives** | maxSpending: maximize net spending subject to bequest floor. maxBequest: maximize after-tax bequest subject to spending floor. Roth conversion amounts optimized in both (subject to caps and per-person controls). | — |
| **Spending profile** | User-specified shape (flat or smile) scaling a first-year basis. Survivorship factor at first death. Optimizer determines achievable basis. | Profile shape fixed; only scale is optimized. |
| **Bequest objective** | After-tax estate value. Tax-deferred and HSA balances discounted by heirs' marginal rate. Surviving spouse inherits per beneficiary fractions; non-spouse portion taxed. | Single heirs' marginal tax rate applied to all inherited tax-deferred and HSA balances. |
| **Taxable accounts** | Dividend and interest yield proportional to balance each year; capital gains when optimizer elects to sell. All realized gains treated as long-term. | All gains treated as long-term; short-term gains (holding period &lt; 1 year) not distinguished. Withdrawals assumed to sell most recent purchases first. |
| **Safety net (taxable)** | Optional inflation-indexed minimum balance per individual's taxable account. Enforced from year 2 through each individual's life horizon. | First year excluded. Can cause infeasibility if minimum exceeds initial balance or desired bequest is smaller than survivor's safety net. |
| **Tax-deferred accounts** (401k, IRA, 403b) | Pre-tax contributions from Wages and Contributions table. Withdrawals taxed as ordinary income. RMDs enforced as minimum withdrawal floors from age 70–75 (birth-year dependent). 10% early withdrawal penalty before age 59½. | Pro-rata rule (IRS Form 8606) not modeled; entire balance treated as pre-tax. Early withdrawal exceptions (72(t), disability, etc.) not modeled. |
| **Roth accounts** | After-tax contributions. Five-year maturation rule enforced via minimum-balance constraints (recent conversions + contribution gains retained). Age 59½ threshold per individual. Conversion amounts optimized; taxable as ordinary income in year of conversion. | Contribution principal not separately tracked; some valid early withdrawals of principal conservatively disallowed. Pro-rata rule not modeled. Roth conversions disallowed in last two years of plan horizon. |
| **Health Savings Accounts (HSA)** | Fourth account type. Pre-tax contributions reduce ordinary income, provisional income, and MAGI. Contributions zeroed at Medicare enrollment age (IRC §223: Medicare disqualifies contributions). All withdrawals treated as qualified (tax-free). Spouse inherits intact. | All withdrawals assumed qualified; pre-65 non-qualified penalty (20%) not modeled. IRS contribution limits not enforced; user responsible. HDHP eligibility assumed, not verified. Catch-up (\$1,000 for 55+) not auto-applied. Mid-year Medicare: entire year zeroed (IRS allows proration). |
| **Fixed assets** | Real estate, annuities, collectibles, etc. Disposition generates proceeds split into ordinary income, LTCG, and tax-free portions by asset type. Growth rate from acquisition to disposition year. Sales commission applied. | Fixed outflows; disposition timing and amount user-specified. No optimization of sale timing. |
| **Debts** | Amortized payments from start year for term years. Principal and interest from standard amortization. Enters cash-flow as fixed outflows. | No optimization of paydown vs. invest. Mortgage interest not deducted (standard deduction assumed). |
| **Wages & contributions** | Year-indexed table: wages, other income, net inv, contributions to all account types, Roth conversions, big-ticket items. Five-year lookback for Roth maturation. | User-supplied; no optimization of contribution amounts. HSA contributions zeroed at Medicare age. |
| **Social Security benefits** | PIA × age-based adjustment factor. FRA by birth year (65–67). Own, spousal, and survivor benefits computed from PIA and DOB. First-year proration by fraction of year remaining (same as pension). Taxability (0–85%) from provisional income formula. Optional trim for trust-fund scenarios. | Family maximum benefit cap not modeled. Earnings test not modeled; users assumed fully retired before FRA. Survivor benefits assumed claimed in year of spouse's death; deferral strategy not optimized. WEP and GPO repealed (2025); not modeled. |
| **Pension income** | Monthly amount and commencement age per individual. Optional inflation indexing. First-year proration by fraction of year remaining. Joint-and-survivor fraction for survivor benefit. | Early-commencement reductions and late-commencement credits not modeled. |
| **Ordinary income tax** | Seven brackets (OBBBA 2026: 10–37%). Standard deduction + 65+ additional + OBBBA §1002 bonus (phases out by MAGI). Bracket widths and rates inflation-adjusted. Optional reversion to pre-TCJA rates. | State income taxes not modeled. Itemized deductions not modeled; standard deduction only. OBBBA 65+ bonus phaseout computed outside LP (post-solution update). |
| **Long-term capital gains tax** | Three brackets (0%, 15%, 20%) based on total taxable income. LTCG stacks on ordinary income. Optimizer fills lowest-rate brackets first. Optional: `withLTCG="optimize"` uses exact MILP formulation with binary variables (`zl`) to select the 0%/15%/20% bracket each year. | All realized gains treated as long-term; short-term gains not modeled. |
| **Net Investment Income Tax (NIIT)** | 3.8% on lesser of NII and MAGI excess over \$200k (single) / \$250k (MFJ). NII = dividends, interest, LTCG, rent/trust from `net inv` column. Converged via self-consistent loop. Optional: `withNIIT="optimize"` uses exact MILP formulation with binary variables (`zj`) to determine whether MAGI exceeds the threshold each year; most effective when `withLTCG="optimize"` is also set. | Thresholds not indexed for inflation (per IRS). |
| **Required Minimum Distributions (RMDs)** | IRS Uniform Lifetime Table III for standard cases; IRS Joint and Last Survivor Table II (Pub 590-B) when spouse is the sole beneficiary and more than 10 years younger. Starting age: 70 (pre-1949), 72 (1949–1950), 73 (1951–1959), 75 (1960+). Fractions applied to prior-year-end balance. | Inherited IRA and beneficiary RMD rules not modeled. |
| **Medicare Part B & IRMAA** | Part B premium + IRMAA surcharges from MAGI two years prior. Default: self-consistent loop. Optional: MIP formulation for exact bracket selection; can be disabled for pre-65-only modeling. | Part D IRMAA not modeled (modest underestimate for higher-income households). IRMAA thresholds assumed to scale with general inflation; CMS may use different index. First two plan years require user-supplied prior MAGI (default zero). |
| **ACA marketplace (pre-65)** | Net Premium Tax Credit (PTC) cost: user sets SLCSP benchmark premium; PTC computed from MAGI and FPL. Two modes: **loop** (default) uses SC iteration with year-aware acaCosts; **optimize** uses LP/MIP to co-optimize MAGI vs ACA cost. Below 138% FPL returns full SLCSP (loop) or 2.1% (optimize; Medicaid approximation). | **Loop**: Year-aware (2025/2026 rules). Exact piecewise linear. ACA fixed per MAGI each iteration. **Optimize**: 2026 rules only; no year-awareness. Constant-per-bracket approximation. LP can reduce ACA by shifting MAGI. Above 400% FPL: full SLCSP (both modes). SLCSP user-supplied; FPL updated annually. |
| **Cash-flow balance** | Annual equality: spending + taxes + Medicare + debt payments + contributions = wages + SS + pension + withdrawals + fixed-asset proceeds + other income. All amounts inflation-adjusted (today's dollars). Big-ticket items shift spending into specific years. | Single annual time step; no intra-year cash-flow detail. |
| **Asset allocation** | User-specified glide path (linear or s-curve) from initial to final allocation across four asset classes (S&P 500, corporate bonds, T-notes, cash). Per-account or per-individual or household-wide. | Accounts assumed rebalanced to target allocation. No optimization of allocation itself. |
| **Return rate models** | Constant: trailing-30, user, conservative, optimistic, historical average. Varying: historical (replay), histogaussian, histolognormal, gaussian, lognormal, bootstrap_sor, var, garch_dcc. Custom DataFrame model or pluggable Python modules via API. Optional reverse (time-reversal) and roll sequence transforms for varying methods. | Constant rates: no sequence-of-returns risk. Historical: plan horizon must fit in selected window. Stochastic methods require sufficient history for fitting. |
| **Simulation modes** | Historical back-test: replays past return sequences from selected window. Monte Carlo: stochastic sampling (bootstrap SOR, histogaussian, lognormal, etc.). Fixed-rate: constant or user-supplied returns. | Historical: plan horizon must fit in data window; single deterministic path. Monte Carlo: sequence-of-returns risk; convergence depends on sample size. Historical-range augmented sampling uses reverse × roll combinations. |
| **Filing status** | MFJ until first spouse's death; then single. Standard deduction, brackets, SS thresholds, LTCG thresholds, and Medicare premiums transition automatically. | Head of household not modeled. Death year fixed at plan construction; no stochastic mortality. |
| **Self-consistent (SC) loop** | Iteratively fixes nonlinear quantities (SS taxability, NIIT, LTCG bracket bounds, Medicare IRMAA, OBBBA phaseout) at previous values, solves LP, recomputes, repeats until convergence. | Convergence not guaranteed in edge cases. Optional MIP modes (`withSSTaxability="optimize"`, `withLTCG="optimize"`, `withNIIT="optimize"`, `withACA="optimize"`, `withMedicare="optimize"`) for exact treatment at higher computational cost. |
| **MIP decomposition** | When multiple `"optimize"` flags are active simultaneously, the monolithic MILP may be slow (~400 binary variables). Two decomposition strategies are available via `withDecomposition`. **Sequential** (relax-and-fix): solves LP relaxation, rounds bracket binary families (LTCG → SS taxability → NIIT → Medicare → ACA) sequentially, fixes each before re-solving; fast heuristic. **Benders**: classical Benders decomposition separating bracket selection (master MIP: zl, zm, za, zs, zj) from continuous planning (subproblem LP/MIP: all other vars + zx); generates dual-based optimality cuts to certify global optimality within the specified MIP gap. Both modes fall back to monolithic MIP when no bracket binaries are present. Both HiGHS and MOSEK supported. | Sequential mode is a heuristic (not globally optimal). Benders guarantees global optimality but requires solving 2–3 problems per iteration. Convergence typically occurs in 1–3 Benders iterations in practice. |
| **Beneficiary fractions** | Fraction of each account type left to surviving spouse at first death. Default 1.0 for all (including HSA). When not all 1.0, triggers binary variables for exact modeling. | Can significantly increase solve time when fractions differ across accounts. |

---

*Source: Derived from `papers/owl.tex`, `src/owlplanner/plan.py`, `src/owlplanner/tax2026.py`, and related modules. Tax year 2026 rules.*
