AI CAPEX & the Markets

This tool is a specialized quantitative risk-analysis framework for stress-testing a stylized S&P 500 portfolio against a pullback in AI-related capital expenditure by mega-cap technology firms. Rather than pre-filling results, the prompt instructs the model to write and execute a vectorized Monte Carlo simulation (Geometric Brownian Motion with Itô correction, Merton jump-diffusion, and two-state regime switching), then build the report strictly from the code's actual output and from cited data. It quantifies downside as probabilities, confidence intervals, and risk metrics (VaR, CVaR, maximum drawdown), carries the AI-capex-to-return linkage as an explicit uncertainty sweep, and frames positioning as generic decision frameworks — not individualized financial advice.

Full Prompt

Copy the text below and paste the prompt into your preferred AI conversational search interface.

# AI Capex Market Stress Test — Analyst Prompt

**Prompt vintage:** August 2026. **Report date:** fill in at run time.
**Data-vintage rule:** any figure in §2.1 carrying a "as-supplied" date more than 90 days before your report date is presumed stale. Re-source it or mark it `[stale — not used]`. Do not carry a stale number into the report because it looks plausible.

---

## 0. Operating Contract — read before doing anything

These rules override any instinct to produce a polished-looking answer quickly. Follow them literally.

1. **All numbers must be computed or cited. Never invented.** Every figure in the results, risk-metric, and sensitivity tables must come from code you actually execute in this session. Every figure in the market-context and transmission sections must come from a source you cite. If you can do neither, write `[unverified]` and move on — do not fill the cell with a plausible guess.
2. **Use a code-execution / Python tool.** This task requires running a Monte Carlo simulation. If you have a code interpreter, use it. **If you cannot execute code in this environment, stop and say so explicitly — do not narrate or estimate simulation outputs.** A hand-waved "approximately 45%" is a failure, not an answer.
3. **Declare your environment before you start.** In one short block at the top of your response, state: (a) whether you can execute Python; (b) whether that sandbox has network access; (c) whether you have a separate web-search/retrieval tool; (d) whether you have any historical price data available locally. Everything downstream — especially §9's back-test — depends on these four answers, and pretending to capabilities you lack is the most common failure mode for this task. If the sandbox has no network, hard-code cited figures into the script from a manifest (§3.4) rather than fetching them.
4. **The parameters below are assumptions, not facts.** Treat every μ, σ, correlation, jump loading, and scenario weight as an input to be flagged and pressure-tested, not as established truth. Surface them as assumptions in the report.
5. **Pre-register before you run.** Before executing anything, write 3–5 sentences stating what you expect the simulation to show — direction and rough magnitude of P(bear) across scenarios, and which of the three transmission channels you expect to dominate. Then report where the output contradicted you. This is a required section, not an optional flourish; it is the only defense against retrofitting the narrative to whatever the engine happened to print.
6. **This is an educational exercise, not financial advice.** Recommendations must be presented as decision *frameworks* for hypothetical investor archetypes — never as individualized instructions to buy, sell, or hold specific securities. Include a not-financial-advice disclaimer in your output.
7. **Provenance everywhere.** Tag every number in the report as `[sim]` (produced by code you ran), `[cited]` (with a dated source), `[assumed]` (an input you chose or accepted), or `[unverified]`. §12 requires you to reconcile these tags. No orphan numbers.
8. **Say "interval," not "confidence interval," unless you mean it.** Simulated 5th–95th percentiles are *predictive intervals* from an assumed model. Monte Carlo standard errors are *sampling* uncertainty about your own estimate. These are different quantities and the report must not conflate them; both are required (§4).

If any of these cannot be satisfied, say which and why before producing partial work.

## 1. Objective & Persona

You are a quantitative risk analyst. Your task is to stress-test a stylized S&P 500 portfolio against a disruption in AI-related capital expenditure by mega-cap technology firms, quantify the downside as **probabilities and intervals** (never point predictions), and translate the results into recession-risk and portfolio-positioning analysis.

Deliver: (a) a runnable simulation, (b) its actual outputs, and (c) a written report built strictly on those outputs and on cited data. Lead with uncertainty; the single largest source of it — the AI-capex-to-return linkage — must be carried as a variable throughout, not buried.

**Framing note.** Verify the current direction of AI capex spending yourself (§2.1) rather than assuming a cut: through mid-2026 the observed direction has largely been the opposite of a pullback, with guidance revised upward and the funding mix shifting materially toward external debt and equity. Two consequences for the model: (i) the shock scenarios are *conditional counterfactuals* over a still-expanding base, so state the capex level the cut is applied to; (ii) a **financing channel** is first-class (§2.4a) — the risk that capex continues but is funded by debt into a non-cutting rate environment, which transmits through credit spreads rather than through a spending pause. A stress test that can only represent "they spend less" cannot represent the scenario the market is actually pricing.

---

# PART A — INPUTS (assumptions to verify and flag)

## 2.1 Market-context figures — retrieve as of the report date

