A second brain for macro analysts. Models the financial world as an interconnected causal factor graph — 52 nodes (financial products + macro factors), 117 directed causal edges — and makes it tangible through a 3D interactive visualization. An AI agent fetches real data, analyzes sentiment, and propagates impact through the network. You simulate hypothetical shocks ("what if oil crashes?") and watch the cascade. You pin your own reasoning to nodes. The tool remembers what you think, not just what the data says.
Not a trading signal. A reasoning tool.
- Phase 1 (Foundation): Complete — graph model, agent, 3D viz, API, WebSocket
- Phase 2 (Real-time + Autonomy): Complete — 52 nodes, 117 edges, market data (yfinance), scheduler, sentiment history charts, agent audit log
- Phase 3 (Intelligence + Polish): Complete — dynamic weight recalculation, anomaly detection (2σ auto-trigger), time slider, node clustering, Reddit integration
- Phase 4 (Agent Intelligence): Complete — planning phase, self-critique, cross-node consistency, confidence decomposition
- Phase 5 (Validation): Complete — prediction resolution, agent memory, track record feedback loop, scheduler toggle, predictions panel
- Phase 6 (Hardening): Complete — validation threshold fix, edge muting (no more permanent flips), retry logic (FRED/yfinance), magnitude scoring for predictions, regime refresh per phase
- Phase 7 (What-If Simulator): Complete — shock propagation simulator, impact report panel, cascade visualization on graph
- Phase 8 (Second Brain): Complete — analyst annotations (persistent per-node notes), regime narrator (LLM-generated macro narrative)
- Phase 9 (Hardening II): Complete — graph mutation lock, session rollback, background task crash recovery, agent timeout, WebSocket heartbeat, error boundary, CRUD error handling, AbortController, graphData memoization, timestamp fix
- Phase 13 (Hardening IV + Data Pipeline): Complete — 16 bug fixes (LLM error handling + retry + timeout, graph state rollback on agent error, batch propagation cascade fix, concurrent scheduler agent guard, accept_suggestion lock, missing import NameError, broadcast task tracking, annotation error handling, WebSocket effect fix, SentimentChart catch, Graph3D linkColor O(n) → O(1)), expanded yfinance coverage (13→21 tickers: +3 forex, +3 volatility/credit indices, +2 bond ETFs), richer market data (5-day trend context per ticker), agent prompt optimization (
80→25 tool calls: batch-first, no re-fetching pre-fetched data), FRED series sync fix - Phase 14 (Scenario Engine — "Macro Sim"): Complete — scenario extrapolation agent (4-phase: research → history → generation → mapping, max 27 rounds), "generate first, map second" design (agent reasons freely about real-world impacts, then maps to graph nodes + suggests new nodes/edges), multi-shock simulate, branching scenarios with probability weights, editable shocks, quick triggers from RSS, scenario history, WebSocket progress, ScenarioPanel UI
- Phase 15 (Scenario Intelligence): Complete — 10 scenario engine improvements: economic calendar tool (FOMC/CPI/NFP/GDP + FRED API), options positioning tool (IV, put/call ratio, term structure), current date + market snapshot injected into all phases, expanded Mapper prompt (decision criteria, BAD/GOOD mapping examples, directionality notes), cross-branch coherence check, non-linear shock interaction model (stress multiplier + sigmoid compression), convergence detection in sub-agent loop, edge suggestion validation fix, scenario comparison view (frontend), conditional scenario chaining (chain follow-up scenarios from branch outcomes). Topic diversity fix: 12 domain-aligned news queries, LLM picks top 5 with diversity mandate, random auto-selection, recent trigger avoidance.
- Backend: Python 3.12+, FastAPI, Uvicorn
- Agent: Anthropic SDK (Claude, raw tool-use loop — no framework)
- Graph Engine: NetworkX + numpy/scipy
- Database: PostgreSQL 16 + pgvector + TimescaleDB
- Cache/PubSub: Redis
- Market Data: yfinance — 21 tickers (equities, commodities, forex, volatility indices, bond ETFs; no API key needed)
- Macro Data: FRED API — 16 series (optional, free key from fredaccount.stlouisfed.org; mock data fallback)
- News Data: 30 curated RSS feeds (no API key needed) + keyword→node matching engine
- Social Data: asyncpraw (Reddit, optional)
- Frontend: Next.js 15 + react-force-graph-3d (Three.js/WebGL)
- State: Zustand
- Charts: Lightweight Charts (TradingView)
- Deployment: Docker Compose (local-first, OSS)
causal-sentiment/
backend/
app/
main.py # FastAPI entry point + incremental graph seeding + CORS (ports 3000, 3001)
config.py # Settings (pydantic-settings, reads ../.env)
models/
graph.py # Node, Edge, NodeType, EdgeDirection
observations.py # SentimentObservation, AgentRun, Prediction, Annotation
scenarios.py # Scenario, ScenarioShock, ScenarioPrediction, NodeSuggestion (+ parent_scenario_id for chaining)
agent/
orchestrator.py # Three-phase reasoning loop: Plan → Analyze → Validate (max 35 rounds), pre-fetch data package, evidence provenance
tools.py # 12 tools: fetch_fred, fetch_market, search_news, search_reddit, fetch_sec, update_sentiment, batch_update_sentiment, get_neighborhood, get_analysis_context, validate_consistency, record_prediction, get_agent_track_record
prompts.py # Phase-aware system prompts (planning, analysis, validation, self-calibration)
schemas.py # Anthropic tool definitions (11 tools)
scenario_agent.py # Scenario extrapolation orchestrator (4-phase: research → history → generation → mapping, max 27 rounds), convergence detection, cross-branch coherence, topic diversity (12 domain queries)
scenario_prompts.py # Scenario system + phase prompts (intelligence analyst persona, calibration anchors, expanded mapper with BAD/GOOD examples)
scenario_schemas.py # Scenario tool schemas (get_graph_topology, get_economic_calendar, fetch_options_summary, preview_propagation, submit_scenarios + reused tools)
graph_engine/
topology.py # 52 nodes + 117 edges (hardcoded domain knowledge)
propagation.py # Weighted BFS with exponential decay + merge_multi_shock_impacts (non-linear: stress multiplier + sigmoid compression)
weights.py # Centrality, decay, clamping
correlations.py # Dynamic weight recalculation from empirical Pearson correlations
anomalies.py # Z-score anomaly detection on node observations (2σ threshold)
predictions.py # Prediction resolution — compare agent predictions against actual outcomes
data_pipeline/
fred.py # FRED API client (16 macro series, optional — mock data fallback)
market.py # yfinance client (21 tickers: equities, commodities, forex, vol indices, bond ETFs) + fetch_options_summary (IV, put/call ratio, term structure)
calendar.py # Economic calendar: FOMC dates, recurring releases (CPI/NFP/GDP/PCE/ISM), optional FRED releases API
retry.py # Exponential backoff retry utility (3 attempts)
reddit.py # Reddit pipeline (asyncpraw, keyword→node mapping, 3 subreddits)
scheduler.py # APScheduler: 9 jobs (FRED 4h, market 1h, Reddit 2h, EDGAR daily 6AM, agent 6h, weights 3AM, regime 2h, decay 2AM, prediction resolution 1h) — disabled by default (SCHEDULER_ENABLED=false)
api/
routes_graph.py # Graph CRUD + snapshot + anomalies + clusters + sentiment history + simulate + annotations + regime narrative
routes_agent.py # POST /api/agent/analyze, GET /api/agent/runs, GET /api/agent/predictions, GET /api/agent/predictions/summary
routes_scenario.py # POST /api/scenarios, GET /api/scenarios, GET /api/scenarios/{id}, POST /api/scenarios/{id}/apply, POST /api/scenarios/{id}/chain, GET /api/scenarios/quick-triggers
websocket.py # WebSocket manager + broadcast
db/
connection.py # async SQLAlchemy + asyncpg
requirements.txt
Dockerfile
frontend/
src/
app/page.tsx # Main dashboard layout
components/
Graph3D.tsx # react-force-graph-3d wrapper + cluster forces + anomaly highlighting + simulation overlay
NodePanel.tsx # Node detail: sentiment, what-if simulator, analyst notes, chart, anomaly badge, causal edges, evidence, deep dive
SimulationPanel.tsx # What-if impact report: affected nodes, paths, hop count
ScenarioPanel.tsx # Scenario engine: trigger input, quick triggers, branching scenario cards, editable shocks, history, branch comparison view, scenario chaining UI
SentimentChart.tsx # Lightweight Charts time-series (7d/30d/90d)
SentimentTimeline.tsx # Bottom bar: top movers by sentiment
FilterBar.tsx # Run analysis button, clustered/free layout toggle, regime narrator, legend
AgentRunLog.tsx # Expandable agent run history with tool call details
PredictionsPanel.tsx # Prediction tracker: pending/resolved predictions, hit rate, color-coded cards
TimeSlider.tsx # Historical playback slider (7d range, 1h steps, play/pause)
hooks/
useGraphData.ts # Zustand store: graph, anomalies, snapshots, clustering, WebSocket sync
useNodeSelection.ts # Node selection + deep dive logic
lib/
graphTransforms.ts # API → force-graph transforms, color mapping, edge direction colors
websocket.ts # Auto-reconnecting WebSocket client
types/graph.ts # TypeScript interfaces: GraphNode, GraphEdge, ForceGraphNode, ForceGraphLink, AgentRun, AnomalyInfo
package.json
docker-compose.yml # PostgreSQL + TimescaleDB + Redis
.env.example
# First-time setup (installs everything)
./setup.sh
# Start all services (DB, backend, frontend)
./start.sh
# Stop everything
./stop.sh
# Tests
cd backend && source .venv/bin/activate && pytest
# Full stack via Docker
docker-compose up --build3D Visualization (Next.js + react-force-graph-3d)
↕ WebSocket
API Layer (FastAPI)
↕
┌─────────┼──────────┬────────────────┐
Agent Graph Data Pipeline Historical
(Claude Engine (APScheduler) Store
tool-use) (NetworkX) (TimescaleDB)
Flow: Data Pipeline fetches from FRED/yfinance/news/Reddit → anomaly check → triggers Agent if 2σ move detected → Agent calls Claude with tools → sentiment written to Graph Engine → propagation runs → WebSocket pushes to 3D visualization.
- 52 nodes across 11 categories: macro (8), monetary policy (4), geopolitics (4), rates/credit (6), volatility (5), commodities (6), equities (6), equity fundamentals (3), currencies (4), flows/sentiment (3), global (3)
- 117 directed edges with causal direction (positive/negative/complex), base weight, dynamic weight, transmission lag
- Impact propagation: Weighted BFS with exponential decay (30% per hop), max 4 hops, signals clamped to [-1, 1]
- Edge effective weight:
0.6 * base_weight + 0.4 * dynamic_weight - Dynamic weights: Updated daily from 90-day Pearson correlations between connected node pairs
The agent runs a structured Plan → Analyze → Validate loop (max 35 rounds total):
- Planning Phase — Agent inspects the graph state (anomalies, stale nodes, regime shifts, recent observations) via
get_analysis_contextand decides which nodes to prioritize and why. Outputs a structured analysis plan. - Analysis Phase — Pre-fetched data (FRED, yfinance, RSS headlines) is already in context. Agent reasons about it, writes sentiment via
batch_update_sentiment(batch-first, ~25 tool call budget). Must cite RSS headlines from T1/T2/T3 sources in evidence. Agent should NOT re-fetch pre-fetched data. - Validation Phase — Agent calls
validate_consistencyto check for cross-node contradictions (including unchanged neighbors with non-zero sentiment), then self-critiques and corrects if needed.
fetch_fred_data— FRED macro series (16 series mapped to nodes, optional)fetch_market_prices— yfinance prices (21 tickers: equities, forex, vol indices, bond ETFs)search_news— RSS headlines (30 curated feeds, no API key needed)search_reddit— Reddit social sentiment (r/wallstreetbets, r/economics, r/stocks)fetch_sec_filings— SEC EDGAR financial dataupdate_sentiment_signal— write sentiment to single node + trigger propagation (confidence decomposition: data_freshness, source_agreement, signal_strength)batch_update_sentiment— write sentiment to multiple nodes in one call (single graph lock + atomic commit)get_graph_neighborhood— inspect node + neighborsget_analysis_context— graph-wide state summary: anomalies, stale nodes, regime, recent changes, data freshnessvalidate_consistency— check cross-node contradictions after updates (e.g., conflicting directional signals on causally linked nodes)record_prediction— store a falsifiable prediction for future backtestingget_agent_track_record— query prediction hit rate, accuracy stats, and recent outcomes for self-calibration
- Scheduled — every 6 hours on nodes with fresh data
- Anomaly-driven — auto-triggered when 2σ move detected after data fetch
- User-initiated — "Run Full Analysis" button or per-node "Deep Dive"
A scenario extrapolation agent that takes a real-world event or hypothetical trigger and generates branching probability-weighted scenarios with multi-node shocks.
The agent reasons freely about real-world consequences first (unconstrained by graph structure), THEN is shown the graph topology and asked to map impacts to nodes. If no node fits, it suggests new nodes/edges. This avoids anchoring bias and enables graph evolution.
Each phase is a separate sub-agent with fresh context and focused tools:
| Phase | Agent | Rounds | Tools | Purpose |
|---|---|---|---|---|
| 1 | Researcher | 4 | search_news, fetch_market_prices, get_economic_calendar | Structural situational awareness: facts, actors, market reaction, upcoming catalysts |
| 2 | Historian | 5 | search_news, fetch_market_prices, fetch_historical_prices | Calibration: 2-3 structural parallels grounded in real price data |
| 3 | Strategist | 12 | search_news, fetch_market_prices, get_economic_calendar, fetch_options_summary | Scenario generation: 2-3 branches with free-form impacts, causal chains, probability weights |
| 4 | Mapper | 6 | validate_consistency, get_graph_topology, preview_propagation | Map free-form impacts to nodes, calibrate shock values, verify cascades |
- Current date + market snapshot (SPY, VIX, Oil, DXY, 10Y) injected into Phases 1-3 so the agent knows what year it is and current market levels
- Domain-specific supplements auto-detected from trigger keywords (7 domains: geopolitical, monetary, trade, technology, climate, pandemic, corporate)
- Vulnerability context — extreme-sentiment nodes and high-weight edges injected as "fragility points"
- Track record — resolved scenario predictions injected into Phase 3 for self-calibration
Reuses existing code (search_news, fetch_market_prices, validate_consistency, LLM client, WebSocket) but NEVER reads previous agent outputs (stored sentiments, past runs, predictions). Reads only graph topology (nodes + edges = domain knowledge).
When user applies a branch, merge_multi_shock_impacts() runs propagate_signal for each shock independently, then applies:
- Stress multiplier — when 4+ shocks fire simultaneously:
1.0 + 0.15 * (n_shocks - 3) - Sigmoid compression — diminishing returns near ±1.0 extremes
- Read-only (no DB writes to graph state)
After Phase 3, Jaccard similarity is computed across branch impact sets. Branches with >0.8 overlap are flagged as too similar (logged as warnings).
Sub-agent loop tracks recent tool calls. If the same tool is called with >70% similar inputs (Jaccard on word sets), a nudge is injected: "Synthesize what you have and proceed to submission."
POST /api/scenarios/{id}/chain creates a follow-up scenario from a parent branch outcome. The parent's narrative, shocks, and structural outcome are injected as "assumed context" into the child's Phase 1. Enables multi-step strategic planning: "If Branch A materializes, what happens next?"
Frontend Compare mode lets users select 2 branches side-by-side. Shows node-by-node shock comparison with color coding (green=both positive, red=both negative, blue=opposite, gray=unique) and "Common Risk Nodes" summary.
12 domain-aligned news queries (geopolitics, monetary, trade, tech, energy, financial stability, health, labor, sovereign, housing, EM, food) replace the old single query. LLM picks top 5 with explicit diversity mandate. Recent scenario triggers injected as avoidance list. Auto-pick uses random.choice(triggers[:5]).
APScheduler runs 9 background jobs (all disabled by default — set SCHEDULER_ENABLED=true in .env):
- FRED fetch — every 4 hours (+ anomaly check → auto-trigger agent if 2σ)
- Market fetch (yfinance) — every 1 hour (+ anomaly check → auto-trigger agent if 2σ)
- Reddit fetch — every 2 hours (stores posts matched to nodes by keyword)
- Agent analysis — every 6 hours (only nodes with fresh data since last run)
- Weight recalculation — daily at 3AM UTC (Pearson correlation → dynamic_weight on edges)
- Sentiment decay — daily at 2AM UTC (24h half-life exponential decay)
- Prediction resolution — every 1 hour (resolves expired predictions, no LLM cost)
| Method | Path | Description |
|---|---|---|
| GET | /api/health |
Health check with node/edge counts |
| GET | /api/graph/full |
Full graph for 3D visualization |
| GET | /api/graph/node/{id} |
Single node details |
| GET | /api/graph/sentiment/history/{id}?days=30 |
Sentiment time-series |
| GET | /api/graph/snapshot?timestamp=... |
Historical graph state at a point in time |
| GET | /api/graph/anomalies?lookback_days=30&z_threshold=2 |
Anomalous nodes (z-score) |
| GET | /api/graph/clusters |
Node cluster assignments by type |
| POST | /api/agent/analyze |
Trigger agent analysis ({"node_ids": [...]} or all) |
| GET | /api/agent/runs?limit=20 |
Recent agent runs with tool call logs |
| GET | /api/agent/predictions?limit=20&status=pending |
List predictions (pending/resolved) |
| GET | /api/agent/predictions/summary |
Prediction stats: hit rate, by-direction breakdown |
| POST | /api/graph/simulate |
What-if shock propagation (read-only, no DB write) |
| GET | /api/annotations?node_id=... |
List analyst annotations for a node |
| POST | /api/annotations |
Create analyst annotation |
| PUT | /api/annotations/{id} |
Update annotation text/pin |
| DELETE | /api/annotations/{id} |
Delete annotation |
| POST | /api/graph/regime/narrative |
LLM-generated regime narrative |
| POST | /api/scenarios |
Trigger scenario extrapolation (runs in background) |
| GET | /api/scenarios?limit=20 |
List recent scenarios |
| GET | /api/scenarios/{id} |
Get full scenario with branches, shocks, suggestions |
| POST | /api/scenarios/{id}/apply |
Apply a branch (multi-shock simulate, read-only) |
| POST | /api/scenarios/{id}/chain |
Chain a follow-up scenario from a parent branch outcome |
| GET | /api/scenarios/quick-triggers |
Get 5 scenario-worthy events from current news (12 domain queries) |
| WS | /ws |
Real-time graph updates |
- 3D Force Graph — WebGL visualization with sentiment-colored nodes, directional edge particles
- What-if shock simulator — drag slider to hypothetical sentiment, click Simulate: affected nodes glow, unaffected dim, impact particles flow along causal paths. Impact report shows all affected nodes with magnitude and path.
- Analyst annotations — persistent per-node notes. Pin important notes, delete stale ones. Survives page refreshes and restarts.
- Regime narrator — click the regime badge to expand, click "Generate Narrative" for LLM-generated macro prose. Top driver chips fly camera to that node.
- Node detail panel — sentiment score, confidence, what-if slider, analyst notes, anomaly alert, causal edges with weight breakdown, sentiment chart, evidence, deep dive button
- Anomaly highlighting — anomalous nodes glow yellow and appear 1.5x larger
- Clustered layout — toggle to group nodes spatially by type (macro, equities, etc.)
- Sentiment chart — Lightweight Charts line chart with 7d/30d/90d range buttons
- Time slider — historical playback over 7 days with 1-hour steps and auto-play
- Agent run log — expandable cards showing status, duration, tool calls with outputs, analyzed nodes
- Predictions panel — color-coded prediction tracker (green=hit, red=miss, yellow=pending) with hit rate summary and countdown timers
- Scenario engine — type a trigger event or click a quick trigger from current news (12 domain queries for diversity), see 2-3 branching scenarios with probability weights, causal chains, and mapped shocks. Edit shock values before applying. Compare mode: select 2 branches side-by-side with color-coded node impacts and common risk nodes. Chain mode: generate follow-up scenarios from branch outcomes. Suggested new nodes/edges shown when graph has gaps. Export as JSON.
- Real-time updates — WebSocket pushes graph changes after analysis completes
Users must provide their own API keys in .env:
ANTHROPIC_API_KEY— required for agent analysis (orOPENAI_API_KEY)SCHEDULER_ENABLED—falseby default; settrueto enable background jobs (burns API credits)FRED_API_KEY— optional (free key from fredaccount.stlouisfed.org; mock data fallback without it)NEWSAPI_KEY— optional (RSS feeds are primary news source, no key needed)REDDIT_CLIENT_ID— optional (Reddit social sentiment, free at reddit.com/prefs/apps)REDDIT_CLIENT_SECRET— optional (Reddit social sentiment)
- Backend uses async Python throughout (asyncpg, httpx, yfinance via to_thread)
- All data models: Pydantic v2 in
backend/app/models/ - Config reads
.envfrom bothbackend/and project root (../.env) - All timestamps in UTC; DB columns are
TIMESTAMP WITHOUT TIME ZONE— always usedatetime.utcnow()notdatetime.now(timezone.utc)to avoid offset-naive/aware mismatch - Sentiment scores always in [-1.0, +1.0] range
- Confidence scores in [0.0, 1.0]
SentimentObservation.raw_data(JSONB) stores original FRED/market/Reddit data- CORS allows both
localhost:3000andlocalhost:3001(Next.js may pick either port) - Scheduler jobs create their own
async_session()— they run outside FastAPI request lifecycle - Graph lock: All in-memory graph mutations must use
async with app_state.graph_lock:to prevent race conditions between concurrent agent runs, scheduler jobs, and API requests - Error boundary: Frontend is wrapped in
ErrorBoundarycomponent — component crashes show recovery UI instead of white screen - WebSocket heartbeat: Client pings every 30s, server responds with pong. Connection considered dead after 10s without response.
- Phase 6 (Hardening): Validation threshold fix, edge muting, retry logic, magnitude scoring, regime refresh
- Phase 7 (What-If Simulator): Shock propagation simulator with cascade visualization + impact report panel
- Phase 8 (Second Brain): Analyst annotations (persistent per-node notes with pin), regime narrator (LLM-generated macro narrative)
- Phase 9 (Hardening II): Graph mutation lock (asyncio.Lock), session rollback on agent error, background task crash recovery, agent timeout fallback (15min), WebSocket heartbeat, error boundary, annotation CRUD error handling, AbortController on fetches, graphData useMemo, timestamp standardization
- Phase 10 (Intelligence Pipeline): RSS news pipeline (27→30 curated feeds, no API key needed), enhanced keyword→node matching with word boundaries/exclusions/confidence scoring, source reliability tiers in agent prompts, morning brief (daily intelligence summary with LLM narrative), news trending detection (auto-trigger agent on 3+ source convergence), automation toggles UI (runtime scheduler control)
- Phase 11 (Agent Intelligence): Pre-fetch data package (FRED + yfinance + RSS injected into agent prompt before it starts), batch sentiment update tool (84→33 tool calls), filled all 10 empty nodes with data sources (FRED: UMCSENT, CES0500000003 + 40 keyword rules + 3 RSS feeds), evidence panel provenance (real/mock/inferred per source per node), increased round budget (25→35), camera reset on background click
- Phase 12 (Hardening III): 10 bug fixes (missing Prediction import, FRED series mismatch, batch lock race condition, WebSocket broadcast concurrency, agent timeout, prediction source filter, validate_consistency neighbor coverage), RSS evidence pipeline (agent now cites Bloomberg/Reuters/CNBC in evidence text), evidence accumulation (20 entries per node instead of overwrite), tool call outputs stored in agent runs for audit/export, data_sources provenance fixed (FRED_SERIES_MAP import was missing — pre-fetch silently failed every run), LLM token limit increased (4096→8192)
- Phase 13 (Hardening IV + Data Pipeline): 16 bug fixes (LLM API error handling with retry/timeout, graph state rollback on agent error, batch propagation cascade fix, concurrent scheduler agent semaphore, accept_suggestion graph lock, missing run_analysis import, broadcast task tracking, annotation error handling, WebSocket effect stabilization, SentimentChart dynamic import catch, Graph3D linkColor performance O(n)→O(1) via nodeMap), yfinance expansion (13→21 tickers: EURUSD=X, USDJPY=X, USDCNY=X, ^MOVE, ^SKEW, ^VIX, HYG, LQD), richer market data (5-day trend/range per ticker), agent prompt optimization (
80→25 tool calls: batch-first mandate, removed redundant fetch instructions), FRED series sync (MANEMP added to scheduler) - Phase 14 (Scenario Engine — "Macro Sim"): Scenario extrapolation agent (4-phase multi-agent: research → history → generation → mapping), "generate first, map second" design, multi-shock simulate, branching scenarios, editable shocks, quick triggers from RSS, scenario history, WebSocket progress, ScenarioPanel UI
- Phase 15 (Scenario Intelligence): 10 improvements (economic calendar tool, options positioning tool, date/market injection, expanded Mapper prompt, cross-branch coherence, non-linear shock model, convergence detection, edge suggestion fix, comparison view, scenario chaining) + topic diversity fix (12 domain queries, diversity mandate, recent trigger avoidance)
- Edge discovery — agent suggests new causal links from correlation anomalies (EdgeSuggestion model + TopologySuggestions.tsx already exist and are wired)
- Seasonal anomaly adjustment — CPI, unemployment have seasonal patterns; current 2σ detector spams false positives
- Frontend polish — node shapes actually rendered, per-panel error boundaries
- Integration tests — API endpoints, agent reasoning, WebSocket
- Multi-agent architecture: Adds complexity without solving core value problem — nail single-agent first
- Authentication/multi-tenant: Premature — nail single-user experience first
- More nodes: 52 is already a lot to reason about; adding more increases noise