Skip to main content

Terrain — Backend Notes for UI Wiring

Ground truth for the Strategy Lab / Terrain Workbench wiring. Authoritative for the backend (this repo: ClickHouse + the Python API). Frontend routing and theme are covered by the app-repo wiring gap analysis and are out of scope here. Last verified against code 2026-06-24.

0. Naming

Terrain is Sequency’s regime classification & detection system. It replaces the internal working terms “vNext” / “regime_v2” in all product/UI naming.
  • Terrain v1 = the 2×3 grid.
  • Terrain v2 = the multi-axis read.
Internal backend symbols (regime_v2, RegimeSnapshotV2, regime_vnext/, regime_archive) keep their names for now; “Terrain” is the product-facing name. Product name → code symbol map: Current canon — cite these, not the docs/superpowers/specs/_deprecated/ set:
  • Program charter — docs/superpowers/specs/2026-06-11-regime-engine-program-charter.md
  • Terrain v2 design — docs/superpowers/specs/2026-06-21-regime-vnext-design.md (currently local-only — not yet committed to main)
  • Locked prereg + evidence — docs/superpowers/specs/2026-06-22-regime-vnext-prereg-reset.md
  • Production-policy design — docs/superpowers/specs/2026-06-22-regime-vnext-production-policy-readiness-design.md
  • SP1/SP2/SP3 designs; docs/api/screener-regime-intraday.md; docs/runbooks/regime-vnext-rd.md

1. The taxonomies + EXACT enums (stop guessing these)

Terrain v1 — the 2×3 grid

Direction × Volatility. Persisted daily in daily_regime_labels.regime_grid.
  • Direction: BULL | SIDEWAYS | BEAR (note: SIDEWAYS, not “NEUTRAL”, in the label string)
  • Volatility: LOW_VOL | HIGH_VOL
  • Cell string: e.g. BULL_LOW_VOL, BEAR_HIGH_VOL (6 cells)

Terrain v2 — the 3-axis read (backtester-derivable subset)

  • risk_state: stress | elevated | calm | normal
  • volatility_change: expanding | compressing | stableNOT rising
  • directional_pressure: upside_extended | balanced | downside_extendedno persistent_trend
  • Cell string: "{risk_state}|{volatility_change}|{directional_pressure}" — e.g. calm|stable|upside_extended, normal|stable|balanced
Important: the RegimeSnapshotV2 model defines 6 axes (the above 3 plus breadth_state, correlation_state, intraday_structure). Those three have no point-in-time source in regime_archive, so the backtester / historical path produces only the 3 axes above. Do not render the other three for any historical/backtest view — they don’t exist there.

2. Data provenance + pins (corrections to the handoff)

  • Terrain v2 axes are NOT persisted daily. Only the 2×3 grid is stored daily (daily_regime_labels). Terrain v2 is derived on-the-fly from regime_archive via services/regime_vnext/comparison.py / backtester/regime_v2.py (derive_regime_v2_axes_from_snapshot). This is the biggest hidden cost of the Workbench, and it is the recommended slice-1 path.
  • Pins: logic_version = 'sp1-v1' (the invented 'rl-2026.06.2' does not exist). variant:
    • 'emitted' — point-in-time, look-ahead-free. PIT already exists; the limit is data volume (forward accrual), not schema.
    • 'corrected' — descriptive / full-history backfill. Use this for descriptive displays and backtest attribution.
  • A persisted daily Terrain-v2 table (full backfill) is NOT required for slice 1, and is NOT blocked by the regime-program governance charter — that charter governs alpha certification (promoting regime-conditioning to a live-money gate), not a descriptive display table. Treat backfill as a future performance optimization, not a prerequisite.

3. Terrain v2 ↔ v1 grid projection (for the UI)

Both derive from the same regime_archive substrate (slope_pctile, vol_pctile, shock), so v2 maps onto the familiar grid: v1 and v2 are computed independently (v1 = persisted grid; v2 = derived), so they agree but are not a strict per-row mechanical projection. The UI should read v1 for the grid headline and v2 for the axis drill-down — both are stored (§4.2), so no client-side projection is needed.

4. Two distinct backend surfaces — do NOT conflate them

4.1 Terrain analysis (market-level) — NET-NEW, still to build

Purpose: current/historical market regime + per-regime market attribution (the Terrain Workbench).
  • ~70% of the math exists offline in services/regime_vnext/comparison.py (reads regime_archive + daily rollups, derives the v2 axes, computes per-regime attribution). It has no HTTP route yet — that route is the critical path.
  • Route naming: use /api/graph/v1/terrain/.... The singular /api/graph/v1/regime prefix is taken (regime.py + regime_v2.py); a plural /regimes would work but /terrain both avoids the collision and adopts the product name. regime_vnext.py exists but is currently unmounted.
  • Slice-1 sourcing: derive on-the-fly (§2). variant='corrected' for full history, variant='emitted' for honest PIT.

4.2 Strategy effectiveness across Terrain — ALREADY SHIPPED (PR #1165 + #1166)

Purpose: how a strategy performed across regimes (the heatmap). You do not need to build this aggregation — it already exists and accrues automatically.
  • Table: backtest_regime_effectiveness (ClickHouse, DB sequency). Written on every backtest completion (best-effort; never blocks a run), for both the rule-driven and cross-sectional paths.
  • Stores both taxonomies per (strategy, cell): rows with regime_taxonomy='terrain_v1' (grid cells) and regime_taxonomy='terrain_v2' (3-axis cells).
  • Schema: Engine: ReplacingMergeTree(computed_at), ORDER BY (strategy_id, regime_taxonomy, regime_cell, run_id).
  • UI usage: read terrain_v1 rows for the 6-cell grid heatmap headline; read terrain_v2 rows for the axis drill-down. Query “strategy X across all runs in cell Y” directly off this table.
  • Migration: clickhouse/058_backtest_regime_effectiveness.sql. Accumulator: api/app/services/backtester/regime_effectiveness.py.

5. Quick reference for the wiring agent

  • It’s Terrain (v1 grid / v2 3-axis), not “vNext”. Name the design-system module lib/terrain.ts and the tokens accordingly.
  • Use the exact enums in §1 — compressing|stable|expanding, no rising, no persistent_trend.
  • Pins: logic_version='sp1-v1'; variant emitted (PIT) / corrected (descriptive).
  • New work = the market-level Terrain analysis route (§4.1). Strategy-across-Terrain data is done (§4.2) — don’t rebuild it.
  • Theme + frontend routing (/api/v4, /market/pulse, providers.tsx default): see the app-repo gap analysis; those are not backend concerns.