**Retrieve each item fresh.** Supplying a number and asking for verification anchors the analysis to the supplied figure, and every one of these is time-varying. The right-hand column gives an order-of-magnitude sanity band only — if your retrieved value falls outside it, that is information, not an error to be corrected toward the band.

| # | Item to retrieve (with date and source) | Sanity band (not a target) |
|---|---|---|
| 1 | Top-10 S&P 500 weight, current + trailing 12m path | 30–45% |
| 2 | Aggregate hyperscaler capex, current calendar year vs. prior, **and whether guidance has been revised up or down in the last two quarters** | $400B–$900B |
| 3 | Per-company current-year capex guidance (AMZN / GOOGL / MSFT / META), with the guidance *range* where companies give one | $100B–$210B each |
| 4 | Share of hyperscaler capex funded by external debt/equity vs. operating cash flow; recent large issuances | — |
| 5 | Hyperscaler aggregate FCF trend and capital intensity (capex / revenue) | — |
| 6 | U.S. share of global equity market cap | 45–60% |
| 7 | Total U.S. market cap / S&P 500 cap | — |
| 8 | FINRA margin debt, latest month | — |
| 9 | Foreign holdings of U.S. equities (Treasury TIC data) | — |
| 10 | Current fed funds target range, **latest FOMC statement date, and the direction of dissents** | — |
| 11 | Equal-weight vs. cap-weight S&P 500 spread, YTD and trailing 12m | — |
| 12 | IG credit spreads and any AI/data-center-linked issuance spread widening | — |

Items 4, 5, 11, and 12 are the ones most likely to be missing from a stale mental model. Verify the direction of policy risk (item 10) before §7 relies on it — do not assume the Fed has cutting room.

**Retrieval discipline:** prefer company filings and earnings-call guidance, FRED/Treasury/FINRA/BEA series, and index-provider factsheets. Do not cite content-farm aggregations of capex totals; several circulate with transcription errors and mutually inconsistent totals. Where credible sources disagree materially (they will, on aggregate capex, because of finance-lease and prepayment treatment), report the range and say which definition each uses.

## 2.2 Portfolio — 10 sleeves (top-9 single names + "Rest of S&P 500")

Weights sum to 1.0; the top-9 sum to 0.3677. **Check this against item 1 above** — if the current top-10 weight has moved more than ~3 points from 36.8%, rescale the sleeves and say so, or run both the supplied and current weightings and report the difference.

| # | Sleeve | Weight | μ (annual) | σ (annual) | Category |
|---|---|---|---|---|---|
| 0 | NVDA | 0.0716 | 0.25 | 0.48 | tech |
| 1 | AAPL | 0.0605 | 0.25 | 0.24 | tech |
| 2 | MSFT | 0.0480 | 0.25 | 0.28 | tech |
| 3 | AMZN | 0.0344 | 0.25 | 0.34 | tech |
| 4 | GOOGL| 0.0596 | 0.25 | 0.31 | tech |
| 5 | META | 0.0261 | 0.25 | 0.38 | tech |
| 6 | AVGO | 0.0249 | 0.25 | 0.41 | tech |
| 7 | TSLA | 0.0253 | 0.25 | 0.56 | tech |
| 8 | BRK.B| 0.0173 | 0.06 | 0.19 | nontech |
| 9 | REST | 0.6323 | 0.06 | 0.22 | broad |

**Assumption flags to carry into the report:**
- **μ is a simple (arithmetic) expected annual return, not a log return.** The engine subtracts ½σ² inside the log-drift accordingly. State this; the two conventions differ by ~11 percentage points a year for NVDA.
- The 25% μ for all eight tech sleeves is a forward-earnings-growth proxy adjusted for elevated valuations. It is optimistic, forward-looking, and **identical across eight names with very different capex exposure** — NVDA is a capex *recipient*, MSFT/AMZN/GOOGL/META are capex *spenders*, and AAPL is largely neither. A capex cut plausibly moves these in opposite directions in the near term. The single-μ treatment is an assumption that biases toward a clean one-directional shock; disclose it, and if you extend the model, differentiate μ by capex role rather than adding more sleeves.
- σ and ρ are backward-looking while μ is forward-looking — an internal inconsistency you must disclose.
- σ values are stated as trailing-252-day realized vol. If you have return data, recompute them and report both; if not, treat them as supplied and say so.
- The index is **fixed-share (buy-and-hold), not rebalanced**: the engine holds share counts constant, so winners' weights drift up within each path. Real cap-weighted indices behave similarly between reconstitutions, but state it.

## 2.3 Correlation structure (factor model)

Single common factor = "AI exposure." Resulting block correlations:

- Intra-tech (NVDA, AAPL, MSFT, AMZN, GOOGL, META, TSLA pairwise): **0.72**
- AVGO ↔ other tech: **0.65**
- Tech ↔ BRK.B: **0.32**; Tech ↔ REST: **0.38**
- AVGO ↔ BRK.B: **0.32**; AVGO ↔ REST: **0.40**
- BRK.B ↔ REST: **0.50**

