@burdenoff/microfe-brainyrich 2026.731.1 → 2026.731.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1142,7 +1142,8 @@ function it({ opportunity: e }) {
1142
1142
  children: [
1143
1143
  "Market value ",
1144
1144
  h(e.marketValue),
1145
- " vs. cost basis ",
1145
+ " vs. cost basis",
1146
+ " ",
1146
1147
  h(e.costBasis),
1147
1148
  " · ",
1148
1149
  g(e.lossPctOfPortfolio),
@@ -1 +1 @@
1
- {"version":3,"file":"RiskPage.js","names":[],"sources":["../../../src/brainyrich/pages/RiskPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n Textarea,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Activity,\n AlertTriangle,\n ArrowRight,\n Check,\n Eye,\n Gauge,\n Layers,\n MoreHorizontal,\n Plus,\n RefreshCw,\n Scale,\n Scissors,\n ShieldAlert,\n ShieldCheck,\n Sparkles,\n TrendingUp,\n X,\n} from 'lucide-react';\nimport {\n useRebalanceProposals,\n usePortfolios,\n usePagedInsights,\n useCreateRebalanceProposal,\n useTransitionRebalanceProposal,\n useAcknowledgeInsight,\n useDismissInsight,\n useResolveInsight,\n usePortfolioRiskSignals,\n useGenerateRiskInsights,\n usePortfolioRiskSummary,\n useTaxLossOpportunities,\n useHarvestTaxLossInsights,\n} from '../hooks/useBrainyRichApi';\nimport type {\n BraPortfolio,\n BraRebalanceProposal,\n BraRebalanceStatus,\n BraInsight,\n BraInsightSeverity,\n BraInsightType,\n BraRiskSignal,\n BraTaxLossOpportunity,\n} from '../types/bra';\nimport {\n SectionShell,\n EmptyState,\n LoadingState,\n ErrorState,\n formatMoney,\n formatPct,\n formatDate,\n statusBadgeVariant,\n} from './_shared';\nimport {\n ConfirmDialog,\n ActorName,\n LoadMore,\n StatTile,\n GlassCard,\n FadeIn,\n DonutChart,\n LifecycleStepper,\n type VizTone,\n type DonutDatum,\n} from '../components';\nimport { CommentThread } from '../components/reuse/CommentThread';\n\n// ============================================================================\n// Domain rules (derived from the SDL enum, not fabricated data)\n// ============================================================================\n\n/** Valid forward/side transitions per current rebalance status. Terminal states map to []. */\nconst NEXT_STATUSES: Record<BraRebalanceStatus, BraRebalanceStatus[]> = {\n DRAFT: ['PROPOSED', 'CANCELLED'],\n PROPOSED: ['APPROVED', 'REJECTED', 'CANCELLED'],\n APPROVED: ['EXECUTED', 'CANCELLED'],\n REJECTED: [],\n EXECUTED: [],\n CANCELLED: [],\n};\n\n/** Insight types that belong on the risk/rebalancing surface. */\nconst RISK_INSIGHT_TYPES: BraInsightType[] = [\n 'DRIFT',\n 'CONCENTRATION_RISK',\n 'REBALANCE_DUE',\n 'CASH_DRAG',\n 'FEE_ANOMALY',\n];\nconst RISK_INSIGHT_TYPE_SET = new Set<BraInsightType>(RISK_INSIGHT_TYPES);\n\nfunction humanize(value: string): string {\n return value\n .toLowerCase()\n .split('_')\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1))\n .join(' ');\n}\n\n/** Lifecycle chart stages (forward path). Side states handled by the stepper. */\nconst LIFECYCLE_STEPS = ['Draft', 'Proposed', 'Approved', 'Executed'];\n\n/** Categorical donut tone per proposal status (distinct emerald-brand-first hues). */\nconst STATUS_TONE: Record<BraRebalanceStatus, VizTone> = {\n DRAFT: 'neutral',\n PROPOSED: 'warning',\n APPROVED: 'blue',\n EXECUTED: 'success',\n REJECTED: 'error',\n CANCELLED: 'neutral',\n};\n\nconst STATUS_ORDER: BraRebalanceStatus[] = [\n 'PROPOSED',\n 'DRAFT',\n 'APPROVED',\n 'EXECUTED',\n 'REJECTED',\n 'CANCELLED',\n];\n\n/** Donut tone per insight severity. */\nconst SEVERITY_TONE: Record<BraInsightSeverity, VizTone> = {\n CRITICAL: 'error',\n HIGH: 'warning',\n MEDIUM: 'info',\n LOW: 'teal',\n INFO: 'neutral',\n};\n\nconst SEVERITY_ORDER: BraInsightSeverity[] = ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW', 'INFO'];\n\n/** A best-effort structured trade row parsed from the opaque `trades` JSON. */\ninterface TradeRow {\n action?: string;\n symbol?: string;\n quantity?: number;\n value?: number;\n}\n\n/**\n * Parse the opaque `trades` scalar into structured rows WITHOUT inventing data:\n * only keys actually present on each object are surfaced. Returns null when the\n * value is not an array of plain objects (callers fall back to a text summary).\n */\nfunction parseTrades(trades: unknown): TradeRow[] | null {\n if (!Array.isArray(trades) || trades.length === 0) return null;\n const rows: TradeRow[] = [];\n for (const item of trades) {\n if (!item || typeof item !== 'object' || Array.isArray(item)) return null;\n const t = item as Record<string, unknown>;\n const get = (keys: string[]): unknown => {\n for (const k of Object.keys(t)) {\n if (keys.includes(k.toLowerCase())) return t[k];\n }\n return undefined;\n };\n const action = get(['action', 'side', 'type']);\n const symbol = get(['symbol', 'ticker', 'asset', 'instrument']);\n const quantity = get(['quantity', 'qty', 'shares', 'units']);\n const value = get(['value', 'notional', 'amount', 'total', 'marketvalue']);\n rows.push({\n action: typeof action === 'string' ? action : undefined,\n symbol: typeof symbol === 'string' ? symbol : undefined,\n quantity: typeof quantity === 'number' ? quantity : undefined,\n value: typeof value === 'number' ? value : undefined,\n });\n }\n return rows;\n}\n\n/**\n * Render one entry of a `BraRiskSignal.metrics` object without inventing\n * formatting rules per-key: numbers render as plain locale numbers (2dp when\n * fractional), booleans as Yes/No, everything else as-is. This is the ONLY\n * place the deterministic engine's real inputs/formula reach the screen —\n * never replaced by a derived/opaque display value.\n */\nfunction formatMetricValue(value: unknown): string {\n if (value === null || value === undefined) return '—';\n if (typeof value === 'number') {\n return Number.isInteger(value)\n ? value.toLocaleString()\n : value.toLocaleString(undefined, { maximumFractionDigits: 2 });\n }\n if (typeof value === 'boolean') return value ? 'Yes' : 'No';\n if (typeof value === 'string') return value;\n return JSON.stringify(value);\n}\n\n/** Semantic tone for a trade action (color is never the only signal). */\nfunction tradeActionTone(action: string | undefined): string {\n const a = (action ?? '').toUpperCase();\n if (a.includes('BUY') || a.includes('ADD')) return 'text-status-success-text';\n if (a.includes('SELL') || a.includes('TRIM') || a.includes('REDUCE'))\n return 'text-status-error-text';\n return 'text-text-secondary';\n}\n\n/** Summarize the opaque `trades` JSON scalar without inventing data. */\nfunction summarizeTrades(trades: unknown): string {\n if (trades == null) return '—';\n if (Array.isArray(trades)) {\n return `${trades.length} trade${trades.length === 1 ? '' : 's'}`;\n }\n if (typeof trades === 'object') {\n const n = Object.keys(trades as Record<string, unknown>).length;\n return `${n} field${n === 1 ? '' : 's'}`;\n }\n return String(trades);\n}\n\n// ============================================================================\n// Create-proposal form\n// ============================================================================\n\ninterface ProposalFormState {\n portfolioId: string;\n driftPct: string;\n rationale: string;\n trades: string;\n}\n\nconst EMPTY_PROPOSAL_FORM: ProposalFormState = {\n portfolioId: '',\n driftPct: '',\n rationale: '',\n trades: '',\n};\n\nfunction parseNum(value: string): number | undefined {\n if (value.trim() === '') return undefined;\n const n = Number(value);\n return Number.isFinite(n) ? n : undefined;\n}\n\nexport function RiskPage() {\n const {\n data: proposals,\n isLoading: proposalsLoading,\n isError: proposalsError,\n refetch: refetchProposals,\n } = useRebalanceProposals();\n\n const { data: portfolios } = usePortfolios();\n\n // ---- BOFF-4236: deterministic risk-signal engine + optional AI summary ----\n // Defaults to the first portfolio until the user explicitly picks one — a\n // derived value (not synced via effect) so there's no cascading-render setState.\n const [manualRiskPortfolioId, setManualRiskPortfolioId] = useState<string | undefined>(undefined);\n const riskPortfolioId = manualRiskPortfolioId ?? portfolios[0]?.id ?? '';\n\n const {\n data: riskReport,\n isLoading: riskLoading,\n isError: riskError,\n refetch: refetchRisk,\n } = usePortfolioRiskSignals(riskPortfolioId || undefined);\n const generateRiskInsights = useGenerateRiskInsights();\n const {\n data: riskSummary,\n isFetching: riskSummaryFetching,\n refetch: refetchRiskSummary,\n } = usePortfolioRiskSummary(riskPortfolioId || undefined);\n\n // ---- BOFF-4237: configurable tax-loss-harvesting detector + wash-sale caution ----\n const {\n data: taxLossReport,\n isLoading: taxLossLoading,\n isError: taxLossError,\n refetch: refetchTaxLoss,\n } = useTaxLossOpportunities(riskPortfolioId || undefined);\n const harvestTaxLossInsights = useHarvestTaxLossInsights();\n\n const {\n items: insights,\n hasMore: insightsHasMore,\n loadMore: loadMoreInsights,\n isLoading: insightsLoading,\n isFetchingNextPage: insightsFetchingMore,\n isError: insightsError,\n refetch: refetchInsights,\n } = usePagedInsights();\n\n const createProposal = useCreateRebalanceProposal();\n const transitionProposal = useTransitionRebalanceProposal();\n const acknowledgeInsight = useAcknowledgeInsight();\n const dismissInsight = useDismissInsight();\n const resolveInsight = useResolveInsight();\n\n const [createOpen, setCreateOpen] = useState(false);\n const [form, setForm] = useState<ProposalFormState>(EMPTY_PROPOSAL_FORM);\n const [tradesError, setTradesError] = useState<string | null>(null);\n const [detailProposal, setDetailProposal] = useState<BraRebalanceProposal | null>(null);\n const [confirmTransition, setConfirmTransition] = useState<{\n proposal: BraRebalanceProposal;\n status: BraRebalanceStatus;\n } | null>(null);\n\n // Portfolio lookup for names + drift thresholds (real backend data).\n const portfolioById = useMemo(() => {\n const map = new Map<string, BraPortfolio>();\n for (const p of portfolios) map.set(p.id, p);\n return map;\n }, [portfolios]);\n\n const riskInsights = useMemo(\n () => insights.filter((i) => RISK_INSIGHT_TYPE_SET.has(i.type)),\n [insights]\n );\n\n const activeProposals = proposals.filter(\n (p) => p.status === 'DRAFT' || p.status === 'PROPOSED' || p.status === 'APPROVED'\n );\n const openInsights = riskInsights.filter((i) => i.status === 'OPEN');\n const avgDrift =\n proposals.length > 0\n ? proposals.reduce((sum, p) => sum + (p.driftPct ?? 0), 0) / proposals.length\n : null;\n\n // Breach count drives the drift tile's tone (real: drift ≥ portfolio threshold).\n const breachedCount = useMemo(\n () =>\n proposals.filter((p) => {\n const threshold = portfolioById.get(p.portfolioId)?.driftThresholdPct;\n return threshold != null && Number.isFinite(threshold) && p.driftPct >= threshold;\n }).length,\n [proposals, portfolioById]\n );\n\n // Real drift series (chronological) — decorative sparkline on the drift KPI.\n const driftSeries = useMemo(\n () =>\n [...proposals]\n .sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime())\n .map((p) => p.driftPct)\n .filter((n) => Number.isFinite(n)),\n [proposals]\n );\n\n // Proposal pipeline distribution (real counts by lifecycle status).\n const statusDonut = useMemo<DonutDatum[]>(() => {\n const counts = new Map<BraRebalanceStatus, number>();\n for (const p of proposals) counts.set(p.status, (counts.get(p.status) ?? 0) + 1);\n return STATUS_ORDER.filter((s) => (counts.get(s) ?? 0) > 0).map((s) => ({\n label: humanize(s),\n value: counts.get(s) ?? 0,\n tone: STATUS_TONE[s],\n }));\n }, [proposals]);\n\n // Open risk-signal distribution (real counts by severity).\n const severityDonut = useMemo<DonutDatum[]>(() => {\n const counts = new Map<BraInsightSeverity, number>();\n for (const i of openInsights) counts.set(i.severity, (counts.get(i.severity) ?? 0) + 1);\n return SEVERITY_ORDER.filter((s) => (counts.get(s) ?? 0) > 0).map((s) => ({\n label: humanize(s),\n value: counts.get(s) ?? 0,\n tone: SEVERITY_TONE[s],\n }));\n }, [openInsights]);\n\n const canCreate = portfolios.length > 0;\n\n function openCreate() {\n setForm(EMPTY_PROPOSAL_FORM);\n setTradesError(null);\n setCreateOpen(true);\n }\n\n function submitCreate() {\n if (!form.portfolioId) return;\n let trades: unknown;\n if (form.trades.trim() !== '') {\n try {\n trades = JSON.parse(form.trades);\n } catch {\n setTradesError('Trades must be valid JSON.');\n return;\n }\n }\n const portfolio = portfolioById.get(form.portfolioId);\n createProposal.mutate(\n {\n portfolioId: form.portfolioId,\n householdId: portfolio?.householdId ?? null,\n driftPct: parseNum(form.driftPct),\n rationale: form.rationale.trim() || null,\n ...(trades !== undefined ? { trades } : {}),\n },\n { onSuccess: () => setCreateOpen(false) }\n );\n }\n\n /** Destructive transitions (reject/cancel) confirm first; forward transitions fire directly. */\n function requestTransition(proposal: BraRebalanceProposal, status: BraRebalanceStatus) {\n if (status === 'REJECTED' || status === 'CANCELLED') {\n setConfirmTransition({ proposal, status });\n return;\n }\n transitionProposal.mutate({ id: proposal.id, status });\n }\n\n /** Drift is a breach when it meets/exceeds the portfolio's configured threshold. */\n function driftBreached(p: BraRebalanceProposal): boolean {\n const threshold = portfolioById.get(p.portfolioId)?.driftThresholdPct;\n return threshold != null && Number.isFinite(threshold) && p.driftPct >= threshold;\n }\n\n return (\n <SectionShell\n title=\"Risk & Rebalancing\"\n description=\"Review drift-driven rebalance proposals and act on portfolio risk insights.\"\n badges={[\n `${activeProposals.length} active`,\n `${openInsights.length} open insight${openInsights.length === 1 ? '' : 's'}`,\n ]}\n actionLabel=\"New proposal\"\n onAction={openCreate}\n >\n {/* Premium KPI row */}\n <div className=\"grid gap-4 sm:grid-cols-2 xl:grid-cols-4\">\n <FadeIn index={0}>\n <StatTile\n label=\"Average drift\"\n value={avgDrift === null ? '—' : formatPct(avgDrift)}\n spark={driftSeries.length > 1 ? driftSeries : undefined}\n sparkTone={breachedCount > 0 ? 'error' : 'brand'}\n glow\n icon={<Gauge className=\"size-4\" aria-hidden=\"true\" />}\n />\n </FadeIn>\n <FadeIn index={1}>\n <StatTile\n label=\"Active proposals\"\n value={String(activeProposals.length)}\n icon={<Activity className=\"size-4\" aria-hidden=\"true\" />}\n />\n </FadeIn>\n <FadeIn index={2}>\n <StatTile\n label=\"Total proposals\"\n value={String(proposals.length)}\n icon={<Layers className=\"size-4\" aria-hidden=\"true\" />}\n />\n </FadeIn>\n <FadeIn index={3}>\n <StatTile\n label=\"Open risk insights\"\n value={String(openInsights.length)}\n deltaTone={openInsights.length > 0 ? 'negative' : 'neutral'}\n icon={<ShieldAlert className=\"size-4\" aria-hidden=\"true\" />}\n />\n </FadeIn>\n </div>\n\n {/* Hero band — pipeline + risk-signal distribution donuts */}\n {(statusDonut.length > 0 || severityDonut.length > 0) && !proposalsLoading ? (\n <div className=\"grid gap-4 lg:grid-cols-2\">\n <FadeIn index={0}>\n <GlassCard glow className=\"h-full\">\n <div className=\"mb-3 flex items-center gap-2\">\n <TrendingUp className=\"size-4 text-text-secondary\" aria-hidden=\"true\" />\n <h2 className=\"text-sm font-semibold text-text-primary\">Proposal pipeline</h2>\n </div>\n <DonutChart\n data={statusDonut}\n centerValue={String(proposals.length)}\n centerLabel=\"proposals\"\n height={200}\n />\n </GlassCard>\n </FadeIn>\n <FadeIn index={1}>\n <GlassCard className=\"h-full\">\n <div className=\"mb-3 flex items-center gap-2\">\n <ShieldAlert className=\"size-4 text-text-secondary\" aria-hidden=\"true\" />\n <h2 className=\"text-sm font-semibold text-text-primary\">Open risk signals</h2>\n </div>\n {severityDonut.length > 0 ? (\n <DonutChart\n data={severityDonut}\n centerValue={String(openInsights.length)}\n centerLabel=\"open\"\n height={200}\n />\n ) : (\n <div className=\"flex h-[200px] flex-col items-center justify-center gap-2 text-center\">\n <ShieldCheck className=\"size-8 text-status-success-text\" aria-hidden=\"true\" />\n <p className=\"text-sm text-text-secondary\">No open risk signals.</p>\n </div>\n )}\n </GlassCard>\n </FadeIn>\n </div>\n ) : null}\n\n {/* Portfolio risk signals (BOFF-4236) — deterministic engine + optional AI summary */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Gauge className=\"h-5 w-5\" aria-hidden=\"true\" />\n Portfolio risk signals\n </CardTitle>\n <CardDescription>\n Real, explainable signals computed live from this portfolio&apos;s own holdings and\n target allocation — every signal below shows the real inputs and formula/threshold\n behind it. Informational only, never a buy/sell recommendation.\n </CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"min-w-[220px] space-y-1.5\">\n <Label htmlFor=\"risk-portfolio\">Portfolio</Label>\n <Select value={riskPortfolioId} onValueChange={setManualRiskPortfolioId}>\n <SelectTrigger id=\"risk-portfolio\">\n <SelectValue placeholder=\"Select a portfolio\" />\n </SelectTrigger>\n <SelectContent>\n {portfolios.map((p) => (\n <SelectItem key={p.id} value={p.id}>\n {p.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"mt-auto\"\n disabled={!riskPortfolioId || riskLoading}\n onClick={() => refetchRisk()}\n >\n <RefreshCw className=\"size-4\" aria-hidden=\"true\" />\n Recompute\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"mt-auto\"\n disabled={\n !riskPortfolioId ||\n (riskReport?.signals.length ?? 0) === 0 ||\n generateRiskInsights.isPending\n }\n onClick={() => generateRiskInsights.mutate(riskPortfolioId)}\n >\n <ShieldAlert className=\"size-4\" aria-hidden=\"true\" />\n {generateRiskInsights.isPending ? 'Saving…' : 'Save as insights'}\n </Button>\n </div>\n\n {portfolios.length === 0 ? (\n <EmptyState\n icon={<Gauge className=\"size-6\" aria-hidden=\"true\" />}\n title=\"No portfolios yet\"\n description=\"Create a portfolio to compute real risk signals from its holdings.\"\n />\n ) : riskLoading ? (\n <LoadingState />\n ) : riskError ? (\n <ErrorState onRetry={() => refetchRisk()} />\n ) : riskReport ? (\n <div className=\"space-y-4\">\n <div className=\"grid gap-3 sm:grid-cols-3\">\n <StatTile\n label=\"Portfolio value\"\n value={formatMoney(riskReport.totalValue)}\n icon={<Layers className=\"size-4\" aria-hidden=\"true\" />}\n />\n <StatTile\n label=\"Holdings considered\"\n value={String(riskReport.holdingsConsidered)}\n icon={<Activity className=\"size-4\" aria-hidden=\"true\" />}\n />\n <StatTile\n label=\"Signals breached\"\n value={String(riskReport.signals.length)}\n deltaTone={riskReport.signals.length > 0 ? 'negative' : 'neutral'}\n icon={<ShieldAlert className=\"size-4\" aria-hidden=\"true\" />}\n />\n </div>\n\n {riskReport.signals.length === 0 ? (\n <EmptyState\n icon={<ShieldCheck className=\"size-6\" aria-hidden=\"true\" />}\n title=\"No configured threshold was breached\"\n description=\"This portfolio's concentration, cash, drift and unrealized-loss metrics are all within their configured thresholds.\"\n />\n ) : (\n <ul className=\"space-y-3\">\n {riskReport.signals.map((signal, i) => (\n <RiskSignalRow key={`${signal.kind}-${i}`} signal={signal} />\n ))}\n </ul>\n )}\n\n {/* Optional AI-generated plain-language summary of the signals above */}\n <div className=\"rounded-xl border border-border-subtle bg-bg-surface p-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <div className=\"flex items-center gap-2\">\n <Sparkles className=\"size-4 text-text-secondary\" aria-hidden=\"true\" />\n <h3 className=\"text-sm font-semibold text-text-primary\">AI summary</h3>\n <span className=\"text-xs text-text-muted\">\n (optional — plain-language restatement of the signals above; never a source of\n numbers)\n </span>\n </div>\n <Button\n variant=\"outline\"\n size=\"sm\"\n disabled={!riskPortfolioId || riskSummaryFetching}\n onClick={() => refetchRiskSummary()}\n >\n <Sparkles className=\"size-4\" aria-hidden=\"true\" />\n {riskSummaryFetching ? 'Generating…' : 'Generate AI summary'}\n </Button>\n </div>\n {riskSummaryFetching ? (\n <p className=\"mt-2 text-sm text-text-secondary\">Asking the AI provider…</p>\n ) : riskSummary?.generated ? (\n <div className=\"mt-2 space-y-1\">\n <p className=\"text-sm text-text-primary\">{riskSummary.summary}</p>\n <p className=\"text-xs text-text-muted\">\n AI-generated commentary\n {riskSummary.provider ? ` · ${riskSummary.provider}` : ''} · based on{' '}\n {riskSummary.signalsConsidered} computed signal\n {riskSummary.signalsConsidered === 1 ? '' : 's'} above\n </p>\n </div>\n ) : riskSummary && !riskSummary.generated ? (\n <p className=\"mt-2 text-sm text-text-secondary\">\n AI summary unavailable — {riskSummary.reason ?? 'no provider configured'}. The\n deterministic signals above are unaffected.\n </p>\n ) : (\n <p className=\"mt-2 text-sm text-text-muted\">\n Not generated yet. The deterministic signals above always work without this.\n </p>\n )}\n </div>\n </div>\n ) : (\n <EmptyState\n icon={<Gauge className=\"size-6\" aria-hidden=\"true\" />}\n title=\"Select a portfolio\"\n description=\"Choose a portfolio above to compute its real risk signals.\"\n />\n )}\n </CardContent>\n </Card>\n\n {/* Tax-loss-harvesting opportunities (BOFF-4237) — configurable thresholds + wash-sale caution */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Scissors className=\"h-5 w-5\" aria-hidden=\"true\" />\n Tax-loss-harvesting opportunities\n </CardTitle>\n <CardDescription>\n Real unrealized-loss detection for the selected portfolio, using configurable dollar/percent\n thresholds and a wash-sale caution flag from your recorded transactions. Detection only — this\n never places a trade, and it is not tax advice.\n </CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n disabled={!riskPortfolioId || taxLossLoading}\n onClick={() => refetchTaxLoss()}\n >\n <RefreshCw className=\"size-4\" aria-hidden=\"true\" />\n Recompute\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n disabled={\n !riskPortfolioId ||\n (taxLossReport?.opportunities.length ?? 0) === 0 ||\n harvestTaxLossInsights.isPending\n }\n onClick={() => harvestTaxLossInsights.mutate({ portfolioId: riskPortfolioId })}\n >\n <ShieldAlert className=\"size-4\" aria-hidden=\"true\" />\n {harvestTaxLossInsights.isPending ? 'Saving…' : 'Save as insights'}\n </Button>\n {taxLossReport ? (\n <span className=\"text-xs text-text-muted\">\n Thresholds: ≥{formatMoney(taxLossReport.thresholds.minLossAmount)} or ≥\n {formatPct(taxLossReport.thresholds.minLossPct)} of portfolio value\n </span>\n ) : null}\n </div>\n\n {portfolios.length === 0 ? (\n <EmptyState\n icon={<Scissors className=\"size-6\" aria-hidden=\"true\" />}\n title=\"No portfolios yet\"\n description=\"Create a portfolio to detect real tax-loss-harvesting opportunities from its holdings.\"\n />\n ) : taxLossLoading ? (\n <LoadingState />\n ) : taxLossError ? (\n <ErrorState onRetry={() => refetchTaxLoss()} />\n ) : taxLossReport && taxLossReport.opportunities.length > 0 ? (\n <ul className=\"space-y-3\">\n {taxLossReport.opportunities.map((opp) => (\n <TaxLossOpportunityRow key={opp.symbol} opportunity={opp} />\n ))}\n </ul>\n ) : taxLossReport ? (\n <EmptyState\n icon={<ShieldCheck className=\"size-6\" aria-hidden=\"true\" />}\n title=\"No opportunities at the current thresholds\"\n description=\"No symbol's unrealized loss clears the configured dollar/percent thresholds.\"\n />\n ) : (\n <EmptyState\n icon={<Scissors className=\"size-6\" aria-hidden=\"true\" />}\n title=\"Select a portfolio\"\n description=\"Choose a portfolio above to detect real tax-loss opportunities.\"\n />\n )}\n </CardContent>\n </Card>\n\n {/* Rebalance proposals */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Scale className=\"h-5 w-5\" aria-hidden=\"true\" />\n Rebalance proposals\n </CardTitle>\n <CardDescription>\n Drift against target allocation, with lifecycle actions per proposal.\n </CardDescription>\n </CardHeader>\n <CardContent>\n {proposalsLoading ? (\n <LoadingState />\n ) : proposalsError ? (\n <ErrorState onRetry={() => refetchProposals()} />\n ) : proposals.length === 0 ? (\n <EmptyState\n icon={<Scale className=\"size-6\" aria-hidden=\"true\" />}\n title=\"No rebalance proposals\"\n description={\n canCreate\n ? 'Create a proposal when a portfolio drifts from its target allocation.'\n : 'Create a portfolio first, then propose a rebalance when it drifts.'\n }\n action={\n canCreate ? (\n <Button size=\"sm\" onClick={openCreate}>\n <Plus className=\"size-4\" aria-hidden=\"true\" />\n New proposal\n </Button>\n ) : undefined\n }\n />\n ) : (\n <div className=\"overflow-x-auto\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>Portfolio</TableHead>\n <TableHead className=\"text-right\">Drift</TableHead>\n <TableHead>Status</TableHead>\n <TableHead>Rationale</TableHead>\n <TableHead>Trades</TableHead>\n <TableHead>Created</TableHead>\n <TableHead className=\"w-12 text-right\">Actions</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {proposals.map((p) => {\n const portfolio = portfolioById.get(p.portfolioId);\n const breached = driftBreached(p);\n const nextStatuses = NEXT_STATUSES[p.status];\n const threshold = portfolio?.driftThresholdPct;\n const meterPct =\n threshold != null && threshold > 0\n ? Math.min(100, (p.driftPct / threshold) * 100)\n : null;\n return (\n <TableRow\n key={p.id}\n onClick={() => setDetailProposal(p)}\n className=\"cursor-pointer transition-colors motion-safe:hover:bg-bg-elevated\"\n >\n <TableCell>\n <p className=\"font-medium text-text-primary\">\n {portfolio?.name ?? 'Unknown portfolio'}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {portfolio?.baseCurrency ?? '—'}\n {threshold != null ? ` · threshold ${formatPct(threshold)}` : ''}\n </p>\n </TableCell>\n <TableCell className=\"text-right\">\n <span\n className={`inline-flex items-center justify-end gap-1 font-semibold tabular-nums ${\n breached ? 'text-status-error-text' : 'text-text-primary'\n }`}\n >\n {breached ? (\n <AlertTriangle className=\"size-4\" aria-hidden=\"true\" />\n ) : null}\n {formatPct(p.driftPct)}\n </span>\n {meterPct != null ? (\n <div\n className=\"ml-auto mt-1 h-1.5 w-24 overflow-hidden rounded-full bg-bg-sunken\"\n role=\"progressbar\"\n aria-valuenow={Math.round(meterPct)}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={`Drift vs threshold for ${portfolio?.name ?? 'portfolio'}`}\n >\n <div\n className=\"h-full rounded-full\"\n style={{\n width: `${meterPct}%`,\n background: breached\n ? 'var(--color-status-error)'\n : 'var(--color-action-primary-bg)',\n }}\n />\n </div>\n ) : breached ? (\n <p className=\"text-xs text-status-error-text\">Over threshold</p>\n ) : null}\n </TableCell>\n <TableCell>\n <Badge variant={statusBadgeVariant(p.status)}>{humanize(p.status)}</Badge>\n </TableCell>\n <TableCell className=\"max-w-xs\">\n <p className=\"truncate text-sm text-text-secondary\">\n {p.rationale ?? '—'}\n </p>\n </TableCell>\n <TableCell className=\"text-sm text-text-secondary\">\n {summarizeTrades(p.trades)}\n </TableCell>\n <TableCell className=\"text-sm text-text-secondary\">\n {formatDate(p.createdAt)}\n </TableCell>\n <TableCell className=\"text-right\" onClick={(e) => e.stopPropagation()}>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label={`Actions for ${portfolio?.name ?? 'proposal'}`}\n >\n <MoreHorizontal className=\"size-4\" aria-hidden=\"true\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem onClick={() => setDetailProposal(p)}>\n <Eye className=\"size-4\" aria-hidden=\"true\" />\n View details\n </DropdownMenuItem>\n {nextStatuses.length > 0 ? (\n <>\n <DropdownMenuSeparator />\n <DropdownMenuLabel>Advance to</DropdownMenuLabel>\n {nextStatuses.map((status) => {\n const destructive =\n status === 'REJECTED' || status === 'CANCELLED';\n return (\n <DropdownMenuItem\n key={status}\n disabled={transitionProposal.isPending}\n className={\n destructive ? 'text-status-error-text' : undefined\n }\n onClick={() => requestTransition(p, status)}\n >\n {destructive ? (\n <X className=\"size-4\" aria-hidden=\"true\" />\n ) : (\n <ArrowRight className=\"size-4\" aria-hidden=\"true\" />\n )}\n {humanize(status)}\n </DropdownMenuItem>\n );\n })}\n </>\n ) : null}\n </DropdownMenuContent>\n </DropdownMenu>\n </TableCell>\n </TableRow>\n );\n })}\n </TableBody>\n </Table>\n </div>\n )}\n </CardContent>\n </Card>\n\n {/* Risk insights */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <ShieldAlert className=\"h-5 w-5\" aria-hidden=\"true\" />\n Risk insights\n </CardTitle>\n <CardDescription>\n Drift, concentration, cash-drag and fee-anomaly signals detected across your portfolios.\n </CardDescription>\n </CardHeader>\n <CardContent>\n {insightsLoading ? (\n <LoadingState />\n ) : insightsError ? (\n <ErrorState onRetry={() => refetchInsights()} />\n ) : riskInsights.length === 0 ? (\n <EmptyState\n icon={<ShieldCheck className=\"size-6\" aria-hidden=\"true\" />}\n title=\"No risk insights\"\n description=\"No drift, concentration, cash-drag or fee-anomaly signals are open right now.\"\n />\n ) : (\n <div className=\"space-y-3\">\n {riskInsights.map((insight, i) => (\n <FadeIn key={insight.id} index={i}>\n <InsightRow\n insight={insight}\n onAcknowledge={() => acknowledgeInsight.mutate(insight.id)}\n onResolve={() => resolveInsight.mutate(insight.id)}\n onDismiss={() => dismissInsight.mutate(insight.id)}\n actionPending={\n acknowledgeInsight.isPending ||\n resolveInsight.isPending ||\n dismissInsight.isPending\n }\n />\n </FadeIn>\n ))}\n <LoadMore\n hasMore={insightsHasMore}\n onClick={loadMoreInsights}\n loading={insightsFetchingMore}\n label=\"Load more insights\"\n />\n </div>\n )}\n </CardContent>\n </Card>\n\n {/* Create proposal dialog */}\n <Dialog open={createOpen} onOpenChange={setCreateOpen}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>New rebalance proposal</DialogTitle>\n <DialogDescription>\n Propose a rebalance for a portfolio that has drifted from its target allocation.\n </DialogDescription>\n </DialogHeader>\n {!canCreate ? (\n <EmptyState\n icon={<Scale className=\"size-6\" aria-hidden=\"true\" />}\n title=\"Create a portfolio first\"\n description=\"A rebalance proposal targets a portfolio. Add a portfolio on the Portfolios page, then return here to propose a rebalance.\"\n />\n ) : (\n <div className=\"grid gap-4\">\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"prop-portfolio\">\n Portfolio <span className=\"text-status-error-text\">*</span>\n </Label>\n <Select\n value={form.portfolioId}\n onValueChange={(v) => setForm((f) => ({ ...f, portfolioId: v }))}\n >\n <SelectTrigger id=\"prop-portfolio\">\n <SelectValue placeholder=\"Select a portfolio\" />\n </SelectTrigger>\n <SelectContent>\n {portfolios.map((p) => (\n <SelectItem key={p.id} value={p.id}>\n {p.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"prop-drift\">Drift %</Label>\n <Input\n id=\"prop-drift\"\n type=\"number\"\n value={form.driftPct}\n onChange={(e) => setForm((f) => ({ ...f, driftPct: e.target.value }))}\n placeholder=\"e.g. 6.5\"\n />\n </div>\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"prop-rationale\">Rationale</Label>\n <Textarea\n id=\"prop-rationale\"\n value={form.rationale}\n onChange={(e) => setForm((f) => ({ ...f, rationale: e.target.value }))}\n placeholder=\"Why is this rebalance needed?\"\n />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"prop-trades\">Trades (JSON, optional)</Label>\n <Textarea\n id=\"prop-trades\"\n className=\"font-mono text-xs\"\n value={form.trades}\n onChange={(e) => {\n setTradesError(null);\n setForm((f) => ({ ...f, trades: e.target.value }));\n }}\n placeholder='e.g. [{\"symbol\":\"VOO\",\"action\":\"SELL\",\"quantity\":10}]'\n />\n {tradesError ? (\n <p className=\"text-xs text-status-error-text\">{tradesError}</p>\n ) : null}\n </div>\n </div>\n )}\n <DialogFooter>\n <DialogClose asChild>\n <Button variant=\"outline\">Cancel</Button>\n </DialogClose>\n <Button onClick={submitCreate} disabled={!form.portfolioId || createProposal.isPending}>\n {createProposal.isPending ? 'Creating…' : 'Create proposal'}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n\n {/* Proposal detail — lifecycle, proposed trades, risk insights + discussion */}\n {(() => {\n // Re-read from the live list so the stepper/status reflect transitions.\n const live = detailProposal\n ? (proposals.find((p) => p.id === detailProposal.id) ?? detailProposal)\n : null;\n const related = live ? insights.filter((i) => i.subjectId === live.portfolioId) : [];\n return (\n <ProposalDetailDialog\n proposal={live}\n portfolio={live ? (portfolioById.get(live.portfolioId) ?? null) : null}\n relatedInsights={related}\n nextStatuses={live ? NEXT_STATUSES[live.status] : []}\n transitionPending={transitionProposal.isPending}\n onTransition={(status) => {\n if (live) requestTransition(live, status);\n }}\n onOpenChange={(open) => {\n if (!open) setDetailProposal(null);\n }}\n />\n );\n })()}\n\n {/* Confirm destructive lifecycle transition (reject / cancel) */}\n <ConfirmDialog\n open={confirmTransition !== null}\n onOpenChange={(open) => {\n if (!open) setConfirmTransition(null);\n }}\n title={\n confirmTransition?.status === 'REJECTED'\n ? 'Reject this proposal?'\n : 'Cancel this proposal?'\n }\n description={\n confirmTransition\n ? `This moves the rebalance proposal for ${\n portfolioById.get(confirmTransition.proposal.portfolioId)?.name ?? 'this portfolio'\n } to ${humanize(confirmTransition.status)}. This cannot be undone.`\n : undefined\n }\n confirmLabel={confirmTransition?.status === 'REJECTED' ? 'Reject' : 'Cancel proposal'}\n cancelLabel=\"Keep\"\n destructive\n pending={transitionProposal.isPending}\n onConfirm={() => {\n if (!confirmTransition) return;\n transitionProposal.mutate(\n { id: confirmTransition.proposal.id, status: confirmTransition.status },\n { onSuccess: () => setConfirmTransition(null) }\n );\n }}\n />\n </SectionShell>\n );\n}\n\n// ============================================================================\n// Proposal detail dialog — rationale summary, actors, and discussion thread\n// ============================================================================\n\nfunction ProposalDetailDialog({\n proposal,\n portfolio,\n relatedInsights,\n nextStatuses,\n transitionPending,\n onTransition,\n onOpenChange,\n}: {\n proposal: BraRebalanceProposal | null;\n portfolio: BraPortfolio | null;\n relatedInsights: BraInsight[];\n nextStatuses: BraRebalanceStatus[];\n transitionPending: boolean;\n onTransition: (status: BraRebalanceStatus) => void;\n onOpenChange: (open: boolean) => void;\n}) {\n const trades = proposal ? parseTrades(proposal.trades) : null;\n const breached =\n proposal != null &&\n portfolio?.driftThresholdPct != null &&\n Number.isFinite(portfolio.driftThresholdPct) &&\n proposal.driftPct >= portfolio.driftThresholdPct;\n\n return (\n <Dialog open={proposal !== null} onOpenChange={onOpenChange}>\n <DialogContent className=\"max-h-[88vh] max-w-3xl overflow-y-auto\">\n {proposal ? (\n <>\n <DialogHeader>\n <p className=\"text-xs font-medium uppercase tracking-wide text-text-secondary\">\n Detail\n </p>\n <DialogTitle className=\"flex flex-wrap items-center gap-2 text-xl\">\n {portfolio?.name ?? 'Rebalance proposal'}\n <span className=\"text-text-secondary\">— Rebalance proposal</span>\n <Badge variant={statusBadgeVariant(proposal.status)}>\n {humanize(proposal.status)}\n </Badge>\n </DialogTitle>\n <DialogDescription>\n Created {formatDate(proposal.createdAt)}\n {proposal.executedAt ? ` · executed ${formatDate(proposal.executedAt)}` : ''}\n </DialogDescription>\n </DialogHeader>\n\n {/* Lifecycle stepper — DRAFT → PROPOSED → APPROVED → EXECUTED (+ side states). */}\n <div className=\"rounded-xl border border-border-subtle bg-bg-surface p-4\">\n <LifecycleStepper steps={LIFECYCLE_STEPS} current={humanize(proposal.status)} />\n </div>\n\n {/* Key facts as premium tiles */}\n <div className=\"grid gap-3 sm:grid-cols-2 lg:grid-cols-4\">\n <StatTile\n label=\"Drift\"\n value={formatPct(proposal.driftPct)}\n deltaTone={breached ? 'negative' : 'neutral'}\n glow={breached}\n icon={<Gauge className=\"size-4\" aria-hidden=\"true\" />}\n />\n <StatTile\n label=\"Threshold\"\n value={\n portfolio?.driftThresholdPct != null\n ? formatPct(portfolio.driftThresholdPct)\n : '—'\n }\n />\n <div className=\"rounded-xl border border-border-subtle bg-bg-surface p-4\">\n <p className=\"text-xs text-text-secondary\">Proposed by</p>\n <p className=\"mt-1 truncate text-sm font-medium text-text-primary\">\n {proposal.proposedById ? <ActorName id={proposal.proposedById} /> : '—'}\n </p>\n </div>\n <div className=\"rounded-xl border border-border-subtle bg-bg-surface p-4\">\n <p className=\"text-xs text-text-secondary\">Approved by</p>\n <p className=\"mt-1 truncate text-sm font-medium text-text-primary\">\n {proposal.approvedById ? <ActorName id={proposal.approvedById} /> : '—'}\n </p>\n </div>\n </div>\n\n {/* Proposed trades */}\n <div className=\"space-y-2\">\n <h3 className=\"text-sm font-semibold text-text-primary\">Proposed trades</h3>\n {trades && trades.length > 0 ? (\n <div className=\"overflow-x-auto rounded-lg border border-border-subtle\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>Action</TableHead>\n <TableHead>Symbol</TableHead>\n <TableHead className=\"text-right\">Quantity</TableHead>\n <TableHead className=\"text-right\">Est. value</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {trades.map((t, i) => (\n <TableRow key={i}>\n <TableCell className={`font-semibold ${tradeActionTone(t.action)}`}>\n {t.action ? t.action.toUpperCase() : '—'}\n </TableCell>\n <TableCell className=\"font-medium text-text-primary\">\n {t.symbol ?? '—'}\n </TableCell>\n <TableCell className=\"text-right tabular-nums text-text-secondary\">\n {t.quantity != null ? t.quantity.toLocaleString() : '—'}\n </TableCell>\n <TableCell className=\"text-right tabular-nums text-text-secondary\">\n {t.value != null\n ? formatMoney(t.value, portfolio?.baseCurrency ?? 'USD')\n : '—'}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n ) : (\n <p className=\"text-sm text-text-secondary\">\n {summarizeTrades(proposal.trades)} — no structured trade breakdown available.\n </p>\n )}\n </div>\n\n {/* Rationale */}\n <div className=\"space-y-1\">\n <h3 className=\"text-sm font-semibold text-text-primary\">Rationale</h3>\n <p className=\"text-sm text-text-secondary\">{proposal.rationale ?? '—'}</p>\n </div>\n\n {/* Lifecycle actions (mirrors the row menu; destructive actions confirm) */}\n {nextStatuses.length > 0 ? (\n <div className=\"flex flex-wrap gap-2\">\n {nextStatuses.map((status) => {\n const destructive = status === 'REJECTED' || status === 'CANCELLED';\n return (\n <Button\n key={status}\n variant={destructive ? 'outline' : 'default'}\n size=\"sm\"\n disabled={transitionPending}\n className={destructive ? 'text-status-error-text' : undefined}\n onClick={() => onTransition(status)}\n >\n {destructive ? (\n <X className=\"size-4\" aria-hidden=\"true\" />\n ) : (\n <ArrowRight className=\"size-4\" aria-hidden=\"true\" />\n )}\n {humanize(status)}\n </Button>\n );\n })}\n </div>\n ) : null}\n\n {/* Risk insights tied to this portfolio (real, filtered by subjectId) */}\n {relatedInsights.length > 0 ? (\n <div className=\"space-y-2 border-t border-border-subtle pt-4\">\n <h3 className=\"flex items-center gap-2 text-sm font-semibold text-text-primary\">\n <ShieldAlert className=\"size-4\" aria-hidden=\"true\" />\n Risk insights\n </h3>\n <ul className=\"space-y-2\">\n {relatedInsights.map((insight) => (\n <li\n key={insight.id}\n className=\"rounded-lg border border-border-subtle bg-bg-surface p-3\"\n >\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"text-sm font-medium text-text-primary\">\n {insight.title}\n </span>\n <Badge variant={statusBadgeVariant(insight.severity)}>\n {humanize(insight.severity)}\n </Badge>\n <Badge variant=\"outline\">{humanize(insight.type)}</Badge>\n <Badge variant={statusBadgeVariant(insight.status)}>\n {humanize(insight.status)}\n </Badge>\n </div>\n {insight.detail ? (\n <p className=\"mt-1 text-xs text-text-secondary\">{insight.detail}</p>\n ) : null}\n </li>\n ))}\n </ul>\n </div>\n ) : null}\n\n <div className=\"border-t border-border-subtle pt-4\">\n <CommentThread\n entityType=\"brainyrich-rebalance\"\n entityId={proposal.id}\n heading=\"Discussion\"\n />\n </div>\n </>\n ) : null}\n </DialogContent>\n </Dialog>\n );\n}\n\n// ============================================================================\n// Risk signal row (BOFF-4236) — real inputs/formula always shown, never hidden\n// ============================================================================\n\nfunction RiskSignalRow({ signal }: { signal: BraRiskSignal }) {\n const metricEntries = Object.entries((signal.metrics as Record<string, unknown>) ?? {});\n return (\n <li className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <p className=\"font-medium text-text-primary\">{signal.title}</p>\n <Badge variant={statusBadgeVariant(signal.severity)}>{humanize(signal.severity)}</Badge>\n <Badge variant=\"outline\">{humanize(signal.kind)}</Badge>\n </div>\n {signal.detail ? <p className=\"mt-1 text-sm text-text-secondary\">{signal.detail}</p> : null}\n {metricEntries.length > 0 ? (\n <dl className=\"mt-3 grid grid-cols-2 gap-x-4 gap-y-1 sm:grid-cols-3 lg:grid-cols-4\">\n {metricEntries.map(([key, value]) => (\n <div key={key} className=\"min-w-0\">\n <dt className=\"truncate text-[11px] uppercase tracking-wide text-text-muted\">\n {humanize(key)}\n </dt>\n <dd className=\"truncate text-sm font-medium tabular-nums text-text-primary\">\n {formatMetricValue(value)}\n </dd>\n </div>\n ))}\n </dl>\n ) : null}\n </li>\n );\n}\n\n// ============================================================================\n// Tax-loss opportunity row (BOFF-4237) — real numbers + wash-sale caution\n// ============================================================================\n\nfunction TaxLossOpportunityRow({ opportunity }: { opportunity: BraTaxLossOpportunity }) {\n const metricEntries = Object.entries((opportunity.metrics as Record<string, unknown>) ?? {});\n return (\n <li className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <p className=\"font-medium text-text-primary\">\n {opportunity.symbol} — unrealized loss {formatMoney(opportunity.unrealizedLoss)}\n </p>\n <Badge variant={statusBadgeVariant(opportunity.severity)}>{humanize(opportunity.severity)}</Badge>\n {opportunity.washSaleRisk ? (\n <Badge variant=\"outline\" className=\"text-status-error-text\">\n <AlertTriangle className=\"mr-1 size-3\" aria-hidden=\"true\" />\n Wash-sale caution\n </Badge>\n ) : null}\n </div>\n <p className=\"mt-1 text-sm text-text-secondary\">\n Market value {formatMoney(opportunity.marketValue)} vs. cost basis {formatMoney(opportunity.costBasis)}\n {' · '}\n {formatPct(opportunity.lossPctOfPortfolio)} of portfolio value\n </p>\n {opportunity.washSaleReason ? (\n <p className=\"mt-1 text-xs text-status-error-text\">{opportunity.washSaleReason}</p>\n ) : null}\n {metricEntries.length > 0 ? (\n <dl className=\"mt-3 grid grid-cols-2 gap-x-4 gap-y-1 sm:grid-cols-3 lg:grid-cols-4\">\n {metricEntries\n .filter(([key]) => key !== 'formula')\n .map(([key, value]) => (\n <div key={key} className=\"min-w-0\">\n <dt className=\"truncate text-[11px] uppercase tracking-wide text-text-muted\">\n {humanize(key)}\n </dt>\n <dd className=\"truncate text-sm font-medium tabular-nums text-text-primary\">\n {formatMetricValue(value)}\n </dd>\n </div>\n ))}\n </dl>\n ) : null}\n </li>\n );\n}\n\n// ============================================================================\n// Insight row\n// ============================================================================\n\nfunction InsightRow({\n insight,\n onAcknowledge,\n onResolve,\n onDismiss,\n actionPending,\n}: {\n insight: BraInsight;\n onAcknowledge: () => void;\n onResolve: () => void;\n onDismiss: () => void;\n actionPending: boolean;\n}) {\n const terminal = insight.status === 'RESOLVED' || insight.status === 'DISMISSED';\n return (\n <div className=\"flex items-start justify-between gap-4 rounded-lg border border-border-subtle bg-bg-surface p-4 transition-shadow motion-safe:hover:shadow-[var(--shadow-pop-hover,var(--shadow-elevation-2))]\">\n <div className=\"min-w-0 space-y-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <p className=\"font-medium text-text-primary\">{insight.title}</p>\n <Badge variant={statusBadgeVariant(insight.severity)}>{humanize(insight.severity)}</Badge>\n <Badge variant=\"outline\">{humanize(insight.type)}</Badge>\n <Badge variant={statusBadgeVariant(insight.status)}>{humanize(insight.status)}</Badge>\n </div>\n {insight.detail ? <p className=\"text-sm text-text-secondary\">{insight.detail}</p> : null}\n <p className=\"text-xs text-text-muted\">Detected {formatDate(insight.createdAt)}</p>\n </div>\n {terminal ? (\n <span className=\"mt-1 text-xs text-text-muted\">Closed</span>\n ) : (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label={`Actions for ${insight.title}`}\n disabled={actionPending}\n >\n <MoreHorizontal className=\"size-4\" aria-hidden=\"true\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {insight.status === 'OPEN' ? (\n <DropdownMenuItem onClick={onAcknowledge}>\n <Check className=\"size-4\" aria-hidden=\"true\" />\n Acknowledge\n </DropdownMenuItem>\n ) : null}\n <DropdownMenuItem onClick={onResolve}>\n <ShieldCheck className=\"size-4\" aria-hidden=\"true\" />\n Resolve\n </DropdownMenuItem>\n <DropdownMenuItem className=\"text-status-error-text\" onClick={onDismiss}>\n <X className=\"size-4\" aria-hidden=\"true\" />\n Dismiss\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"RiskPage.js","names":[],"sources":["../../../src/brainyrich/pages/RiskPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n Textarea,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Activity,\n AlertTriangle,\n ArrowRight,\n Check,\n Eye,\n Gauge,\n Layers,\n MoreHorizontal,\n Plus,\n RefreshCw,\n Scale,\n Scissors,\n ShieldAlert,\n ShieldCheck,\n Sparkles,\n TrendingUp,\n X,\n} from 'lucide-react';\nimport {\n useRebalanceProposals,\n usePortfolios,\n usePagedInsights,\n useCreateRebalanceProposal,\n useTransitionRebalanceProposal,\n useAcknowledgeInsight,\n useDismissInsight,\n useResolveInsight,\n usePortfolioRiskSignals,\n useGenerateRiskInsights,\n usePortfolioRiskSummary,\n useTaxLossOpportunities,\n useHarvestTaxLossInsights,\n} from '../hooks/useBrainyRichApi';\nimport type {\n BraPortfolio,\n BraRebalanceProposal,\n BraRebalanceStatus,\n BraInsight,\n BraInsightSeverity,\n BraInsightType,\n BraRiskSignal,\n BraTaxLossOpportunity,\n} from '../types/bra';\nimport {\n SectionShell,\n EmptyState,\n LoadingState,\n ErrorState,\n formatMoney,\n formatPct,\n formatDate,\n statusBadgeVariant,\n} from './_shared';\nimport {\n ConfirmDialog,\n ActorName,\n LoadMore,\n StatTile,\n GlassCard,\n FadeIn,\n DonutChart,\n LifecycleStepper,\n type VizTone,\n type DonutDatum,\n} from '../components';\nimport { CommentThread } from '../components/reuse/CommentThread';\n\n// ============================================================================\n// Domain rules (derived from the SDL enum, not fabricated data)\n// ============================================================================\n\n/** Valid forward/side transitions per current rebalance status. Terminal states map to []. */\nconst NEXT_STATUSES: Record<BraRebalanceStatus, BraRebalanceStatus[]> = {\n DRAFT: ['PROPOSED', 'CANCELLED'],\n PROPOSED: ['APPROVED', 'REJECTED', 'CANCELLED'],\n APPROVED: ['EXECUTED', 'CANCELLED'],\n REJECTED: [],\n EXECUTED: [],\n CANCELLED: [],\n};\n\n/** Insight types that belong on the risk/rebalancing surface. */\nconst RISK_INSIGHT_TYPES: BraInsightType[] = [\n 'DRIFT',\n 'CONCENTRATION_RISK',\n 'REBALANCE_DUE',\n 'CASH_DRAG',\n 'FEE_ANOMALY',\n];\nconst RISK_INSIGHT_TYPE_SET = new Set<BraInsightType>(RISK_INSIGHT_TYPES);\n\nfunction humanize(value: string): string {\n return value\n .toLowerCase()\n .split('_')\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1))\n .join(' ');\n}\n\n/** Lifecycle chart stages (forward path). Side states handled by the stepper. */\nconst LIFECYCLE_STEPS = ['Draft', 'Proposed', 'Approved', 'Executed'];\n\n/** Categorical donut tone per proposal status (distinct emerald-brand-first hues). */\nconst STATUS_TONE: Record<BraRebalanceStatus, VizTone> = {\n DRAFT: 'neutral',\n PROPOSED: 'warning',\n APPROVED: 'blue',\n EXECUTED: 'success',\n REJECTED: 'error',\n CANCELLED: 'neutral',\n};\n\nconst STATUS_ORDER: BraRebalanceStatus[] = [\n 'PROPOSED',\n 'DRAFT',\n 'APPROVED',\n 'EXECUTED',\n 'REJECTED',\n 'CANCELLED',\n];\n\n/** Donut tone per insight severity. */\nconst SEVERITY_TONE: Record<BraInsightSeverity, VizTone> = {\n CRITICAL: 'error',\n HIGH: 'warning',\n MEDIUM: 'info',\n LOW: 'teal',\n INFO: 'neutral',\n};\n\nconst SEVERITY_ORDER: BraInsightSeverity[] = ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW', 'INFO'];\n\n/** A best-effort structured trade row parsed from the opaque `trades` JSON. */\ninterface TradeRow {\n action?: string;\n symbol?: string;\n quantity?: number;\n value?: number;\n}\n\n/**\n * Parse the opaque `trades` scalar into structured rows WITHOUT inventing data:\n * only keys actually present on each object are surfaced. Returns null when the\n * value is not an array of plain objects (callers fall back to a text summary).\n */\nfunction parseTrades(trades: unknown): TradeRow[] | null {\n if (!Array.isArray(trades) || trades.length === 0) return null;\n const rows: TradeRow[] = [];\n for (const item of trades) {\n if (!item || typeof item !== 'object' || Array.isArray(item)) return null;\n const t = item as Record<string, unknown>;\n const get = (keys: string[]): unknown => {\n for (const k of Object.keys(t)) {\n if (keys.includes(k.toLowerCase())) return t[k];\n }\n return undefined;\n };\n const action = get(['action', 'side', 'type']);\n const symbol = get(['symbol', 'ticker', 'asset', 'instrument']);\n const quantity = get(['quantity', 'qty', 'shares', 'units']);\n const value = get(['value', 'notional', 'amount', 'total', 'marketvalue']);\n rows.push({\n action: typeof action === 'string' ? action : undefined,\n symbol: typeof symbol === 'string' ? symbol : undefined,\n quantity: typeof quantity === 'number' ? quantity : undefined,\n value: typeof value === 'number' ? value : undefined,\n });\n }\n return rows;\n}\n\n/**\n * Render one entry of a `BraRiskSignal.metrics` object without inventing\n * formatting rules per-key: numbers render as plain locale numbers (2dp when\n * fractional), booleans as Yes/No, everything else as-is. This is the ONLY\n * place the deterministic engine's real inputs/formula reach the screen —\n * never replaced by a derived/opaque display value.\n */\nfunction formatMetricValue(value: unknown): string {\n if (value === null || value === undefined) return '—';\n if (typeof value === 'number') {\n return Number.isInteger(value)\n ? value.toLocaleString()\n : value.toLocaleString(undefined, { maximumFractionDigits: 2 });\n }\n if (typeof value === 'boolean') return value ? 'Yes' : 'No';\n if (typeof value === 'string') return value;\n return JSON.stringify(value);\n}\n\n/** Semantic tone for a trade action (color is never the only signal). */\nfunction tradeActionTone(action: string | undefined): string {\n const a = (action ?? '').toUpperCase();\n if (a.includes('BUY') || a.includes('ADD')) return 'text-status-success-text';\n if (a.includes('SELL') || a.includes('TRIM') || a.includes('REDUCE'))\n return 'text-status-error-text';\n return 'text-text-secondary';\n}\n\n/** Summarize the opaque `trades` JSON scalar without inventing data. */\nfunction summarizeTrades(trades: unknown): string {\n if (trades == null) return '—';\n if (Array.isArray(trades)) {\n return `${trades.length} trade${trades.length === 1 ? '' : 's'}`;\n }\n if (typeof trades === 'object') {\n const n = Object.keys(trades as Record<string, unknown>).length;\n return `${n} field${n === 1 ? '' : 's'}`;\n }\n return String(trades);\n}\n\n// ============================================================================\n// Create-proposal form\n// ============================================================================\n\ninterface ProposalFormState {\n portfolioId: string;\n driftPct: string;\n rationale: string;\n trades: string;\n}\n\nconst EMPTY_PROPOSAL_FORM: ProposalFormState = {\n portfolioId: '',\n driftPct: '',\n rationale: '',\n trades: '',\n};\n\nfunction parseNum(value: string): number | undefined {\n if (value.trim() === '') return undefined;\n const n = Number(value);\n return Number.isFinite(n) ? n : undefined;\n}\n\nexport function RiskPage() {\n const {\n data: proposals,\n isLoading: proposalsLoading,\n isError: proposalsError,\n refetch: refetchProposals,\n } = useRebalanceProposals();\n\n const { data: portfolios } = usePortfolios();\n\n // ---- BOFF-4236: deterministic risk-signal engine + optional AI summary ----\n // Defaults to the first portfolio until the user explicitly picks one — a\n // derived value (not synced via effect) so there's no cascading-render setState.\n const [manualRiskPortfolioId, setManualRiskPortfolioId] = useState<string | undefined>(undefined);\n const riskPortfolioId = manualRiskPortfolioId ?? portfolios[0]?.id ?? '';\n\n const {\n data: riskReport,\n isLoading: riskLoading,\n isError: riskError,\n refetch: refetchRisk,\n } = usePortfolioRiskSignals(riskPortfolioId || undefined);\n const generateRiskInsights = useGenerateRiskInsights();\n const {\n data: riskSummary,\n isFetching: riskSummaryFetching,\n refetch: refetchRiskSummary,\n } = usePortfolioRiskSummary(riskPortfolioId || undefined);\n\n // ---- BOFF-4237: configurable tax-loss-harvesting detector + wash-sale caution ----\n const {\n data: taxLossReport,\n isLoading: taxLossLoading,\n isError: taxLossError,\n refetch: refetchTaxLoss,\n } = useTaxLossOpportunities(riskPortfolioId || undefined);\n const harvestTaxLossInsights = useHarvestTaxLossInsights();\n\n const {\n items: insights,\n hasMore: insightsHasMore,\n loadMore: loadMoreInsights,\n isLoading: insightsLoading,\n isFetchingNextPage: insightsFetchingMore,\n isError: insightsError,\n refetch: refetchInsights,\n } = usePagedInsights();\n\n const createProposal = useCreateRebalanceProposal();\n const transitionProposal = useTransitionRebalanceProposal();\n const acknowledgeInsight = useAcknowledgeInsight();\n const dismissInsight = useDismissInsight();\n const resolveInsight = useResolveInsight();\n\n const [createOpen, setCreateOpen] = useState(false);\n const [form, setForm] = useState<ProposalFormState>(EMPTY_PROPOSAL_FORM);\n const [tradesError, setTradesError] = useState<string | null>(null);\n const [detailProposal, setDetailProposal] = useState<BraRebalanceProposal | null>(null);\n const [confirmTransition, setConfirmTransition] = useState<{\n proposal: BraRebalanceProposal;\n status: BraRebalanceStatus;\n } | null>(null);\n\n // Portfolio lookup for names + drift thresholds (real backend data).\n const portfolioById = useMemo(() => {\n const map = new Map<string, BraPortfolio>();\n for (const p of portfolios) map.set(p.id, p);\n return map;\n }, [portfolios]);\n\n const riskInsights = useMemo(\n () => insights.filter((i) => RISK_INSIGHT_TYPE_SET.has(i.type)),\n [insights]\n );\n\n const activeProposals = proposals.filter(\n (p) => p.status === 'DRAFT' || p.status === 'PROPOSED' || p.status === 'APPROVED'\n );\n const openInsights = riskInsights.filter((i) => i.status === 'OPEN');\n const avgDrift =\n proposals.length > 0\n ? proposals.reduce((sum, p) => sum + (p.driftPct ?? 0), 0) / proposals.length\n : null;\n\n // Breach count drives the drift tile's tone (real: drift ≥ portfolio threshold).\n const breachedCount = useMemo(\n () =>\n proposals.filter((p) => {\n const threshold = portfolioById.get(p.portfolioId)?.driftThresholdPct;\n return threshold != null && Number.isFinite(threshold) && p.driftPct >= threshold;\n }).length,\n [proposals, portfolioById]\n );\n\n // Real drift series (chronological) — decorative sparkline on the drift KPI.\n const driftSeries = useMemo(\n () =>\n [...proposals]\n .sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime())\n .map((p) => p.driftPct)\n .filter((n) => Number.isFinite(n)),\n [proposals]\n );\n\n // Proposal pipeline distribution (real counts by lifecycle status).\n const statusDonut = useMemo<DonutDatum[]>(() => {\n const counts = new Map<BraRebalanceStatus, number>();\n for (const p of proposals) counts.set(p.status, (counts.get(p.status) ?? 0) + 1);\n return STATUS_ORDER.filter((s) => (counts.get(s) ?? 0) > 0).map((s) => ({\n label: humanize(s),\n value: counts.get(s) ?? 0,\n tone: STATUS_TONE[s],\n }));\n }, [proposals]);\n\n // Open risk-signal distribution (real counts by severity).\n const severityDonut = useMemo<DonutDatum[]>(() => {\n const counts = new Map<BraInsightSeverity, number>();\n for (const i of openInsights) counts.set(i.severity, (counts.get(i.severity) ?? 0) + 1);\n return SEVERITY_ORDER.filter((s) => (counts.get(s) ?? 0) > 0).map((s) => ({\n label: humanize(s),\n value: counts.get(s) ?? 0,\n tone: SEVERITY_TONE[s],\n }));\n }, [openInsights]);\n\n const canCreate = portfolios.length > 0;\n\n function openCreate() {\n setForm(EMPTY_PROPOSAL_FORM);\n setTradesError(null);\n setCreateOpen(true);\n }\n\n function submitCreate() {\n if (!form.portfolioId) return;\n let trades: unknown;\n if (form.trades.trim() !== '') {\n try {\n trades = JSON.parse(form.trades);\n } catch {\n setTradesError('Trades must be valid JSON.');\n return;\n }\n }\n const portfolio = portfolioById.get(form.portfolioId);\n createProposal.mutate(\n {\n portfolioId: form.portfolioId,\n householdId: portfolio?.householdId ?? null,\n driftPct: parseNum(form.driftPct),\n rationale: form.rationale.trim() || null,\n ...(trades !== undefined ? { trades } : {}),\n },\n { onSuccess: () => setCreateOpen(false) }\n );\n }\n\n /** Destructive transitions (reject/cancel) confirm first; forward transitions fire directly. */\n function requestTransition(proposal: BraRebalanceProposal, status: BraRebalanceStatus) {\n if (status === 'REJECTED' || status === 'CANCELLED') {\n setConfirmTransition({ proposal, status });\n return;\n }\n transitionProposal.mutate({ id: proposal.id, status });\n }\n\n /** Drift is a breach when it meets/exceeds the portfolio's configured threshold. */\n function driftBreached(p: BraRebalanceProposal): boolean {\n const threshold = portfolioById.get(p.portfolioId)?.driftThresholdPct;\n return threshold != null && Number.isFinite(threshold) && p.driftPct >= threshold;\n }\n\n return (\n <SectionShell\n title=\"Risk & Rebalancing\"\n description=\"Review drift-driven rebalance proposals and act on portfolio risk insights.\"\n badges={[\n `${activeProposals.length} active`,\n `${openInsights.length} open insight${openInsights.length === 1 ? '' : 's'}`,\n ]}\n actionLabel=\"New proposal\"\n onAction={openCreate}\n >\n {/* Premium KPI row */}\n <div className=\"grid gap-4 sm:grid-cols-2 xl:grid-cols-4\">\n <FadeIn index={0}>\n <StatTile\n label=\"Average drift\"\n value={avgDrift === null ? '—' : formatPct(avgDrift)}\n spark={driftSeries.length > 1 ? driftSeries : undefined}\n sparkTone={breachedCount > 0 ? 'error' : 'brand'}\n glow\n icon={<Gauge className=\"size-4\" aria-hidden=\"true\" />}\n />\n </FadeIn>\n <FadeIn index={1}>\n <StatTile\n label=\"Active proposals\"\n value={String(activeProposals.length)}\n icon={<Activity className=\"size-4\" aria-hidden=\"true\" />}\n />\n </FadeIn>\n <FadeIn index={2}>\n <StatTile\n label=\"Total proposals\"\n value={String(proposals.length)}\n icon={<Layers className=\"size-4\" aria-hidden=\"true\" />}\n />\n </FadeIn>\n <FadeIn index={3}>\n <StatTile\n label=\"Open risk insights\"\n value={String(openInsights.length)}\n deltaTone={openInsights.length > 0 ? 'negative' : 'neutral'}\n icon={<ShieldAlert className=\"size-4\" aria-hidden=\"true\" />}\n />\n </FadeIn>\n </div>\n\n {/* Hero band — pipeline + risk-signal distribution donuts */}\n {(statusDonut.length > 0 || severityDonut.length > 0) && !proposalsLoading ? (\n <div className=\"grid gap-4 lg:grid-cols-2\">\n <FadeIn index={0}>\n <GlassCard glow className=\"h-full\">\n <div className=\"mb-3 flex items-center gap-2\">\n <TrendingUp className=\"size-4 text-text-secondary\" aria-hidden=\"true\" />\n <h2 className=\"text-sm font-semibold text-text-primary\">Proposal pipeline</h2>\n </div>\n <DonutChart\n data={statusDonut}\n centerValue={String(proposals.length)}\n centerLabel=\"proposals\"\n height={200}\n />\n </GlassCard>\n </FadeIn>\n <FadeIn index={1}>\n <GlassCard className=\"h-full\">\n <div className=\"mb-3 flex items-center gap-2\">\n <ShieldAlert className=\"size-4 text-text-secondary\" aria-hidden=\"true\" />\n <h2 className=\"text-sm font-semibold text-text-primary\">Open risk signals</h2>\n </div>\n {severityDonut.length > 0 ? (\n <DonutChart\n data={severityDonut}\n centerValue={String(openInsights.length)}\n centerLabel=\"open\"\n height={200}\n />\n ) : (\n <div className=\"flex h-[200px] flex-col items-center justify-center gap-2 text-center\">\n <ShieldCheck className=\"size-8 text-status-success-text\" aria-hidden=\"true\" />\n <p className=\"text-sm text-text-secondary\">No open risk signals.</p>\n </div>\n )}\n </GlassCard>\n </FadeIn>\n </div>\n ) : null}\n\n {/* Portfolio risk signals (BOFF-4236) — deterministic engine + optional AI summary */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Gauge className=\"h-5 w-5\" aria-hidden=\"true\" />\n Portfolio risk signals\n </CardTitle>\n <CardDescription>\n Real, explainable signals computed live from this portfolio&apos;s own holdings and\n target allocation — every signal below shows the real inputs and formula/threshold\n behind it. Informational only, never a buy/sell recommendation.\n </CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"min-w-[220px] space-y-1.5\">\n <Label htmlFor=\"risk-portfolio\">Portfolio</Label>\n <Select value={riskPortfolioId} onValueChange={setManualRiskPortfolioId}>\n <SelectTrigger id=\"risk-portfolio\">\n <SelectValue placeholder=\"Select a portfolio\" />\n </SelectTrigger>\n <SelectContent>\n {portfolios.map((p) => (\n <SelectItem key={p.id} value={p.id}>\n {p.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"mt-auto\"\n disabled={!riskPortfolioId || riskLoading}\n onClick={() => refetchRisk()}\n >\n <RefreshCw className=\"size-4\" aria-hidden=\"true\" />\n Recompute\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"mt-auto\"\n disabled={\n !riskPortfolioId ||\n (riskReport?.signals.length ?? 0) === 0 ||\n generateRiskInsights.isPending\n }\n onClick={() => generateRiskInsights.mutate(riskPortfolioId)}\n >\n <ShieldAlert className=\"size-4\" aria-hidden=\"true\" />\n {generateRiskInsights.isPending ? 'Saving…' : 'Save as insights'}\n </Button>\n </div>\n\n {portfolios.length === 0 ? (\n <EmptyState\n icon={<Gauge className=\"size-6\" aria-hidden=\"true\" />}\n title=\"No portfolios yet\"\n description=\"Create a portfolio to compute real risk signals from its holdings.\"\n />\n ) : riskLoading ? (\n <LoadingState />\n ) : riskError ? (\n <ErrorState onRetry={() => refetchRisk()} />\n ) : riskReport ? (\n <div className=\"space-y-4\">\n <div className=\"grid gap-3 sm:grid-cols-3\">\n <StatTile\n label=\"Portfolio value\"\n value={formatMoney(riskReport.totalValue)}\n icon={<Layers className=\"size-4\" aria-hidden=\"true\" />}\n />\n <StatTile\n label=\"Holdings considered\"\n value={String(riskReport.holdingsConsidered)}\n icon={<Activity className=\"size-4\" aria-hidden=\"true\" />}\n />\n <StatTile\n label=\"Signals breached\"\n value={String(riskReport.signals.length)}\n deltaTone={riskReport.signals.length > 0 ? 'negative' : 'neutral'}\n icon={<ShieldAlert className=\"size-4\" aria-hidden=\"true\" />}\n />\n </div>\n\n {riskReport.signals.length === 0 ? (\n <EmptyState\n icon={<ShieldCheck className=\"size-6\" aria-hidden=\"true\" />}\n title=\"No configured threshold was breached\"\n description=\"This portfolio's concentration, cash, drift and unrealized-loss metrics are all within their configured thresholds.\"\n />\n ) : (\n <ul className=\"space-y-3\">\n {riskReport.signals.map((signal, i) => (\n <RiskSignalRow key={`${signal.kind}-${i}`} signal={signal} />\n ))}\n </ul>\n )}\n\n {/* Optional AI-generated plain-language summary of the signals above */}\n <div className=\"rounded-xl border border-border-subtle bg-bg-surface p-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <div className=\"flex items-center gap-2\">\n <Sparkles className=\"size-4 text-text-secondary\" aria-hidden=\"true\" />\n <h3 className=\"text-sm font-semibold text-text-primary\">AI summary</h3>\n <span className=\"text-xs text-text-muted\">\n (optional — plain-language restatement of the signals above; never a source of\n numbers)\n </span>\n </div>\n <Button\n variant=\"outline\"\n size=\"sm\"\n disabled={!riskPortfolioId || riskSummaryFetching}\n onClick={() => refetchRiskSummary()}\n >\n <Sparkles className=\"size-4\" aria-hidden=\"true\" />\n {riskSummaryFetching ? 'Generating…' : 'Generate AI summary'}\n </Button>\n </div>\n {riskSummaryFetching ? (\n <p className=\"mt-2 text-sm text-text-secondary\">Asking the AI provider…</p>\n ) : riskSummary?.generated ? (\n <div className=\"mt-2 space-y-1\">\n <p className=\"text-sm text-text-primary\">{riskSummary.summary}</p>\n <p className=\"text-xs text-text-muted\">\n AI-generated commentary\n {riskSummary.provider ? ` · ${riskSummary.provider}` : ''} · based on{' '}\n {riskSummary.signalsConsidered} computed signal\n {riskSummary.signalsConsidered === 1 ? '' : 's'} above\n </p>\n </div>\n ) : riskSummary && !riskSummary.generated ? (\n <p className=\"mt-2 text-sm text-text-secondary\">\n AI summary unavailable — {riskSummary.reason ?? 'no provider configured'}. The\n deterministic signals above are unaffected.\n </p>\n ) : (\n <p className=\"mt-2 text-sm text-text-muted\">\n Not generated yet. The deterministic signals above always work without this.\n </p>\n )}\n </div>\n </div>\n ) : (\n <EmptyState\n icon={<Gauge className=\"size-6\" aria-hidden=\"true\" />}\n title=\"Select a portfolio\"\n description=\"Choose a portfolio above to compute its real risk signals.\"\n />\n )}\n </CardContent>\n </Card>\n\n {/* Tax-loss-harvesting opportunities (BOFF-4237) — configurable thresholds + wash-sale caution */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Scissors className=\"h-5 w-5\" aria-hidden=\"true\" />\n Tax-loss-harvesting opportunities\n </CardTitle>\n <CardDescription>\n Real unrealized-loss detection for the selected portfolio, using configurable\n dollar/percent thresholds and a wash-sale caution flag from your recorded transactions.\n Detection only — this never places a trade, and it is not tax advice.\n </CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n disabled={!riskPortfolioId || taxLossLoading}\n onClick={() => refetchTaxLoss()}\n >\n <RefreshCw className=\"size-4\" aria-hidden=\"true\" />\n Recompute\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n disabled={\n !riskPortfolioId ||\n (taxLossReport?.opportunities.length ?? 0) === 0 ||\n harvestTaxLossInsights.isPending\n }\n onClick={() => harvestTaxLossInsights.mutate({ portfolioId: riskPortfolioId })}\n >\n <ShieldAlert className=\"size-4\" aria-hidden=\"true\" />\n {harvestTaxLossInsights.isPending ? 'Saving…' : 'Save as insights'}\n </Button>\n {taxLossReport ? (\n <span className=\"text-xs text-text-muted\">\n Thresholds: ≥{formatMoney(taxLossReport.thresholds.minLossAmount)} or ≥\n {formatPct(taxLossReport.thresholds.minLossPct)} of portfolio value\n </span>\n ) : null}\n </div>\n\n {portfolios.length === 0 ? (\n <EmptyState\n icon={<Scissors className=\"size-6\" aria-hidden=\"true\" />}\n title=\"No portfolios yet\"\n description=\"Create a portfolio to detect real tax-loss-harvesting opportunities from its holdings.\"\n />\n ) : taxLossLoading ? (\n <LoadingState />\n ) : taxLossError ? (\n <ErrorState onRetry={() => refetchTaxLoss()} />\n ) : taxLossReport && taxLossReport.opportunities.length > 0 ? (\n <ul className=\"space-y-3\">\n {taxLossReport.opportunities.map((opp) => (\n <TaxLossOpportunityRow key={opp.symbol} opportunity={opp} />\n ))}\n </ul>\n ) : taxLossReport ? (\n <EmptyState\n icon={<ShieldCheck className=\"size-6\" aria-hidden=\"true\" />}\n title=\"No opportunities at the current thresholds\"\n description=\"No symbol's unrealized loss clears the configured dollar/percent thresholds.\"\n />\n ) : (\n <EmptyState\n icon={<Scissors className=\"size-6\" aria-hidden=\"true\" />}\n title=\"Select a portfolio\"\n description=\"Choose a portfolio above to detect real tax-loss opportunities.\"\n />\n )}\n </CardContent>\n </Card>\n\n {/* Rebalance proposals */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Scale className=\"h-5 w-5\" aria-hidden=\"true\" />\n Rebalance proposals\n </CardTitle>\n <CardDescription>\n Drift against target allocation, with lifecycle actions per proposal.\n </CardDescription>\n </CardHeader>\n <CardContent>\n {proposalsLoading ? (\n <LoadingState />\n ) : proposalsError ? (\n <ErrorState onRetry={() => refetchProposals()} />\n ) : proposals.length === 0 ? (\n <EmptyState\n icon={<Scale className=\"size-6\" aria-hidden=\"true\" />}\n title=\"No rebalance proposals\"\n description={\n canCreate\n ? 'Create a proposal when a portfolio drifts from its target allocation.'\n : 'Create a portfolio first, then propose a rebalance when it drifts.'\n }\n action={\n canCreate ? (\n <Button size=\"sm\" onClick={openCreate}>\n <Plus className=\"size-4\" aria-hidden=\"true\" />\n New proposal\n </Button>\n ) : undefined\n }\n />\n ) : (\n <div className=\"overflow-x-auto\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>Portfolio</TableHead>\n <TableHead className=\"text-right\">Drift</TableHead>\n <TableHead>Status</TableHead>\n <TableHead>Rationale</TableHead>\n <TableHead>Trades</TableHead>\n <TableHead>Created</TableHead>\n <TableHead className=\"w-12 text-right\">Actions</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {proposals.map((p) => {\n const portfolio = portfolioById.get(p.portfolioId);\n const breached = driftBreached(p);\n const nextStatuses = NEXT_STATUSES[p.status];\n const threshold = portfolio?.driftThresholdPct;\n const meterPct =\n threshold != null && threshold > 0\n ? Math.min(100, (p.driftPct / threshold) * 100)\n : null;\n return (\n <TableRow\n key={p.id}\n onClick={() => setDetailProposal(p)}\n className=\"cursor-pointer transition-colors motion-safe:hover:bg-bg-elevated\"\n >\n <TableCell>\n <p className=\"font-medium text-text-primary\">\n {portfolio?.name ?? 'Unknown portfolio'}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {portfolio?.baseCurrency ?? '—'}\n {threshold != null ? ` · threshold ${formatPct(threshold)}` : ''}\n </p>\n </TableCell>\n <TableCell className=\"text-right\">\n <span\n className={`inline-flex items-center justify-end gap-1 font-semibold tabular-nums ${\n breached ? 'text-status-error-text' : 'text-text-primary'\n }`}\n >\n {breached ? (\n <AlertTriangle className=\"size-4\" aria-hidden=\"true\" />\n ) : null}\n {formatPct(p.driftPct)}\n </span>\n {meterPct != null ? (\n <div\n className=\"ml-auto mt-1 h-1.5 w-24 overflow-hidden rounded-full bg-bg-sunken\"\n role=\"progressbar\"\n aria-valuenow={Math.round(meterPct)}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={`Drift vs threshold for ${portfolio?.name ?? 'portfolio'}`}\n >\n <div\n className=\"h-full rounded-full\"\n style={{\n width: `${meterPct}%`,\n background: breached\n ? 'var(--color-status-error)'\n : 'var(--color-action-primary-bg)',\n }}\n />\n </div>\n ) : breached ? (\n <p className=\"text-xs text-status-error-text\">Over threshold</p>\n ) : null}\n </TableCell>\n <TableCell>\n <Badge variant={statusBadgeVariant(p.status)}>{humanize(p.status)}</Badge>\n </TableCell>\n <TableCell className=\"max-w-xs\">\n <p className=\"truncate text-sm text-text-secondary\">\n {p.rationale ?? '—'}\n </p>\n </TableCell>\n <TableCell className=\"text-sm text-text-secondary\">\n {summarizeTrades(p.trades)}\n </TableCell>\n <TableCell className=\"text-sm text-text-secondary\">\n {formatDate(p.createdAt)}\n </TableCell>\n <TableCell className=\"text-right\" onClick={(e) => e.stopPropagation()}>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label={`Actions for ${portfolio?.name ?? 'proposal'}`}\n >\n <MoreHorizontal className=\"size-4\" aria-hidden=\"true\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem onClick={() => setDetailProposal(p)}>\n <Eye className=\"size-4\" aria-hidden=\"true\" />\n View details\n </DropdownMenuItem>\n {nextStatuses.length > 0 ? (\n <>\n <DropdownMenuSeparator />\n <DropdownMenuLabel>Advance to</DropdownMenuLabel>\n {nextStatuses.map((status) => {\n const destructive =\n status === 'REJECTED' || status === 'CANCELLED';\n return (\n <DropdownMenuItem\n key={status}\n disabled={transitionProposal.isPending}\n className={\n destructive ? 'text-status-error-text' : undefined\n }\n onClick={() => requestTransition(p, status)}\n >\n {destructive ? (\n <X className=\"size-4\" aria-hidden=\"true\" />\n ) : (\n <ArrowRight className=\"size-4\" aria-hidden=\"true\" />\n )}\n {humanize(status)}\n </DropdownMenuItem>\n );\n })}\n </>\n ) : null}\n </DropdownMenuContent>\n </DropdownMenu>\n </TableCell>\n </TableRow>\n );\n })}\n </TableBody>\n </Table>\n </div>\n )}\n </CardContent>\n </Card>\n\n {/* Risk insights */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <ShieldAlert className=\"h-5 w-5\" aria-hidden=\"true\" />\n Risk insights\n </CardTitle>\n <CardDescription>\n Drift, concentration, cash-drag and fee-anomaly signals detected across your portfolios.\n </CardDescription>\n </CardHeader>\n <CardContent>\n {insightsLoading ? (\n <LoadingState />\n ) : insightsError ? (\n <ErrorState onRetry={() => refetchInsights()} />\n ) : riskInsights.length === 0 ? (\n <EmptyState\n icon={<ShieldCheck className=\"size-6\" aria-hidden=\"true\" />}\n title=\"No risk insights\"\n description=\"No drift, concentration, cash-drag or fee-anomaly signals are open right now.\"\n />\n ) : (\n <div className=\"space-y-3\">\n {riskInsights.map((insight, i) => (\n <FadeIn key={insight.id} index={i}>\n <InsightRow\n insight={insight}\n onAcknowledge={() => acknowledgeInsight.mutate(insight.id)}\n onResolve={() => resolveInsight.mutate(insight.id)}\n onDismiss={() => dismissInsight.mutate(insight.id)}\n actionPending={\n acknowledgeInsight.isPending ||\n resolveInsight.isPending ||\n dismissInsight.isPending\n }\n />\n </FadeIn>\n ))}\n <LoadMore\n hasMore={insightsHasMore}\n onClick={loadMoreInsights}\n loading={insightsFetchingMore}\n label=\"Load more insights\"\n />\n </div>\n )}\n </CardContent>\n </Card>\n\n {/* Create proposal dialog */}\n <Dialog open={createOpen} onOpenChange={setCreateOpen}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>New rebalance proposal</DialogTitle>\n <DialogDescription>\n Propose a rebalance for a portfolio that has drifted from its target allocation.\n </DialogDescription>\n </DialogHeader>\n {!canCreate ? (\n <EmptyState\n icon={<Scale className=\"size-6\" aria-hidden=\"true\" />}\n title=\"Create a portfolio first\"\n description=\"A rebalance proposal targets a portfolio. Add a portfolio on the Portfolios page, then return here to propose a rebalance.\"\n />\n ) : (\n <div className=\"grid gap-4\">\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"prop-portfolio\">\n Portfolio <span className=\"text-status-error-text\">*</span>\n </Label>\n <Select\n value={form.portfolioId}\n onValueChange={(v) => setForm((f) => ({ ...f, portfolioId: v }))}\n >\n <SelectTrigger id=\"prop-portfolio\">\n <SelectValue placeholder=\"Select a portfolio\" />\n </SelectTrigger>\n <SelectContent>\n {portfolios.map((p) => (\n <SelectItem key={p.id} value={p.id}>\n {p.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"prop-drift\">Drift %</Label>\n <Input\n id=\"prop-drift\"\n type=\"number\"\n value={form.driftPct}\n onChange={(e) => setForm((f) => ({ ...f, driftPct: e.target.value }))}\n placeholder=\"e.g. 6.5\"\n />\n </div>\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"prop-rationale\">Rationale</Label>\n <Textarea\n id=\"prop-rationale\"\n value={form.rationale}\n onChange={(e) => setForm((f) => ({ ...f, rationale: e.target.value }))}\n placeholder=\"Why is this rebalance needed?\"\n />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor=\"prop-trades\">Trades (JSON, optional)</Label>\n <Textarea\n id=\"prop-trades\"\n className=\"font-mono text-xs\"\n value={form.trades}\n onChange={(e) => {\n setTradesError(null);\n setForm((f) => ({ ...f, trades: e.target.value }));\n }}\n placeholder='e.g. [{\"symbol\":\"VOO\",\"action\":\"SELL\",\"quantity\":10}]'\n />\n {tradesError ? (\n <p className=\"text-xs text-status-error-text\">{tradesError}</p>\n ) : null}\n </div>\n </div>\n )}\n <DialogFooter>\n <DialogClose asChild>\n <Button variant=\"outline\">Cancel</Button>\n </DialogClose>\n <Button onClick={submitCreate} disabled={!form.portfolioId || createProposal.isPending}>\n {createProposal.isPending ? 'Creating…' : 'Create proposal'}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n\n {/* Proposal detail — lifecycle, proposed trades, risk insights + discussion */}\n {(() => {\n // Re-read from the live list so the stepper/status reflect transitions.\n const live = detailProposal\n ? (proposals.find((p) => p.id === detailProposal.id) ?? detailProposal)\n : null;\n const related = live ? insights.filter((i) => i.subjectId === live.portfolioId) : [];\n return (\n <ProposalDetailDialog\n proposal={live}\n portfolio={live ? (portfolioById.get(live.portfolioId) ?? null) : null}\n relatedInsights={related}\n nextStatuses={live ? NEXT_STATUSES[live.status] : []}\n transitionPending={transitionProposal.isPending}\n onTransition={(status) => {\n if (live) requestTransition(live, status);\n }}\n onOpenChange={(open) => {\n if (!open) setDetailProposal(null);\n }}\n />\n );\n })()}\n\n {/* Confirm destructive lifecycle transition (reject / cancel) */}\n <ConfirmDialog\n open={confirmTransition !== null}\n onOpenChange={(open) => {\n if (!open) setConfirmTransition(null);\n }}\n title={\n confirmTransition?.status === 'REJECTED'\n ? 'Reject this proposal?'\n : 'Cancel this proposal?'\n }\n description={\n confirmTransition\n ? `This moves the rebalance proposal for ${\n portfolioById.get(confirmTransition.proposal.portfolioId)?.name ?? 'this portfolio'\n } to ${humanize(confirmTransition.status)}. This cannot be undone.`\n : undefined\n }\n confirmLabel={confirmTransition?.status === 'REJECTED' ? 'Reject' : 'Cancel proposal'}\n cancelLabel=\"Keep\"\n destructive\n pending={transitionProposal.isPending}\n onConfirm={() => {\n if (!confirmTransition) return;\n transitionProposal.mutate(\n { id: confirmTransition.proposal.id, status: confirmTransition.status },\n { onSuccess: () => setConfirmTransition(null) }\n );\n }}\n />\n </SectionShell>\n );\n}\n\n// ============================================================================\n// Proposal detail dialog — rationale summary, actors, and discussion thread\n// ============================================================================\n\nfunction ProposalDetailDialog({\n proposal,\n portfolio,\n relatedInsights,\n nextStatuses,\n transitionPending,\n onTransition,\n onOpenChange,\n}: {\n proposal: BraRebalanceProposal | null;\n portfolio: BraPortfolio | null;\n relatedInsights: BraInsight[];\n nextStatuses: BraRebalanceStatus[];\n transitionPending: boolean;\n onTransition: (status: BraRebalanceStatus) => void;\n onOpenChange: (open: boolean) => void;\n}) {\n const trades = proposal ? parseTrades(proposal.trades) : null;\n const breached =\n proposal != null &&\n portfolio?.driftThresholdPct != null &&\n Number.isFinite(portfolio.driftThresholdPct) &&\n proposal.driftPct >= portfolio.driftThresholdPct;\n\n return (\n <Dialog open={proposal !== null} onOpenChange={onOpenChange}>\n <DialogContent className=\"max-h-[88vh] max-w-3xl overflow-y-auto\">\n {proposal ? (\n <>\n <DialogHeader>\n <p className=\"text-xs font-medium uppercase tracking-wide text-text-secondary\">\n Detail\n </p>\n <DialogTitle className=\"flex flex-wrap items-center gap-2 text-xl\">\n {portfolio?.name ?? 'Rebalance proposal'}\n <span className=\"text-text-secondary\">— Rebalance proposal</span>\n <Badge variant={statusBadgeVariant(proposal.status)}>\n {humanize(proposal.status)}\n </Badge>\n </DialogTitle>\n <DialogDescription>\n Created {formatDate(proposal.createdAt)}\n {proposal.executedAt ? ` · executed ${formatDate(proposal.executedAt)}` : ''}\n </DialogDescription>\n </DialogHeader>\n\n {/* Lifecycle stepper — DRAFT → PROPOSED → APPROVED → EXECUTED (+ side states). */}\n <div className=\"rounded-xl border border-border-subtle bg-bg-surface p-4\">\n <LifecycleStepper steps={LIFECYCLE_STEPS} current={humanize(proposal.status)} />\n </div>\n\n {/* Key facts as premium tiles */}\n <div className=\"grid gap-3 sm:grid-cols-2 lg:grid-cols-4\">\n <StatTile\n label=\"Drift\"\n value={formatPct(proposal.driftPct)}\n deltaTone={breached ? 'negative' : 'neutral'}\n glow={breached}\n icon={<Gauge className=\"size-4\" aria-hidden=\"true\" />}\n />\n <StatTile\n label=\"Threshold\"\n value={\n portfolio?.driftThresholdPct != null\n ? formatPct(portfolio.driftThresholdPct)\n : '—'\n }\n />\n <div className=\"rounded-xl border border-border-subtle bg-bg-surface p-4\">\n <p className=\"text-xs text-text-secondary\">Proposed by</p>\n <p className=\"mt-1 truncate text-sm font-medium text-text-primary\">\n {proposal.proposedById ? <ActorName id={proposal.proposedById} /> : '—'}\n </p>\n </div>\n <div className=\"rounded-xl border border-border-subtle bg-bg-surface p-4\">\n <p className=\"text-xs text-text-secondary\">Approved by</p>\n <p className=\"mt-1 truncate text-sm font-medium text-text-primary\">\n {proposal.approvedById ? <ActorName id={proposal.approvedById} /> : '—'}\n </p>\n </div>\n </div>\n\n {/* Proposed trades */}\n <div className=\"space-y-2\">\n <h3 className=\"text-sm font-semibold text-text-primary\">Proposed trades</h3>\n {trades && trades.length > 0 ? (\n <div className=\"overflow-x-auto rounded-lg border border-border-subtle\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>Action</TableHead>\n <TableHead>Symbol</TableHead>\n <TableHead className=\"text-right\">Quantity</TableHead>\n <TableHead className=\"text-right\">Est. value</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {trades.map((t, i) => (\n <TableRow key={i}>\n <TableCell className={`font-semibold ${tradeActionTone(t.action)}`}>\n {t.action ? t.action.toUpperCase() : '—'}\n </TableCell>\n <TableCell className=\"font-medium text-text-primary\">\n {t.symbol ?? '—'}\n </TableCell>\n <TableCell className=\"text-right tabular-nums text-text-secondary\">\n {t.quantity != null ? t.quantity.toLocaleString() : '—'}\n </TableCell>\n <TableCell className=\"text-right tabular-nums text-text-secondary\">\n {t.value != null\n ? formatMoney(t.value, portfolio?.baseCurrency ?? 'USD')\n : '—'}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n ) : (\n <p className=\"text-sm text-text-secondary\">\n {summarizeTrades(proposal.trades)} — no structured trade breakdown available.\n </p>\n )}\n </div>\n\n {/* Rationale */}\n <div className=\"space-y-1\">\n <h3 className=\"text-sm font-semibold text-text-primary\">Rationale</h3>\n <p className=\"text-sm text-text-secondary\">{proposal.rationale ?? '—'}</p>\n </div>\n\n {/* Lifecycle actions (mirrors the row menu; destructive actions confirm) */}\n {nextStatuses.length > 0 ? (\n <div className=\"flex flex-wrap gap-2\">\n {nextStatuses.map((status) => {\n const destructive = status === 'REJECTED' || status === 'CANCELLED';\n return (\n <Button\n key={status}\n variant={destructive ? 'outline' : 'default'}\n size=\"sm\"\n disabled={transitionPending}\n className={destructive ? 'text-status-error-text' : undefined}\n onClick={() => onTransition(status)}\n >\n {destructive ? (\n <X className=\"size-4\" aria-hidden=\"true\" />\n ) : (\n <ArrowRight className=\"size-4\" aria-hidden=\"true\" />\n )}\n {humanize(status)}\n </Button>\n );\n })}\n </div>\n ) : null}\n\n {/* Risk insights tied to this portfolio (real, filtered by subjectId) */}\n {relatedInsights.length > 0 ? (\n <div className=\"space-y-2 border-t border-border-subtle pt-4\">\n <h3 className=\"flex items-center gap-2 text-sm font-semibold text-text-primary\">\n <ShieldAlert className=\"size-4\" aria-hidden=\"true\" />\n Risk insights\n </h3>\n <ul className=\"space-y-2\">\n {relatedInsights.map((insight) => (\n <li\n key={insight.id}\n className=\"rounded-lg border border-border-subtle bg-bg-surface p-3\"\n >\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"text-sm font-medium text-text-primary\">\n {insight.title}\n </span>\n <Badge variant={statusBadgeVariant(insight.severity)}>\n {humanize(insight.severity)}\n </Badge>\n <Badge variant=\"outline\">{humanize(insight.type)}</Badge>\n <Badge variant={statusBadgeVariant(insight.status)}>\n {humanize(insight.status)}\n </Badge>\n </div>\n {insight.detail ? (\n <p className=\"mt-1 text-xs text-text-secondary\">{insight.detail}</p>\n ) : null}\n </li>\n ))}\n </ul>\n </div>\n ) : null}\n\n <div className=\"border-t border-border-subtle pt-4\">\n <CommentThread\n entityType=\"brainyrich-rebalance\"\n entityId={proposal.id}\n heading=\"Discussion\"\n />\n </div>\n </>\n ) : null}\n </DialogContent>\n </Dialog>\n );\n}\n\n// ============================================================================\n// Risk signal row (BOFF-4236) — real inputs/formula always shown, never hidden\n// ============================================================================\n\nfunction RiskSignalRow({ signal }: { signal: BraRiskSignal }) {\n const metricEntries = Object.entries((signal.metrics as Record<string, unknown>) ?? {});\n return (\n <li className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <p className=\"font-medium text-text-primary\">{signal.title}</p>\n <Badge variant={statusBadgeVariant(signal.severity)}>{humanize(signal.severity)}</Badge>\n <Badge variant=\"outline\">{humanize(signal.kind)}</Badge>\n </div>\n {signal.detail ? <p className=\"mt-1 text-sm text-text-secondary\">{signal.detail}</p> : null}\n {metricEntries.length > 0 ? (\n <dl className=\"mt-3 grid grid-cols-2 gap-x-4 gap-y-1 sm:grid-cols-3 lg:grid-cols-4\">\n {metricEntries.map(([key, value]) => (\n <div key={key} className=\"min-w-0\">\n <dt className=\"truncate text-[11px] uppercase tracking-wide text-text-muted\">\n {humanize(key)}\n </dt>\n <dd className=\"truncate text-sm font-medium tabular-nums text-text-primary\">\n {formatMetricValue(value)}\n </dd>\n </div>\n ))}\n </dl>\n ) : null}\n </li>\n );\n}\n\n// ============================================================================\n// Tax-loss opportunity row (BOFF-4237) — real numbers + wash-sale caution\n// ============================================================================\n\nfunction TaxLossOpportunityRow({ opportunity }: { opportunity: BraTaxLossOpportunity }) {\n const metricEntries = Object.entries((opportunity.metrics as Record<string, unknown>) ?? {});\n return (\n <li className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <p className=\"font-medium text-text-primary\">\n {opportunity.symbol} — unrealized loss {formatMoney(opportunity.unrealizedLoss)}\n </p>\n <Badge variant={statusBadgeVariant(opportunity.severity)}>\n {humanize(opportunity.severity)}\n </Badge>\n {opportunity.washSaleRisk ? (\n <Badge variant=\"outline\" className=\"text-status-error-text\">\n <AlertTriangle className=\"mr-1 size-3\" aria-hidden=\"true\" />\n Wash-sale caution\n </Badge>\n ) : null}\n </div>\n <p className=\"mt-1 text-sm text-text-secondary\">\n Market value {formatMoney(opportunity.marketValue)} vs. cost basis{' '}\n {formatMoney(opportunity.costBasis)}\n {' · '}\n {formatPct(opportunity.lossPctOfPortfolio)} of portfolio value\n </p>\n {opportunity.washSaleReason ? (\n <p className=\"mt-1 text-xs text-status-error-text\">{opportunity.washSaleReason}</p>\n ) : null}\n {metricEntries.length > 0 ? (\n <dl className=\"mt-3 grid grid-cols-2 gap-x-4 gap-y-1 sm:grid-cols-3 lg:grid-cols-4\">\n {metricEntries\n .filter(([key]) => key !== 'formula')\n .map(([key, value]) => (\n <div key={key} className=\"min-w-0\">\n <dt className=\"truncate text-[11px] uppercase tracking-wide text-text-muted\">\n {humanize(key)}\n </dt>\n <dd className=\"truncate text-sm font-medium tabular-nums text-text-primary\">\n {formatMetricValue(value)}\n </dd>\n </div>\n ))}\n </dl>\n ) : null}\n </li>\n );\n}\n\n// ============================================================================\n// Insight row\n// ============================================================================\n\nfunction InsightRow({\n insight,\n onAcknowledge,\n onResolve,\n onDismiss,\n actionPending,\n}: {\n insight: BraInsight;\n onAcknowledge: () => void;\n onResolve: () => void;\n onDismiss: () => void;\n actionPending: boolean;\n}) {\n const terminal = insight.status === 'RESOLVED' || insight.status === 'DISMISSED';\n return (\n <div className=\"flex items-start justify-between gap-4 rounded-lg border border-border-subtle bg-bg-surface p-4 transition-shadow motion-safe:hover:shadow-[var(--shadow-pop-hover,var(--shadow-elevation-2))]\">\n <div className=\"min-w-0 space-y-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <p className=\"font-medium text-text-primary\">{insight.title}</p>\n <Badge variant={statusBadgeVariant(insight.severity)}>{humanize(insight.severity)}</Badge>\n <Badge variant=\"outline\">{humanize(insight.type)}</Badge>\n <Badge variant={statusBadgeVariant(insight.status)}>{humanize(insight.status)}</Badge>\n </div>\n {insight.detail ? <p className=\"text-sm text-text-secondary\">{insight.detail}</p> : null}\n <p className=\"text-xs text-text-muted\">Detected {formatDate(insight.createdAt)}</p>\n </div>\n {terminal ? (\n <span className=\"mt-1 text-xs text-text-muted\">Closed</span>\n ) : (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label={`Actions for ${insight.title}`}\n disabled={actionPending}\n >\n <MoreHorizontal className=\"size-4\" aria-hidden=\"true\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {insight.status === 'OPEN' ? (\n <DropdownMenuItem onClick={onAcknowledge}>\n <Check className=\"size-4\" aria-hidden=\"true\" />\n Acknowledge\n </DropdownMenuItem>\n ) : null}\n <DropdownMenuItem onClick={onResolve}>\n <ShieldCheck className=\"size-4\" aria-hidden=\"true\" />\n Resolve\n </DropdownMenuItem>\n <DropdownMenuItem className=\"text-status-error-text\" onClick={onDismiss}>\n <X className=\"size-4\" aria-hidden=\"true\" />\n Dismiss\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-brainyrich",
3
- "version": "2026.731.1",
3
+ "version": "2026.731.2",
4
4
  "description": "Burdenoff BrainyRich Microfrontend",
5
5
  "type": "module",
6
6
  "files": [