# stochastic-rs documentation site — plan
A maintainable, Vercel-deployed documentation site for the `stochastic-rs`
workspace. Living document — update as the site is built and the project
evolves.
## 0. Locked-in decisions
| Framework | **Fumadocs** (Next.js 15 App Router, MDX v10) |
| Location | `website/` at the workspace root |
| Language | English only |
| Scope | Full — guides + per-feature catalog + tutorials + Python parity + bench dashboard |
| Hosting | Vercel (GitHub integration, preview deploys per PR) |
Rationale: Fumadocs has the best out-of-the-box DX for math-heavy technical
docs (KaTeX wiring, MDX components like `Cards`/`Tabs`/`Steps`, fast Orama
search). `website/` keeps the site in-tree without colliding with the
existing audit notes under `docs/`. English-only matches the international
crates.io / PyPI audience.
## 1. Tech stack
- `fumadocs-ui` + `fumadocs-mdx` (latest)
- Next.js 15 (App Router, RSC)
- Tailwind v4
- KaTeX via `remark-math` + `rehype-katex` (wired in `source.config.ts`)
- Shiki for code highlighting (presets: `rust`, `python`, `bash`, `toml`)
- Orama search (built into Fumadocs; in-memory index)
- Optional: Mermaid via `@theguild/remark-mermaid` for the rare diagram
Custom React components (under `website/components/`):
- `BenchDashboard` — renders criterion JSON as sortable table with sparklines
- `PythonParityTable` — Rust-vs-Python feature parity matrix
- `ProcessCatalog` — auto-grids cards for a category from frontmatter
- `SDEFormula` — consistent SDE rendering wrapper around KaTeX
- `PaperRef` — reference card with DOI / arXiv link
- `RustExample` — `include`-s a file from `examples/` or `tests/`
## 2. Information architecture
Top-level sections, with **page counts** scoped to what already exists in the
Rust workspace today (counts auditable from `find … -name '*.rs'`):
| 1 | Getting Started | 4 | P0 |
| 2 | Concepts | 8 | P0 |
| 3 | Stochastic Processes | ~80 | P1 |
| 4 | Distributions | 22 | P1 |
| 5 | Copulas | 10 | P2 |
| 6 | Statistics & Estimators| ~30 | P2 |
| 7 | Quant Finance | ~80 | P1 |
| 8 | AI Surrogates | 5 | P2 |
| 9 | Visualization | 2 | P3 |
| 10| Python Bindings | 6 | P1 |
| 11| Tutorials | 8–10 | P0 |
| 12| Benchmarks | 1 | P2 |
| 13| API Reference | 2 | P3 |
| 14| Migration (v1 → v2) | 2 | P0 |
| 15| Contributing | 5 | P2 |
Total ≈ **270 pages**. The vast majority follow strict templates (§3) so
authoring is mechanical.
### Concrete catalog inventory
Audited from current `src/` trees (2026-05-10):
- **Diffusion processes** (30): `ait_sahalia`, `cev`, `cfou`, `cir`, `ckls`,
`fcir`, `feller`, `feller_root`, `fgbm`, `fjacobi`, `fou`, `fouque`, `gbm`,
`gbm_ih`, `gbm_log`, `gompertz`, `hyperbolic`, `hyperbolic2`, `jacobi`,
`kimura`, `linear_sde`, `logistic`, `modified_cir`, `nonlinear_sde`, `ou`,
`pearson`, `quadratic`, `radial_ou`, `regime_switching`, `three_half`,
`verhulst`
- **Jump processes** (16): `bates`, `bilateral_gamma`, `cgmy`, `cts`,
`hawkes_jd`, `ig`, `jump_fou`, `jump_fou_custom`, `kobol`, `kou`,
`levy_diffusion`, `merton`, `mjd_log`, `nig`, `rdts`, `vg`
- **Volatility processes** (11): `bates_svj`, `bergomi`, `double_heston`,
`fbates_svj`, `fheston`, `heston`, `heston_log`, `hkde`, `rbergomi`,
`sabr`, `svcgmy`
- **Interest-rate processes** (14): `adg`, `bgm`, `cir`, `cir_2f`,
`duffie_kan`, `duffie_kan_jump_exp`, `fractional_vasicek`, `hjm`, `ho_lee`,
`hull_white`, `hull_white_2f`, `lmm`, `vasicek`, `wu_zhang`
- **Rough processes** (6): `kernel`, `markov_lift`, `rl_bs`, `rl_fbm`,
`rl_fou`, `rl_heston`
- **Noise** (5): `cfgns`, `cgns`, `fgn`, `gn`, `wn`
- **Distributions** (22 files; 19 user-facing types): `alpha_stable`, `beta`,
`binomial`, `cauchy`, `chi_square`, `complex`, `exp`, `gamma`, `geometric`,
`hypergeometric`, `inverse_gauss`, `lognormal`, `non_central_chi_squared`,
`normal`, `normal_inverse_gauss`, `pareto`, `poisson`, `studentt`,
`uniform`, `weibull` + traits / float impls / special funcs
- **Copulas — bivariate** (4): `clayton`, `frank`, `gumbel`, `independence`
- **Copulas — multivariate** (3): `gaussian`, `tree`, `vine`
- **Pricers** (~30): `asian`, `autocallable`, `barrier`, `basket`, `bermudan`,
`bjerksund_stensland`, `breeden_litzenberger`, `bsm`, `cgmysv`, `chooser`,
`cliquet`, `compound`, `digital`, `dupire`, `engines`, `execution_cost`,
`finite_difference`, `fourier`, `heston`, `heston_stoch_corr`, `kirk`,
`lookback`, `malliavin_gbm`, `malliavin_greeks`, `merton_jump`, `pnl`,
`rainbow`, `rbergomi`, `regime_switching`, `sabr`, `slv`, `snell_envelope`,
`spread`, `variance_swap`
- **Calibrators** (12): `bsm`, `cgmysv`, `double_heston`, `heston`,
`heston_stoch_corr`, `hkde`, `hw_swaption`, `levy`, `rbergomi`, `sabr`,
`sabr_caplet`, `svj`
- **Stats** — MLE (4 files: `density`, `fit`, `process_impls`), realized
(`bipower`, `har`, `kernel`, `pre_averaging`, `two_scale`, `variance`),
econometrics (`changepoint`, `cointegration`, `granger`, `hmm`),
filtering (`mcmc`, `particle`, `ukf`), normality (`anderson_darling`,
`jarque_bera`, `shapiro_francia`), stationarity (`adf`, `ers_dfgls`,
`kpss`, `leybourne_mccabe`, `phillips_perron`), plus standalone
(`fukasawa_hurst`, `gaussian_kde`, `heston_mle`, `heston_nml_cekf`,
`tail_index`, `spectral`, `leverage`, `fou_estimator`, `cir`,
`double_exp`)
- **AI surrogates** (3 model types under `volatility/`): `heston`,
`one_factor` (Bergomi-1F), `rbergomi`
- **Quant — vol surface** (7): `analytics`, `arbitrage`, `implied`,
`model_surface`, `pipeline`, `sabr_smile`, `ssvi`, `svi`
- **Quant — risk** (8): `credit`, `drawdown`, `execution`,
`expected_shortfall`, `greeks`, `performance`, `scenario`, `var`
- **Quant — credit** (5): `bootstrap`, `cds`, `merton`, `migration`,
`survival_curve`
- **Quant — curves** (8): `bootstrap`, `discount_curve`, `interpolation`,
`linalg`, `multi_curve`, `nelson_siegel`, `svensson`, `types`
- **Quant — bonds** (3): `cir`, `hull_white`, `vasicek`
- **Quant — cashflows** (4): `coupon`, `engine`, `leg`, `types`
- **Quant — portfolio** (6): `covariance`, `data`, `engine`, `momentum`,
`optimizers`, `types`
- **Quant — microstructure**: Almgren-Chriss, Kyle, Bouchaud propagator,
Roll / Corwin-Schultz, order book
- **Quant — factors / strategies**: PCA, Fama-MacBeth, Ledoit-Wolf,
pairs trading, regime engine
## 3. Page templates
Eight templates cover ~95% of the catalog. Each enforced by frontmatter
schema (zod).
### 3.1 Process page (used ~80×)
```mdx
---
title: Ornstein-Uhlenbeck (OU)
description: Mean-reverting Gaussian diffusion with constant volatility.
category: process
subcategory: diffusion
crate: stochastic-rs-stochastic
module_path: stochastic_rs::stochastic::diffusion::ou
since: 2.0.0
status: stable
references:
- { author: "Uhlenbeck & Ornstein", year: 1930, title: "On the theory of the Brownian motion" }
---
# Ornstein-Uhlenbeck (OU)
> One-line summary.
## SDE
$$ dX_t = \theta(\mu - X_t)\,dt + \sigma\,dW_t,\quad X_0 = x_0 $$
Closed-form transition density: $X_t \mid X_s \sim \mathcal N(\dots)$.
## Constructor
| `theta` | `T` | Mean-reversion |
| `mu` | `T` | Long-run mean |
| `sigma` | `T` | Volatility |
| `n` | `usize` | Steps |
| `x0` | `Option<T>` | Initial value |
| `t` | `Option<T>` | Horizon |
## Examples
<Tabs items={['Rust', 'Python']}>
<Tab value="Rust">
<RustExample path="examples/ou_quickstart.rs" />
</Tab>
<Tab value="Python">
```python
from stochastic_rs import OU
p = OU(theta=2.0, mu=0.0, sigma=1.0, n=1000, x0=0.0, t=1.0)
path = p.sample()
```
</Tab>
</Tabs>
## Properties
- **Stationary**: yes (Gaussian, mean $\mu$, variance $\sigma^2/(2\theta)$)
- **Markov**: yes
- **Closed-form transition**: yes
- **GPU**: no (CPU SIMD via `f64x4`)
## Calibration / estimation
See [MLE for OU](/docs/stats/mle/process-impls#ou) and
[Fukasawa Hurst](/docs/stats/hurst/fukasawa) for fOU variants.
## See also
- [fOU](/docs/processes/diffusion/fou) — fractional OU
- [CIR](/docs/processes/diffusion/cir) — square-root OU variant
- [Vasicek](/docs/processes/interest/vasicek) — interest-rate parameterisation
## References
<PaperRef doi="..." title="..." />
```
### 3.2 Distribution page (used 19×)
Sections: PDF / CDF / characteristic function (with $\LaTeX$ math), constructor,
Rust + Python example, **closed-form moments** from `DistributionExt` (mean,
variance, skewness, kurtosis), KS-test note, references. Mark explicitly when
a moment is `unimplemented!` per
`memory/project_distribution_ext_status.md`.
### 3.3 Pricer page (~30×)
Sections: model, payoff, method (closed-form / Fourier / MC / FD / lattice),
constructor signature, Rust + Python example, Greeks support
(✅ via `GreeksExt` / ❌), calibration link if applicable, complexity
(O(steps · paths) etc.), references. For MC pricers note variance-reduction
support.
### 3.4 Calibrator page (~12×)
Sections: model, market data needed (strikes / IVs / quote types),
optimiser (LM / DE / NMLE-CEKF / Cui analytic Jacobian), `CalibrationResult`
fields, success criteria (typical RMSE), Rust example, references. Always
link back to the corresponding pricer page.
### 3.5 Estimator page (~30×)
Sections: estimand, method, result struct fields, asymptotic distribution
or bootstrap-CI note, p-value semantics, Rust + Python example, paper
reference. **Required**: cite the paper the implementation follows
verbatim (per `feedback_implementation.md`).
### 3.6 Copula page (10×)
Sections: $C(u, v; \theta)$ formula, dependence parameter range, Kendall's
$\tau$ / Spearman's $\rho$ closed forms, sampling algorithm, tail-dependence
coefficients, Rust + Python example. Per `copula-bivariate` SKILL.
### 3.7 AI surrogate page (3×)
Sections: model spec (`StochVolModelSpec`), input scaler / output scaler,
training-set source (gzip-npy path), `train_save_load` test reference,
`predict_surface` integration with `ImpliedVolSurface::from_flat_iv_grid`,
benchmark vs analytical / Fourier baseline. Per `vol-surrogate-nn` SKILL.
### 3.8 Concept page (8×)
Free-form: `prelude`, trait deep-dives (`FloatExt`, `ProcessExt`,
`DistributionExt`, `PricerExt`, `Calibrator`), feature flags, design
philosophy. Cross-link to `dev-rules` SKILL where appropriate.
## 4. File tree
```
website/
├── package.json
├── pnpm-lock.yaml
├── next.config.mjs
├── source.config.ts # MDX + KaTeX config
├── tailwind.config.ts
├── tsconfig.json
├── README.md # build / preview / deploy
├── public/
│ ├── bench/*.json # criterion exports
│ ├── python-parity.json # generated by scripts/python-parity.ts
│ └── og/*.png # OpenGraph images
├── app/
│ ├── (home)/page.tsx
│ ├── docs/[[...slug]]/page.tsx
│ ├── docs/layout.tsx
│ ├── api/search/route.ts
│ ├── layout.config.tsx
│ ├── layout.tsx
│ └── global.css
├── content/docs/
│ ├── meta.json
│ ├── index.mdx
│ ├── getting-started/
│ ├── concepts/
│ ├── processes/{diffusion,jump,volatility,interest,rough,noise}/
│ ├── distributions/
│ ├── copulas/{bivariate,multivariate}/
│ ├── stats/{mle,realized,econometrics,filtering,normality,stationarity,hurst}/
│ ├── quant/{pricing,calibration,instruments,vol-surface,risk,credit,curves,bonds,cashflows,portfolio,microstructure,factors}/
│ ├── ai/
│ ├── viz/
│ ├── python/
│ ├── tutorials/
│ ├── benchmarks/
│ ├── api/
│ ├── migration/
│ └── contributing/
├── components/
│ ├── BenchDashboard.tsx
│ ├── PythonParityTable.tsx
│ ├── ProcessCatalog.tsx
│ ├── SDEFormula.tsx
│ ├── PaperRef.tsx
│ └── RustExample.tsx
└── scripts/
├── python-parity.ts # generate parity-table JSON from py crate AST
├── docs-audit.ts # diff Rust public API vs docs pages
└── lint-mdx.ts # frontmatter schema check
```
## 5. Source-to-doc consistency
Two rails to prevent rot:
### 5.1 Doctest-backed examples (preferred for hot pages)
Each Rust example for landing / quickstart / top-N processes is also a
file under `tests/doctest_*.rs` (or `examples/`). The MDX `<RustExample>`
component reads the file at build time and inlines the contents inside a
fenced `rust` block. Result: `cargo test --workspace` validates the
examples; broken examples fail CI before the docs deploy.
### 5.2 Inline + sha-pinned (fallback for the long tail)
Pages that can't be doctested annotate each fence with
`// last-checked: <commit-sha>`. The `scripts/docs-audit.ts` quarterly job
flags pages whose pinned sha is older than 90 days while the corresponding
Rust source has changed.
Recommendation: start everything with §5.2 (fast), promote any page that
graduates into the top-50-traffic set to §5.1.
## 6. Per-page metadata schema
Strict zod schema in `source.config.ts`:
```ts
{
title: z.string().min(1),
description: z.string().min(20).max(160),
category: z.enum(['process', 'distribution', 'copula', 'estimator',
'pricer', 'calibrator', 'concept', 'tutorial',
'reference']),
subcategory: z.string().optional(),
crate: z.string().regex(/^stochastic-rs(-\w+)?$/),
module_path: z.string(), // rustdoc path
since: z.string().regex(/^\d+\.\d+/), // semver
status: z.enum(['stable', 'experimental', 'deprecated']),
features: z.array(z.string()).default([]), // required Cargo features
references: z.array(z.object({
author: z.string(),
year: z.number(),
title: z.string(),
doi: z.string().optional(),
arxiv: z.string().optional(),
url: z.string().url().optional(),
})).default([]),
}
```
The `module_path` lets us auto-render a "View on docs.rs" button on every
catalog page.
## 7. Custom components (sketch)
### `<BenchDashboard />`
```
Inputs: /public/bench/*.json (criterion exports, one per bench)
Output: Sortable table, columns: bench / ns/iter / throughput /
delta vs `rc2` baseline / sparkline (last 10 commits)
Update: GitHub Action `bench-publish.yml` runs `cargo bench --bench X --
--output-format bencher`, post-processes to JSON, commits to
website/public/bench/. Triggered weekly + on tag.
```
### `<PythonParityTable />`
```
Inputs: /public/python-parity.json (generated by scripts/python-parity.ts)
#[pyclass] macros, cross-reference against the catalog index.
Update: `pnpm python:parity` runs the script. Commit on PR boundaries.
```
### `<ProcessCatalog category="diffusion" />`
```
Reads: frontmatter from all MDX in content/docs/processes/<category>/
Renders: card grid (name, one-liner, 'View →' link)
```
### `<RustExample path="..." />`
```
Reads: file at <workspace_root>/<path> (e.g. tests/doctest_ou.rs)
Renders: shiki-highlighted rust block
Errors: build fails if the path doesn't exist (catches drift)
```
## 8. Deployment
### Vercel project
- Repo: `dancixx/stochastic-rs`
- Root directory: `website/`
- Framework preset: **Next.js**
- Build command: `pnpm build`
- Install command: `pnpm install --frozen-lockfile`
- Output: `.next` (default)
- Node: 20 LTS
### CI (`.github/workflows/website.yml`)
Triggered on `push` to `main` (paths-filter: `website/**`, `examples/**`,
`*/src/**`, `tests/**`):
1. `pnpm tsc --noEmit`
2. `pnpm lint` (eslint + frontmatter schema check via `scripts/lint-mdx.ts`)
3. `pnpm build` (Fumadocs build, fails on broken internal links)
4. `cargo test --test 'doctest_*'` — validates `<RustExample>` files
5. Vercel auto-deploys on green main.
PR previews: handled by the Vercel GitHub App (no extra workflow needed).
### Domain
- Primary candidate: **`stochastic-rs.dev`** (Google-managed `.dev` TLD,
forced HTTPS, on-brand)
- Fallbacks: `stochastic-rs.org`, `stochastic-rs.com`
- Until registered: `stochastic-rs.vercel.app`
## 9. Phased rollout
Six phases, each shippable. Phase 0+1 = MVP.
| 0 | ½ day | Scaffold (Fumadocs init, Vercel link, KaTeX, Tailwind, theme) | 0 |
| 1 | 2 days | Landing + Getting Started + Concepts (8) + 2 hero tutorials | ~15 |
| 2 | 1 week | Processes: diffusion (30) + jump (16) + noise (5) | ~50 |
| 3 | 4 days | Processes: volatility (11) + interest (14) + rough (6) | ~35 |
| 4 | 4 days | Distributions (19) + copulas (10) | ~30 |
| 5 | 5 days | Quant: pricing (~30) + calibration (~12) | ~45 |
| 6 | 3 days | Quant: vol surface, risk, credit, curves, bonds, instruments | ~35 |
| 7 | 3 days | Stats catalog | ~30 |
| 8 | 2 days | AI + viz + Python parity table + remaining tutorials | ~15 |
| 9 | 2 days | Bench dashboard + contributing + polish + OG images | ~10 |
**Cumulative**: ~6 weeks part-time / ~2.5 weeks full-time. **MVP** (phase
0+1) shippable in 2.5 days.
## 10. Maintenance workflow
### 10.1 Per-PR rule
Any PR that adds a public type in
`stochastic-rs-{stochastic,distributions,copulas,quant,stats,ai}` MUST add
a corresponding MDX page. Enforced by `scripts/docs-audit.ts` running in
CI:
1. Parse diff for `pub struct` / `pub enum` additions in `src/`
2. Lookup `module_path` in the existing MDX frontmatter set
3. Fail with a "missing docs page" error if any addition has no page
The audit is also a quarterly job (cron) to catch drift from edits that
slipped past the diff check.
### 10.2 SKILL: docs-writing
Add `.claude/skills/docs-writing/SKILL.md` with the eight page templates
above so a future Claude session can stub a page in seconds when a new
process / distribution / pricer ships. Include:
- Template per category (copy-paste ready)
- Frontmatter required fields
- KaTeX gotchas (escaping, `$$` vs `\\(`)
- Where to add the entry in `meta.json` (sidebar order)
### 10.3 Quarterly content audit
`scripts/docs-audit.ts` also produces a markdown report:
- Pages whose `module_path` no longer resolves (Rust source moved/removed)
- Pages whose pinned sha (§5.2) is stale + Rust source changed
- Public types with no documentation page (cross-checked against §10.1)
- `references` entries with broken DOI / arXiv links
Output: `docs/DOCSITE_AUDIT_<date>.md`, mirroring the existing audit
naming convention.
## 11. Open questions
- **Versioning**: defer until after `2.0.0` stable is shipped. For now,
`main` only. Old releases reachable via git tags
(`git checkout v1.x -- website && pnpm dev`). Revisit when `3.x` work
starts.
- **Domain**: register `stochastic-rs.dev` (or `.org`) before Phase 0
finishes — DNS propagation lag.
- **Doctest sync** (§5): start §5.2 across the board; promote
hero pages to §5.1 in Phase 9.
- **Bench dashboard data freshness**: weekly cron sufficient, or
on-tag only? Default to weekly + on-tag.
- **Search relevance**: default to Fumadocs Orama. If users complain,
evaluate Pagefind (build-time index) or Algolia DocSearch (free
for OSS).
## 12. Explicit non-goals
- **Auto-generated rustdoc-style pages**: docs.rs already handles that.
We hand-curate per the templates in §3 — narrative > exhaustive.
- **i18n**: locked English-only. Reconsider only if a >10% non-English
user base shows up (very unlikely for a Rust quant lib).
- **Notebook/Jupyter**: out of scope. Tutorials are MDX with `<Tabs>`
for Rust + Python code; no interactive runtime.
- **Dark-mode-only or light-mode-only**: ship both, system preference
default (Fumadocs handles this).
- **Marketing site / blog**: this is a docs site. A blog can be added
later under `/blog/` with `fumadocs-mdx` content collections, but is
not in this plan.
## 13. References
Internal:
- `CLAUDE.md` — workspace layout, traits, prelude
- `docs/V1_TO_V2.md` — port to `migration/v1-to-v2.mdx`
- `docs/WORKSPACE_MIGRATION.md` — context for the workspace section
- `docs/BENCH_BASELINE.md` — feeds the `<BenchDashboard />`
- `docs/PYTHON_BINDING_UPDATE_PLAN.md` — Python catalog scope
- `.claude/skills/*` — author hints; the docs site links out to selected
SKILLs from the `contributing/` section
External (framework docs):
- [Fumadocs](https://fumadocs.dev)
- [Fumadocs MDX math setup](https://www.fumadocs.dev/docs/markdown/math)
- [Vercel: Next.js project setup](https://vercel.com/docs/frameworks/nextjs)