**Crisis overlay (dynamic correlation):** in the crisis regime, multiply every off-diagonal ρ by (1 + β) with β = 0.30, clip to (−0.999, 0.999), then re-project to the nearest valid (positive-semi-definite, unit-diagonal) correlation matrix. Do not skip the projection; static correlation understates diversification failure.

**Report the realized post-projection matrix, not the intent.** β = 0.30 pushes intra-tech to 0.936 pre-projection; the PSD projection then pulls *every* entry, including ones you did not intend to change. Print the actual crisis matrix the engine uses and the max absolute deviation from the naive ×1.3 target, so the reader sees the stylization that was actually applied.

## 2.4 Scenarios — capex shock transmitted through THREE channels

A drift-only shock barely moves a 1-year distribution: over one year the μ term is small next to diffusion, so cutting μ alone leaves the downside almost unchanged. **You are required to demonstrate this, not assert it** (§4, ablation table). A capex pullback is not merely a lower expected return — it is a risk-regime event. Each scenario transmits the shock through three channels simultaneously:

1. **Drift (μ):** lower expected returns for AI-exposed sleeves.
2. **Volatility (σ):** a scenario-level multiplier on every sleeve's σ (stress widens the whole distribution; this stacks on top of the crisis-regime ×1.5).
3. **Regime/jumps:** deeper scenarios raise both the monthly probability of entering the crisis regime, P(normal→crisis), and the annual jump intensity λ.

**Channel 1 semantics (state explicitly):**
Let `cut` = fractional capex reduction *relative to current guidance* (state the dollar base) and `link` = capex-to-return linkage coefficient.
- Tech μ multiplier = `max(0, 1 − cut × link)`
- "Rest" μ multiplier = `max(0, 1 − 0.5 × cut × link)` (broad market absorbs ~50% of the tech shock)
- BRK.B (nontech) μ is unchanged.

So a 25% cut at link = 1.0 multiplies tech μ by 0.75 and REST μ by 0.875.

| Scenario | Capex cut | σ multiplier | Jump λ (annual) | P(→crisis)/mo | Prob. weight | Narrative |
|---|---|---|---|---|---|---|
| Baseline | 0% | 1.00 | 0.05 | 0.05 | 0.35 | Investment continues at guided pace |
| Modest slowdown | 25% | 1.10 | 0.08 | 0.10 | 0.28 | Capex moderates over 2–3 quarters |
| Sharp pullback | 50% | 1.25 | 0.12 | 0.20 | 0.18 | ROI-driven cut |
| Investment freeze | 75% | 1.50 | 0.18 | 0.35 | 0.07 | Near-halt + credit stress |
| Black swan | 90% | 1.80 | 0.30 | 0.50 | 0.02 | Systemic crisis + intervention |
| **Financed acceleration** | **0% (up)** | **1.20** | **0.10** | **0.15** | **0.10** | **Capex continues, funded by debt; spreads widen, multiples compress** |

The σ multiplier, crisis probability, and the weights themselves are **assumptions**. The weights in particular are pure judgment with no estimator behind them; §4 therefore requires an interval on the blended figure obtained by sampling the weight vector, not a single blended number.

## 2.4a Financing channel

The sixth scenario is not a capex cut and cannot be expressed through the §2.4 semantics. Model it as: tech μ multiplier `1 − spread_shock × duration_proxy` with `spread_shock` as an input in basis points and `duration_proxy` an assumed sensitivity of high-multiple equity to credit spreads; σ multiplier and crisis probability as tabled. Both parameters are `[assumed]` — state them, and include `spread_shock` in the §9 sweep. If you judge this channel too speculative to parameterize, you may omit the scenario, but you must say so and explain why in the limitations section rather than dropping it silently.

## 2.5 Simulation settings

| Setting | Value |
|---|---|
| Horizon | 1 year (252 trading days) |
| Paths | 10,000 (≥) |
| Replications | **≥3 independent seeds per configuration** (report across-seed spread) |
| Time step | daily, Δt = 1/252 |
| RNG seeds | 42, 43, 44 (report them) |
| Reported intervals | 5th/95th and 1st/99th predictive percentiles, **plus Monte Carlo SE on every headline probability** |
| Jump size | μ_J = −5%, σ_J = 3% (downward), Poisson arrivals |
| **Jump structure** | **70% of intensity is a common market-wide jump with per-sleeve loadings; 30% idiosyncratic** (see §3.3) |
| Regime switch | 2-state Markov, monthly: P(normal→crisis) scenario-dependent (0.05→0.50); P(crisis→normal)=0.20; crisis vol ×1.5 |
| σ shock | Scenario-level σ multiplier (1.0→1.8), applied before the crisis ×1.5 stacks on top |
| **Linkage sweep** | Run the **entire** suite at link ∈ {0.5, 0.7, 1.0, 1.5} |

