import Drawer from '@mui/material/Drawer';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import Button from '@mui/material/Button';
import Chip from '@mui/material/Chip';
import Divider from '@mui/material/Divider';
import IconButton from '@mui/material/IconButton';
import Table from '@mui/material/Table';
import TableBody from '@mui/material/TableBody';
import TableCell from '@mui/material/TableCell';
import TableRow from '@mui/material/TableRow';
import { Sparkles, X } from 'lucide-react';
import type { CopilotExplainRequest, EvaluationRecord, RareEvent } from '../../types/labeleval';
import { StatusChip, GateLineList, fmtNum, fmtPct, HBar } from './shared';
function MetricRow({ label, value }: { label: string; value: string }) {
return (
{label}
{value}
);
}
export function evidenceCopilotRequest(record: EvaluationRecord): CopilotExplainRequest {
const primary = record.decision?.primary_failure_reason ?? null;
let contextType: CopilotExplainRequest['context_type'] = 'general';
if (record.anomaly.is_anomaly) contextType = 'anomaly';
if (primary === 'GRADER_DISAGREEMENT') contextType = 'disagreement';
if (primary === 'MODEL_REGRESSION') contextType = 'regression';
return {
context_type: contextType,
annotation_id: record.annotation_id,
model_version: record.model_version,
};
}
export default function EvidencePanel({
open,
onClose,
record,
event,
onAskCopilot,
}: {
open: boolean;
onClose: () => void;
record?: EvaluationRecord | null;
event?: RareEvent | null;
onAskCopilot: (request: CopilotExplainRequest) => void;
}) {
return (
Evidence
{record ? (
<>
{record.decision ? : null}
Frame {record.frame_id} · Dataset {record.dataset_id} · Detection confidence{' '}
{fmtNum(record.detection.confidence)}
{record.ground_truth_type ? ` · GT: ${record.ground_truth_type}` : ' · No ground truth reference'}
Geometry
Anomaly ensemble — {record.anomaly.ensemble_strategy.replace(/_/g, ' ')} · threshold{' '}
{fmtNum(record.anomaly.decision_threshold)}
Score {fmtNum(record.anomaly.score)}
{Object.entries(record.anomaly.detector_scores).map(([name, score]) => (
))}
Grading ({record.grading.grader_count} graders)
{record.grading.disagreement_types.length > 0 ? (
{record.grading.disagreement_types.map((d) => (
))}
) : null}
Tracking
ID switch: {record.tracking.id_switch ? 'yes' : 'no'} · Fragmentation:{' '}
{record.tracking.fragmentation ? 'yes' : 'no'} · Track quality: {fmtNum(record.tracking.track_quality)}
Quality gates {record.validation.passed ? '— PASSED' : '— FAILED'}
{record.decision ? (
<>
Triage decision — policy {record.decision.policy_id}
{record.decision.primary_failure_reason ? (
Primary failure: {record.decision.primary_failure_reason.replace(/_/g, ' ')}
) : null}
>
) : null}
{record.injected_errors.length > 0 ? (
<>
Synthetic injected defects (demo transparency): {record.injected_errors.join(', ')}
>
) : null}
}
onClick={() => onAskCopilot(evidenceCopilotRequest(record))}
>
Ask Copilot
>
) : null}
{event ? (
<>
{event.verified ? : null}
{event.description}
Evidence frames ({event.evidence_frames.length})
{event.evidence_frames.map((f) => (
))}
{Object.keys(event.sensor_evidence).length > 0 ? (
<>
Sensor evidence
{Object.entries(event.sensor_evidence).map(([sensor, note]) => (
))}
>
) : null}
}
onClick={() => onAskCopilot({ context_type: 'anomaly', event_id: event.event_id })}
>
Ask Copilot
>
) : null}
{!record && !event ? (
No evidence selected.
) : null}
);
}