New grammar panel replaces free-text AI prompt with a two-step workflow:
1. NL to Grammar: GPT-4o converts description to patch ops (new endpoint ai-to-grammar)
2. Apply: frontend parser applies grammar locally without AI
Grammar syntax: (+|-|~)(node|edge|coef|input|instruments) key=val key=val
Sign shortcuts: + positive, - negative, = neutral
Auto-positions new nodes when x/y omitted.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each /instruments/:id navigation opens a persistent tab in the TabBar.
Multiple instruments can be open simultaneously — state is preserved when switching.
- TabsContext: adds instrumentIds[], openInstrument(), closeInstrument()
- TabBar: renders instrument tabs (teal, monospaced, TrendingUp icon) after static tabs, separated by a divider
- InstrumentDashboard: accepts instrumentIdProp so keep-alive instances use the right id regardless of URL
- App: InstrumentRoute registers the tab on navigation; InstrumentKeepAlive mounts one dashboard per open instrument; NormalRoutes hides on instrument paths (hidden div, Routes still fires)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Library:
- Color chip filters: category (with per-category colors), sub_type, instrument
- Date range filter (created_at) + text search
- Category labels unified to cover event_calendar, fundamental, calendar_event etc.
- Editer button on selected template → opens in editor tab
- Show created_at + created_by in template detail
Editor:
- Accepts initialId prop so Library can pre-load a template
- AI Modify zone: textarea prompt + button calls /api/causal-lab/template/{id}/ai-modify
- Returns modified graph_json from GPT-4o, applied live — user reviews then saves
Backend:
- New POST /api/causal-lab/template/{id}/ai-modify endpoint
- Sends current graph_json + user prompt to GPT-4o
- Returns validated modified graph_json (nodes/edges required)
- Does not auto-save (user controls save)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The filtered event dict was built with explicit fields and omitted these two columns,
so the frontend always received null despite the DB having valid data.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
YFINANCE_MAP now includes GBPUSD, USDJPY, USDCHF, AUDUSD, NZDUSD, USDCAD, XAGUSD, NASDAQ, DAX, FTSE, WTI, US30Y, DXY.
Frontend diagnostic panel shows db_state rows after Recalculer and raw prediction_json prefix per event.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- refreshDebug state lives in parent (InstrumentDashboard) so it survives
fetchSnapshotSilent re-render (ExplanationScore no longer loses debugInfo
when onRefreshDone triggers setLoading → unmount)
- fetchSnapshotSilent: re-fetches snapshot without setLoading(true) so
ExplanationScore stays mounted with its state
- Refresh filter now catches rows where prediction_json is empty even if
actual_json is populated, and handles '[]' / null variants
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
_run_auto_analysis now returns a rich dict {ok, inputs, node_values, actual_moves, error}
instead of bool. The refresh endpoint captures and forwards:
- inputs: what values were fed to evaluate_graph
- node_keys: which nodes were computed in prediction
- actual_moves: actual price pips fetched
- run_error: exception message if it failed
Frontend shows all of this after clicking Recalculer so the root cause is visible.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Auto-generated templates had no lag_days on edges → effective_lag_days=0 →
_drift_metrics used exact-date daily bar (often empty) → actual_json='{}' →
comprehensionScore returned null even after prediction_json was populated.
- Default effective_lag_days=5 when computed as 0 in _run_auto_analysis
- Add lag_days:3 to all auto-generated template edges in _build_graph_json_from_spec
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Events with surprise_pct=NULL (bootstrap or older events) got inputs={} → evaluate_graph
returned {} → prediction_json='{}' → all scores showed 'En attente'.
Three-step fallback in _run_auto_analysis:
1. Use event.surprise_pct if set (existing behaviour)
2. Compute from actual_value / expected_value stored in market_events
3. Look up most recent ff_calendar release by currency + date
Frontend diagnostic now shows surprise_pct per event and exposes actual/expected
in the refresh result panel to make the source visible.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>