Note the stacking: Black swan gives NVDA an in-crisis annualized σ of 0.48 × 1.8 × 1.5 = 1.30. That is defensible for a two-week panic and not for a year. Report the realized average fraction of days spent in the crisis regime per scenario (the engine returns it) so the reader can see how long the model actually holds that vol.

---

# PART B — METHOD

## 3.1 Model

Per sleeve *i*, log-price evolves under Itô-corrected, jump-compensated GBM with regime-dependent volatility and correlation:

$$ \Delta \ln S_i = \left( \mu_i - \kappa_i - \tfrac{1}{2}\sigma_{i,t}^2 \right)\Delta t \; + \; \sigma_{i,t}\sqrt{\Delta t}\,(L_t \epsilon)_i \; + \; b_i J^c N^c + J_i^{\text{idio}} N_i $$

where:
- $\sigma_{i,t} = \sigma_i$ in the normal regime, $1.5\,\sigma_i$ in crisis.
- $L_t$ is the Cholesky factor of the **regime-appropriate** correlation matrix (normal or crisis-overlay).
- $N^c \sim \text{Poisson}(\lambda_c \Delta t)$ is a **single market-wide** arrival shared by all sleeves within a path, with loading $b_i$; $N_i \sim \text{Poisson}(\lambda_i \Delta t)$ is idiosyncratic. $\lambda_c + \lambda_i = \lambda$.
- Jump sizes $\sim \mathcal{N}(\mu_J, \sigma_J^2)$; for $n$ arrivals in one step the aggregate is $\mathcal{N}(n\mu_J, n\sigma_J^2)$.
- $\kappa_i = \lambda_c\left(e^{b_i\mu_J + \frac12 b_i^2\sigma_J^2} - 1\right) + \lambda_i\left(e^{\mu_J + \frac12\sigma_J^2} - 1\right)$ is the Merton compensator, so jumps do not bias the drift.

Both corrections — the $-\tfrac12\sigma^2$ Itô term **and** the $\kappa$ compensator — are required. Omitting them inflates returns.

## 3.2 Jump structure and regime-timing constraints — do not violate these

1. **Jumps must not be fully idiosyncratic.** Drawing independent Poisson arrivals per sleeve (`size=(n_sims, n)`) lets a crash in NVDA be uncorrelated with a crash in REST. In a 10-sleeve portfolio with 63% in one broad sleeve, independent jumps diversify away almost entirely, and the jump channel would contribute close to nothing to portfolio tail risk — defeating the purpose of having it. The engine splits intensity into a common component (shared arrival, per-sleeve loading) and an idiosyncratic remainder. The 70/30 split and the loadings `b_i` are `[assumed]` and belong in the §9 sweep.
2. **Multi-jump variance must scale correctly.** Computing `normal(μ_J, σ_J) * nj` gives variance $n^2\sigma_J^2$ instead of the correct $n\sigma_J^2$. With λΔt ≈ 10⁻³ multiple arrivals in one step are rare, but the error is present at every jump intensity and material in the Black-swan scenario. Use $n\mu_J + \sqrt{n}\,\sigma_J z$.

The monthly regime check must not fire at `t = 0`, which would let paths begin in crisis before any time has elapsed; start the check at `t = 21`.

## 3.3 Reference implementation — run this exact engine

Verified to execute: one 10,000-path scenario takes ~2 seconds; the full 4 linkages × 6 scenarios × 3 seeds suite runs in roughly 2–4 minutes.

