import { useRef, useState } from "react"; import type { ConversationPlan } from "@chopin/protocol"; import { answerText, questionName } from "./analysis-labels"; const PATHS: Record = { "explicit-proposal": "Explicit proposal", "inferred-opportunity": "Inferred opportunity", "existing-offer-update": "Existing-offer update", }; const CHECKS: Record = { research_warranted: "Research need", external: "External suitability", owned: "Source ownership", subject_clarity: "Subject clarity (explicit + contextual)", already_answered: "Already-answered evidence", }; function percent(value: number): string { return `${Number((value * 100).toFixed(2))}%`; } export function ResearchDiagnostics({ analysis, pending, canEdit, onRetry }: { analysis?: ConversationPlan.ResearchAnalysis; pending: boolean; canEdit: boolean; onRetry: (id: string, actionId: string, lane?: "decision" | "research") => Promise; }) { let [busy, setBusy] = useState(false); let [error, setError] = useState(""); let action = useRef(undefined); if (!analysis && !pending) return null; return (

Research analysis

{pending ?

Waiting for research analysis

: ( <>

{analysis!.policyGate}

Model {analysis!.modelVersion} · Questions {analysis!.questionSetVersion} ·{" "} {analysis!.policyVersion && <>Policy {analysis!.policyVersion} ·{" "}} {analysis!.latencyMs} ms

{analysis!.admission && (

Admission path: {PATHS[analysis!.admission.path]}

{analysis!.admission.checks.map(check => { let passed = check.comparison === "minimum" ? check.score >= check.threshold : check.score <= check.threshold; return (
{CHECKS[check.signal]}
{percent(check.score)} ({check.comparison} {percent(check.threshold)};{" "} {passed ? "met" : "not met"})
); })}
)}
Research judgments
{Object.entries(analysis!.answers).map(([key, value]) => (
{questionName(key)}
{answerText(value)}
))}
)} {analysis?.status === "failed" && canEdit && ( )} {error &&

{error}

}
); }