diff --git a/frontend/src/components/signals/BacktestPanel.tsx b/frontend/src/components/signals/BacktestPanel.tsx index a777f58..8155ea2 100644 --- a/frontend/src/components/signals/BacktestPanel.tsx +++ b/frontend/src/components/signals/BacktestPanel.tsx @@ -42,8 +42,19 @@ export function BacktestPanel() { const monitor = report?.portfolio_monitor ?? null; const activeStrategy = selectedStrategy || monitor?.production_strategy || monitor?.strategies[0]?.strategy || ''; + // Default to the window the recommendation was computed on, so the tiles and + // the recommendation never open showing different numbers. They used to: the + // backend preferred "all" while this defaulted to "3y". The 3y fallback is + // only for reports predating basis_lookback. + const basisLookback = report?.recommendation?.basis_lookback ?? null; const activeLookback = - selectedLookback || (monitor?.lookbacks.some((l) => l.lookback === '3y') ? '3y' : monitor?.lookbacks[0]?.lookback) || ''; + selectedLookback || + (basisLookback && monitor?.lookbacks.some((l) => l.lookback === basisLookback) + ? basisLookback + : monitor?.lookbacks.some((l) => l.lookback === '3y') + ? '3y' + : monitor?.lookbacks[0]?.lookback) || + ''; const monitorRun = useMemo( () => monitor?.runs.find((row) => row.strategy === activeStrategy && row.lookback === activeLookback) ?? @@ -175,6 +186,9 @@ export function BacktestPanel() { activeLookback={activeLookback} onStrategyChange={setSelectedStrategy} onLookbackChange={setSelectedLookback} + basisLookback={basisLookback} + basisLookbackLabel={report.recommendation?.basis_lookback_label ?? null} + productionStrategy={monitor?.production_strategy ?? null} /> {report.recommendation && ( diff --git a/frontend/src/components/signals/BacktestRecommendationCard.tsx b/frontend/src/components/signals/BacktestRecommendationCard.tsx index 6a621f5..e4e9b2e 100644 --- a/frontend/src/components/signals/BacktestRecommendationCard.tsx +++ b/frontend/src/components/signals/BacktestRecommendationCard.tsx @@ -81,7 +81,16 @@ export function BacktestRecommendationCard({

What this backtest recommends

- {warningCount > 0 ? ( + {/* No headline means the backend found no production monitor row, so + nothing here describes the production book. Zero keyword warnings + is then absence of data, not a clean bill of health — a green chip + beside "this report predates the portfolio monitor" would be a + success badge for missing data. */} + {!recommendation.headline ? ( + + baseline unavailable + + ) : warningCount > 0 ? ( ⚠ {warningCount} warning{warningCount > 1 ? 's' : ''} diff --git a/frontend/src/components/signals/PortfolioMonitorPanel.tsx b/frontend/src/components/signals/PortfolioMonitorPanel.tsx index 091ba3b..63874cb 100644 --- a/frontend/src/components/signals/PortfolioMonitorPanel.tsx +++ b/frontend/src/components/signals/PortfolioMonitorPanel.tsx @@ -30,6 +30,9 @@ export function PortfolioMonitorPanel({ activeLookback, onStrategyChange, onLookbackChange, + basisLookback = null, + basisLookbackLabel = null, + productionStrategy = null, }: { monitor: BacktestPortfolioMonitor | null | undefined; monitorRun: BacktestPortfolioMonitorRun | null | undefined; @@ -37,6 +40,10 @@ export function PortfolioMonitorPanel({ activeLookback: string; onStrategyChange: (v: string) => void; onLookbackChange: (v: string) => void; + /** The window the recommendation below was computed on. */ + basisLookback?: string | null; + basisLookbackLabel?: string | null; + productionStrategy?: string | null; }) { if (!monitor || !monitorRun) { return ( @@ -90,6 +97,21 @@ export function PortfolioMonitorPanel({
+ {/* The recommendation below is baked into the report and cannot follow a + dropdown. On load the two agree by construction; say so plainly the + moment a selection moves off that basis. */} + {((basisLookback && activeLookback !== basisLookback) || + (productionStrategy && activeStrategy !== productionStrategy)) && ( +

+ Showing{' '} + {productionStrategy && activeStrategy !== productionStrategy + ? 'a comparison strategy' + : 'a different window'} + . The recommendation below is computed on the production strategy over{' '} + {basisLookbackLabel ?? basisLookback} — these tiles will not match it. +

+ )} + {/* Tier 1 — what the book returned. */}