```python
"""AI capex stress test - GBM + systemic/idiosyncratic Merton jumps
   + 2-state regime switching (vol x1.5, dynamic correlation in crisis).
   Vectorized over paths; loops only over the 252 steps."""
import numpy as np

TICKERS  = ['NVDA','AAPL','MSFT','AMZN','GOOGL','META','AVGO','TSLA','BRK.B','REST']
WEIGHTS  = np.array([0.0716,0.0605,0.0480,0.0344,0.0596,0.0261,0.0249,0.0253,0.0173,0.6323])
MU       = np.array([0.25,0.25,0.25,0.25,0.25,0.25,0.25,0.25,0.06,0.06])
SIGMA    = np.array([0.48,0.24,0.28,0.34,0.31,0.38,0.41,0.56,0.19,0.22])
CATEGORY = np.array(['tech']*8 + ['nontech','broad'])
# Loading on the common (systemic) jump factor. ASSUMPTION - sweep it.
JLOAD    = np.array([1.3,1.0,1.1,1.2,1.1,1.2,1.3,1.3,0.5,0.9])

# (name, capex_cut, vol_mult, jump_lambda, p_n2c, prob_weight)
SCENARIOS = [
    ('Baseline',        0.00, 1.00, 0.05, 0.05, 0.35),
    ('Modest -25%',     0.25, 1.10, 0.08, 0.10, 0.28),
    ('Sharp -50%',      0.50, 1.25, 0.12, 0.20, 0.18),
    ('Freeze -75%',     0.75, 1.50, 0.18, 0.35, 0.07),
    ('Black swan -90%', 0.90, 1.80, 0.30, 0.50, 0.02),
    ('Financed accel',  0.00, 1.20, 0.10, 0.15, 0.10),   # see 2.4a; mu handled separately
]


def base_correlation():
    n = len(TICKERS); C = np.eye(n)
    tech = [0,1,2,3,4,5,7]; avgo, brk, rest = 6, 8, 9
    for i in tech:
        for j in tech:
            if i != j: C[i, j] = 0.72
        C[i, avgo] = C[avgo, i] = 0.65
        C[i, brk]  = C[brk, i]  = 0.32
        C[i, rest] = C[rest, i] = 0.38
    C[avgo, brk]  = C[brk, avgo]  = 0.32
    C[avgo, rest] = C[rest, avgo] = 0.40
    C[brk, rest]  = C[rest, brk]  = 0.50
    return C


def nearest_psd(A):
    """Project a symmetric matrix to the nearest PSD correlation matrix."""
    B = (A + A.T) / 2
    vals, vecs = np.linalg.eigh(B)
    vals = np.clip(vals, 1e-8, None)
    B = vecs @ np.diag(vals) @ vecs.T
    d = np.sqrt(np.diag(B))
    B = B / np.outer(d, d)
    np.fill_diagonal(B, 1.0)
    return B


def crisis_correlation(C, beta=0.30):
    Cc = np.clip(C * (1 + beta), -0.999, 0.999)
    np.fill_diagonal(Cc, 1.0)
    return nearest_psd(Cc)


def adjust_mu(mu, category, capex_cut, link):
    out = mu.copy()
    out[category == 'tech']  *= max(0.0, 1 - capex_cut * link)
    out[category == 'broad'] *= max(0.0, 1 - 0.5 * capex_cut * link)
    return out                                   # 'nontech' (BRK.B) unchanged


def simulate(mu, sigma, weights, C_normal, C_crisis,
             n_sims=10000, n_days=252, jump_lambda=0.05, jump_common_share=0.7,
             jload=JLOAD, jump_mu=-0.05, jump_sigma=0.03, crisis_vol_mult=1.5,
             p_n2c=0.05, p_c2n=0.20, seed=42):
    rng = np.random.default_rng(seed)
    n, dt = len(mu), 1/252
    L_n = np.linalg.cholesky(C_normal)
    L_c = np.linalg.cholesky(C_crisis)

    lam_c = jump_lambda * jump_common_share          # market-wide arrivals
    lam_i = jump_lambda * (1 - jump_common_share)    # idiosyncratic arrivals
    kappa = (lam_c * (np.exp(jload*jump_mu + 0.5*(jload**2)*jump_sigma**2) - 1)
             + lam_i * (np.exp(jump_mu + 0.5*jump_sigma**2) - 1))

    logp = np.full((n_sims, n), np.log(100.0))
    idx  = np.empty((n_sims, n_days + 1))
    idx[:, 0] = (weights * np.exp(logp)).sum(axis=1)
    regime = np.zeros(n_sims, dtype=bool)            # False=normal, True=crisis
    crisis_days = np.zeros(n_sims)

    for t in range(n_days):
        if t > 0 and t % 21 == 0:                    # monthly regime transition
            u = rng.random(n_sims)
            to_crisis = (~regime) & (u < p_n2c)
            to_normal = regime & (u < p_c2n)
            regime = (regime & ~to_normal) | to_crisis
        crisis_days += regime

        z  = rng.standard_normal((n_sims, n))
        cz = np.empty_like(z)
        nm = ~regime
        cz[nm]     = z[nm]     @ L_n.T
        cz[regime] = z[regime] @ L_c.T

        sig   = sigma[None, :] * np.where(regime, crisis_vol_mult, 1.0)[:, None]
        drift = (mu[None, :] - kappa[None, :] - 0.5*sig**2) * dt
        diff  = sig * np.sqrt(dt) * cz

        # common jump: one arrival count per path, scaled by per-sleeve loading
        nc = rng.poisson(lam_c * dt, size=n_sims)
        jc = nc*jump_mu + np.sqrt(nc)*jump_sigma*rng.standard_normal(n_sims)
        ni = rng.poisson(lam_i * dt, size=(n_sims, n))
        ji = ni*jump_mu + np.sqrt(ni)*jump_sigma*rng.standard_normal((n_sims, n))
        jump = jload[None, :]*jc[:, None] + ji

        logp += drift + diff + jump
        idx[:, t + 1] = (weights * np.exp(logp)).sum(axis=1)
    return idx, crisis_days / n_days


def metrics(idx):
    r = idx[:, -1] / idx[:, 0] - 1
    run_max = np.maximum.accumulate(idx, axis=1)
    maxdd = ((idx - run_max) / run_max).min(axis=1)
    v95, v99 = np.percentile(r, 5), np.percentile(r, 1)
    n = len(r)
    p_bear = (r <= -0.20).mean()
    return {
        'mean': r.mean(), 'median': np.median(r), 'std': r.std(),
        'p_positive': (r > 0).mean(),
        'p_correction': ((r <= -0.10) & (r > -0.20)).mean(),
        'p_bear': p_bear,
        'se_p_bear': np.sqrt(p_bear*(1-p_bear)/n),   # binomial MC standard error
        'se_mean': r.std()/np.sqrt(n),
        'p_strong_bull': (r > 0.20).mean(),
        'var95': v95, 'var99': v99,
        'cvar95': r[r <= v95].mean(), 'cvar99': r[r <= v99].mean(),
        'median_maxdd': np.median(maxdd), 'p95_maxdd': np.percentile(maxdd, 5),
    }, r


def blended_weight_ci(p_by_scenario, base_weights, alpha=20.0, n_draw=20000, seed=7):
    """Interval on the blended figure from uncertainty in the scenario weights.
       alpha is the Dirichlet concentration: lower = less confident in the weights."""
    rng = np.random.default_rng(seed)
    W = rng.dirichlet(alpha*np.asarray(base_weights), size=n_draw)
    b = W @ np.asarray(p_by_scenario)
    return b.mean(), np.percentile(b, [5, 95])


def run_suite(link, seeds=(42, 43, 44), n_sims=10000, drift_only=False):
    C  = nearest_psd(base_correlation())
    Cc = crisis_correlation(C, beta=0.30)
    rows, pbear, wts = [], [], []
    for name, cut, vmult, lam, pn2c, w in SCENARIOS:
        mu_adj = adjust_mu(MU, CATEGORY, cut, link)
        if drift_only:                       # ablation: channel 1 alone
            vmult, lam, pn2c = 1.00, 0.05, 0.05
        acc = []
        for s in seeds:
            idx, cfrac = simulate(mu_adj, SIGMA*vmult, WEIGHTS, C, Cc,
                                  n_sims=n_sims, jump_lambda=lam, p_n2c=pn2c, seed=s)
            m, _ = metrics(idx)
            m['crisis_frac'] = cfrac.mean()
            acc.append(m)
        agg = {k: float(np.mean([a[k] for a in acc])) for k in acc[0]}
        agg['seed_spread_p_bear'] = float(np.ptp([a['p_bear'] for a in acc]))
        agg['name'] = name
        rows.append(agg); pbear.append(agg['p_bear']); wts.append(w)
    bmean, bci = blended_weight_ci(pbear, wts)
    return rows, bmean, bci


if __name__ == '__main__':
    for link in (0.5, 0.7, 1.0, 1.5):
        rows, bmean, bci = run_suite(link)
        print(f"\n===== LINKAGE = {link} =====")
        for m in rows:
            print(f"{m['name']:16s} mean={m['mean']:+.3f} med={m['median']:+.3f} "
                  f"P(bear)={m['p_bear']:.3f} (se {m['se_p_bear']:.3f}, "
                  f"seed spread {m['seed_spread_p_bear']:.3f}) "
                  f"VaR95={m['var95']:+.3f} CVaR95={m['cvar95']:+.3f} "
                  f"medMaxDD={m['median_maxdd']:+.3f} crisis_frac={m['crisis_frac']:.2f}")
        print(f"Blended P(bear)={bmean:.3f}  90% weight-uncertainty interval "
              f"[{bci[0]:.3f}, {bci[1]:.3f}]")
    rows, _, _ = run_suite(1.0, seeds=(42,), drift_only=True)
    print("\nABLATION - drift channel only, link=1.0:")
    for m in rows:
        print(f"{m['name']:16s} P(bear)={m['p_bear']:.3f} mean={m['mean']:+.3f}")
```

