> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kaireonai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Decision Simulator

> Replay archived decisions under proposed scenario configs and see the diff with bootstrap-CI confidence on value delta.

## API surface

| Endpoint                              | Purpose                                                                                               | Wired scaffold                           |
| ------------------------------------- | ----------------------------------------------------------------------------------------------------- | ---------------------------------------- |
| `POST /api/v1/scenarios/run`          | Single scenario; returns ScenarioResult + 95 % CI on value delta.                                     | `lib/scenario/shadow-score.ts`           |
| `POST /api/v1/scenarios/compare`      | 2–10 scenarios; ranks by value delta with paired-bootstrap p-values.                                  | `lib/scenario/multi-compare.ts`          |
| `POST /api/v1/scenarios/distribution` | Per-segment offer-share + Gini + KL (W11).                                                            | `lib/scenario/distribution-simulator.ts` |
| `POST /api/v1/scenarios/value-finder` | Pareto sweep over revenue × fairness × coverage (W11).                                                | `lib/scenario/value-finder.ts`           |
| `POST /api/v1/scenarios/seasonality`  | Decompose a time-series window into weekly seasonality + trend + residual; optional forward forecast. | `lib/scenario/seasonality.ts`            |

All five are tenant-scoped, rate-limited (10/min run, 5/min compare,
10/min distribution, 6/min value-finder, 20/min seasonality), and write
audit-log rows so DSAR exports can cite what was simulated.

## Run body shape

```json theme={null}
{
  "from": "2026-04-01T00:00:00Z",
  "to": "2026-04-28T00:00:00Z",
  "scenario": {
    "offerScoreMultiplier": { "OFFER_PREMIUM_CARD": 1.1 },
    "offerScoreAdd": {},
    "minScore": 0
  },
  "maxTraces": 5000,
  "seed": 42,
  "offerValues": { "OFFER_PREMIUM_CARD": 1500 }
}
```

* `offerValues` is optional. When absent, `valueDelta` is computed
  using **score as a proxy** for value, and the response sets
  `meta.valuesUsedProxy: true`.
* `maxTraces` caps the archive window at 1–20000 rows.
* `seed` controls the bootstrap PRNG so the CI is reproducible.

## Compare body shape

```json theme={null}
{
  "from": "2026-04-01T00:00:00Z",
  "to": "2026-04-28T00:00:00Z",
  "scenarios": [
    { "name": "baseline_plus_5pct", "config": { "offerScoreMultiplier": { "OFFER_X": 1.05 } } },
    { "name": "diversity_boost",    "config": { "offerScoreAdd":        { "OFFER_X": 0.1 } } }
  ]
}
```

Returns a per-scenario result plus a `pValues` matrix and a
`rank` ordering by value delta.

## Seasonality body shape

```json theme={null}
{
  "history": [
    { "day": "2026-03-01", "value": 1234 },
    { "day": "2026-03-02", "value": 1190 }
  ],
  "forecast": {
    "startDay": "2026-04-29",
    "days": 14,
    "baseLevel": 1200,
    "upliftFactor": 1.08
  }
}
```

`history` requires 7+ points. `forecast` is optional — when omitted,
only the decomposition is returned.

## UI

`/studio/scenarios` ships **5 tabs**: Run, Compare, Outcome,
Optimization Sweep, Seasonality. Run is the polished single-scenario form
with bootstrap-CI on value delta. The other four tabs surface raw
JSON request/response panels — operators paste in the body shape, hit
Run, see the structured response. Chart wrappers are roadmap polish.

## Outcome Distribution

`POST /api/v1/scenarios/distribution` slices archived decisions by a
segment dimension and emits per-segment offer-share, share-delta, Gini
concentration index (0=uniform, 1=winner-take-all), and KL-divergence
(baseline ‖ scenario, nats).

```json theme={null}
{
  "from": "2026-04-01T00:00:00Z",
  "to": "2026-04-28T00:00:00Z",
  "scenario": { "offerScoreMultiplier": { "OFFER_A": 1.2 } },
  "segmentDimension": "tier",
  "segmentResolver": {
    "CUSTOMER_1": { "tier": "gold", "region": "us-east" },
    "CUSTOMER_2": { "tier": "silver", "region": "us-west" }
  }
}
```

The `segmentResolver` is operator-supplied because there is no
`Customer` Prisma model — segment data lives in DataSchema-driven
`ds_*` tables and the operator's UI / batch driver knows how to hydrate
it. Customers missing from the resolver are skipped honestly; the
`meta.tracesScanned` + `meta.segmentsCovered` block reports coverage
so operators see what fraction of the window was attributable.

## Optimization Sweep

`POST /api/v1/scenarios/value-finder` — Pareto-frontier sweep over
revenue × fairness × coverage.

```json theme={null}
{
  "from": "2026-04-01T00:00:00Z",
  "to": "2026-04-28T00:00:00Z",
  "scenarios": [
    { "name": "baseline", "config": {} },
    { "name": "boost-A",  "config": { "offerScoreMultiplier": { "OFFER_A": 1.2 } } },
    { "name": "boost-B",  "config": { "offerScoreMultiplier": { "OFFER_B": 1.2 } } }
  ],
  "segmentDimension": "tier",
  "offerValues": { "OFFER_A": 100, "OFFER_B": 80 }
}
```

Response `rows[]` carries per-scenario `revenue / fairness / coverage /
picks / dominated`. `paretoFront[]` lists non-dominated names. The
`recommended` field is the Pareto-front member with the highest
geometric mean of normalized axes — a conservative default, never
binding.

**Honest limits:** `fairness` is returned as not-a-number when the
archive lacks segments (returned, not silenced). `revenue` falls back
to score-as-proxy when `offerValues` are absent.

## Honest limits

* Per-offer business value (margin / expected revenue) is best
  supplied by the caller. When missing, the route falls back to score
  as a proxy and **explicitly flags it** in `meta.valuesUsedProxy`.
* The compare endpoint loads the archive once per call; very wide
  windows (`maxTraces` near the cap) on slow Postgres can take 10+s.
* The seasonality endpoint does not query the DB for time-series
  data — the canonical KPI source varies per tenant. Caller supplies
  the history.
