/** * Public interview projection for the Case GET payload. * * The tap card is shown only when the follow-up is a discriminator * (candidates already diverge or holdout) and the Agent wrote choice copy. * Card identity is the persisted focus UUID plus the inference revision. */ import { previousInferenceFromReceipt } from "./inference-adapter"; import { decideFromDossier, rectificationFollowupCatalog, } from "./decision-from-dossier"; import { evidenceLedgerFingerprint } from "./tool-service"; import { projectRectificationChoiceCard } from "./method-followup"; import { internalObservationsFromWindowScan, windowScanFromDecisionReceipt, } from "./varga-observations"; import type { RectificationChoiceCard } from "./choice-card"; export function choiceCardFromCaseDossier(dossier: { evidence: readonly Readonly<{ id?: string; status: string; domain: string; datePrecision: string; occurredFrom: string | null; occurredTo: string | null; eventKind?: string | null; summary?: string | null; }>[]; conversationSummary: { activeFocus: { id?: string; questionId?: string; intent: string; targetDomain: string | null; targetKind: string | null; expectedAnswerSchema?: Readonly> | null; } | null; declinedSkippedTopics: readonly Readonly>[]; }; latestResult: { resultId?: string; decisionReceipt: Readonly> | null; selectionAllowed?: boolean; confirmationAllowed?: boolean; candidates?: readonly Readonly<{ time: string; rank?: number; tiedMinuteCount?: number; relativeSupport?: number; }>[]; evidenceLedgerFingerprint?: string | null; } | null; case: { acceptedTime: string | null; status?: string; }; turns?: readonly Readonly<{ role: string; text: string | null }>[]; }): RectificationChoiceCard | null { const catalog = rectificationFollowupCatalog(dossier.latestResult, dossier.evidence); const observations = internalObservationsFromWindowScan( windowScanFromDecisionReceipt(dossier.latestResult?.decisionReceipt ?? null), ); const inference = previousInferenceFromReceipt(dossier.latestResult?.decisionReceipt ?? null); const decision = decideFromDossier(dossier, { currentEvidenceFingerprint: evidenceLedgerFingerprint(dossier.evidence as never), }); const latestAssistantText = [...(dossier.turns ?? [])] .reverse() .find((turn) => turn.role === "assistant") ?.text ?? null; return projectRectificationChoiceCard({ evidence: dossier.evidence, activeFocus: dossier.conversationSummary.activeFocus, declinedTopics: dossier.conversationSummary.declinedSkippedTopics, closedCollectFocuses: dossier.conversationSummary.declinedSkippedTopics, observations, sessionOutcome: decision.sessionOutcome, ...catalog, precisionStage: decision.precisionStage === "collect_events" ? "collect_events" : decision.precisionStage === "ready_to_adopt" ? "ready_to_adopt" : catalog.precisionStage, accepted: Boolean(dossier.case.acceptedTime), selectionAllowed: decision.selectionAllowed, proposeAllowed: decision.proposeAllowed, confirmationAllowed: decision.canConfirmExactMinute, caseRevision: inference?.revision ?? 0, candidateScores: decision.separation.ranked.map((item) => ({ time: item.time, score: item.score, })), userStopped: dossier.case.status === "paused", latestAssistantText, candidatesSeparated: decision.separation.sufficient, holdoutValidation: decision.holdoutValidation, }); } export { decideFromDossier, overlayPublicDecision } from "./decision-from-dossier";