**You may extend the engine** (GARCH vol, historical-bootstrap comparison, per-sleeve output, fan-chart percentiles, KDE/CDF plots, the §2.4a financing channel). If you do, keep the Itô and jump-compensator corrections, keep the common-jump structure, and report what you changed.

## 3.4 Input manifest

Before running, print a manifest: every parameter the engine uses, its value, its provenance tag (`[sim]` / `[cited]` / `[assumed]` / `[unverified]`), and — for cited items — the source and as-of date. Any parameter you changed from the values in this prompt must be listed with the reason. The manifest goes in the report as Appendix D.

## 3.5 Capex–return linkage — the master uncertainty

The mapping "1% capex cut → X% return hit" is the highest-uncertainty assumption in the whole exercise, and it is almost certainly **non-linear** (small cuts may read as efficiency; large cuts signal a broken thesis), **lagged** (cuts may not hit revenue for 4–8 quarters), and **sign-ambiguous across sleeves** (a spender cutting capex may rally while its suppliers fall). The linear, contemporaneous, uniform-sign treatment here is a modeling convenience and the report's dominant weakness. Do not pick one value: run the full suite at link ∈ {0.5, 0.7, 1.0, 1.5}, report all four, and frame the base case as a range.

---

# PART C — DELIVERABLE (report skeleton)

Fill the tables **only** with values your code produced or sources you cited. Leave a cell blank or mark `[unverified]` rather than guessing. Present the link = 1.0 run as the base case and show how conclusions move across the sweep.

**Output budget:** aim for 2,500–4,000 words plus tables. If you must cut, drop in this order: §7, §6's global-transmission note, Appendix C. Never cut §0's environment declaration, the pre-registration, §5, §9's sensitivity table, §10, or §12.

## 0. Environment & pre-registration
Per Operating Contract items 3 and 5. Four lines on capability, then 3–5 sentences of expectations. Do not revise this after seeing results; annotate it instead.

## 1. Executive Summary
- Frame findings as probabilities and intervals: "an X% modeled probability of a 1-year return between Y% and Z%, conditional on the assumptions in §3.4."
- State the central risk and its transmission channels in two sentences.
- Give a decision threshold, e.g. "a rules-based allocator that de-risks when P(≥20% decline) exceeds __% would act at __."
- **Up front:** name the model's biggest limitation (the capex→return linkage) and show how the headline numbers swing across the sweep. If the swing is small relative to the swing from the σ multiplier, say that plainly — it means the model's own headline framing is off.
- Restate: educational, not financial advice.

## 2. Market Context
Using only retrieved/cited figures from §2.1: concentration level and trend, cap-weight vs. equal-weight spread, the capex trajectory **and the direction of recent guidance revisions**, the funding-mix shift and what it implies for the credit channel, capital intensity and FCF compression, current policy rate and the direction of policy risk, and U.S. systemic weight in global markets. Cite every number with an as-of date. Where a previously reported figure has since changed materially, note the old value and the new one — the delta is itself evidence about how fast this thesis moves.

## 3. Methodology
Confirm the engine, the corrections applied, paths, seeds, replications, regime and jump settings, the common/idiosyncratic jump split, and the shock semantics (§2.4, §2.4a). Report which parameters you recomputed vs. accepted as supplied. Reference Appendix D.

## 4. Results — base case (link = 1.0)

| Scenario | P(Bear ≥20%) ± MC SE | Seed spread | P(Correction 10–20%) | P(Positive) | P(Strong Bull >20%) | Median | Mean | Crisis-day fraction |
|---|---|---|---|---|---|---|---|---|
| Baseline | | | | | | | | |
| Modest −25% | | | | | | | | |
| Sharp −50% | | | | | | | | |
| Freeze −75% | | | | | | | | |
| Black swan −90% | | | | | | | | |
| Financed acceleration | | | | | | | | |

**If the across-seed spread exceeds ~3× the binomial MC SE, say so and investigate.** It means path-level dependence (regime persistence) makes your effective sample smaller than 10,000 independent draws, and the binomial SE understates your true uncertainty. Raise path count until the spread stabilizes, or report the across-seed spread as the honest error bar.

**Risk metrics (1-year):**

| Scenario | VaR 95% | VaR 99% | CVaR 95% | CVaR 99% | Median MaxDD | 5th-pct MaxDD |
|---|---|---|---|---|---|---|

**Channel ablation — required.** Re-run each scenario with channel 1 alone (μ adjusted, σ multiplier = 1.0, λ and P(→crisis) at baseline), then with channels 1+2, then all three. Report P(bear) for each:

| Scenario | Drift only | Drift + vol | All three | Share of total effect from channels 2–3 |
|---|---|---|---|---|

This table is the empirical claim behind §2.4's assertion that drift alone is nearly inert. If it turns out drift carries most of the effect, the scenario design is wrong and you should say so.

**Probability-weighted blended outlook:** report the weighted mean return and blended P(bear), **each with the Dirichlet 90% interval on the scenario weights**. A blended point estimate without that interval overstates precision, since the weights are the least-defensible numbers in the entire specification.

**Required visuals** (generated from the simulation, not by hand): return-distribution KDE with −10%/−20% lines; CDF; fan chart of the 10th–90th percentile path band; correlation heatmap of the *realized post-projection* crisis matrix. Label every chart as model output.

## 5. Linkage Sensitivity (headline robustness check)

| Linkage | Sharp −50%: P(Bear) | Sharp −50%: Median | Blended P(Bear) [90% wt. interval] | Blended Mean |
|---|---|---|---|---|
| 0.5 | | | | |
| 0.7 | | | | |
| 1.0 | | | | |
| 1.5 | | | | |

Interpret: how much of the "bear market" conclusion is signal and how much is an artifact of link = 1.0? Compare the linkage-driven range against the σ-multiplier-driven range from §9 and state which assumption is actually doing the work.

## 6. Recession Risk & Transmission (qualitative, cited)
Translate the simulated equity shock into macro channels — wealth effect on consumption, corporate-investment cascade, employment, credit. **Label every multiplier and elasticity as an assumption and cite it** (MPC out of wealth, jobs-per-tech-job, capex share of GDP growth contribution). Do not present derived dollar/job figures as precise; give ranges and show the arithmetic. Include the data-center construction and power-sector employment channel, which is now large enough to matter and is not in the equity sleeves. Add a brief global-transmission note (U.S. weight, cross-market correlation, USD/capital-flow effects) with the same sourcing discipline.

## 7. Mitigating Factors
Policy capacity **measured against the verified current rate and the verified direction of policy risk** — if the Fed is on hold with hawkish dissents and inflation above target, "cutting room" is an assumption that needs defending, not an automatic backstop. Also: valuation support / mean reversion, sector rotation to defensives (with the equal-weight spread as evidence on whether rotation is already underway), buyback capacity given FCF compression, structural resilience. Frame as forces that could compress the simulated downside; quantify only what you can cite.

## 8. Positioning Frameworks (NOT individualized advice)
Open with the not-financial-advice disclaimer. For each hypothetical archetype — long-horizon passive, tactical allocator, growth/high-tolerance, conservative, corporate treasury — describe **how the framework responds to the probability outputs**, e.g. "a rules-based allocator that de-risks when P(bear) crosses a threshold would…". Use illustrative, generic levers (equity/cash/duration tilts, hedging concepts, liquidity buffers). **No specific buy/sell calls, target prices, or stop levels on named securities.** Note explicitly that the framework outputs are only as good as the linkage assumption, so a threshold rule keyed to a modeled probability inherits all of §10.

## 9. Validation & Sensitivity

**Back-test — conditional on §0.** If you have historical return data: fit on one window, simulate the next, compare distributions (KS test) and 95% VaR violation rate (expect ~5%; flag if <3% or >7%). **If you do not have the data, do not skip validation — run the fallback:** simulate from the engine with known parameters, then re-estimate those parameters from the simulated paths and check recovery, and verify VaR coverage by construction on held-out paths. This tests the estimator and the code, not the model's realism, and you must label it as such. Stating "no data available" and stopping is acceptable only if the fallback is also impossible.

**Parameter sensitivity (±10–20% each, one at a time, effect on P(bear)):** tech μ, tech σ, intra-tech ρ, linkage, scenario σ multiplier, crisis-entry probability, **common-jump share, jump loadings b_i, and crisis correlation β**. Rank the parameters by effect size and present the ranking as the headline of this section. The expectation is that the σ multiplier and crisis probability dominate — if they do, the report's central finding is a statement about your volatility assumptions, not about AI capex, and the executive summary must say so.

**Model comparison:** if feasible, contrast GBM with a historical bootstrap and note where fat tails diverge.

## 10. Limitations (state plainly, up front and here)
- GBM normality understates fat tails and volatility clustering; jumps and regimes only partially fix this.
- Correlations are unstable in stress; the crisis overlay is a stylization, and the PSD projection alters entries beyond the intended ones.
- The capex→return linkage is uncertain, non-linear, lagged, and modeled with a uniform sign across sleeves that in reality have opposing exposures. This is the dominant risk to every conclusion.
- Scenario probability weights are judgment, not estimates; the Dirichlet interval quantifies the arithmetic consequence, not the judgment error.
- "Rest of S&P 500" as one sleeve hides sector dispersion and rotation.
- Macro variables (rates, inflation, GDP, credit spreads) are exogenous; the financing channel is a reduced-form stand-in for a mechanism the model does not represent.
- Behavioral amplification (forced deleveraging, herding, passive-flow reflexivity) is absent, so severe-scenario probabilities are likely lower bounds.
- Parameters are static over the horizon. Re-run quarterly, since the §2.1 inputs move quickly.

## 11. Conclusion
Tie back to probabilities and the linkage sweep. State clearly what would change the assessment (observed revenue guidance, a guidance cut at any of the four spenders, spread widening on AI-linked issuance) and what to monitor (capex guidance revisions in both directions, credit spreads, funding mix, VIX, concentration, equal-weight spread). Close with the disclaimer.

## 12. Provenance reconciliation (required, last)
A single table listing every distinct number that appears in the report, its provenance tag, and its source or the code cell that produced it. Then a one-line count: how many `[sim]`, `[cited]`, `[assumed]`, `[unverified]`. If any `[unverified]` figure appears in the executive summary, move it out or delete it.

---

## Appendix A — equations
Discretized multi-asset GBM with Itô correction; Merton jump-diffusion with the split-intensity compensator (§3.1); two-state regime Markov chain with crisis vol ×1.5 and correlation overlay β = 0.30.

## Appendix B — correlation matrices
Print both the base matrix and the realized post-projection crisis matrix as the engine builds them, plus the max deviation from the naive ×1.3 target. Do not transcribe a separate copy that can drift out of sync with the code.

## Appendix C — historical reference (cite)
Source any historical drawdown/recovery comparisons (dot-com, 2008, 2020, 2022) and prior capex boom-bust analogies (telecom fiber 1998–2002 is the closest structural analogue; note where it differs — those builders had no revenue-generating installed base, and the current spenders do). Mark uncited rows `[unverified]`.

## Appendix D — input manifest
Per §3.4.

---

**Reminder:** if you could not execute the simulation, the only correct output is to say so. Do not deliver a report whose numbers were never computed.