/** * 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 { askedKeysFromLedgerEvidence } from "../core/candidate-contrast-packet.ts"; import { askedProbeKeysFromReceipt, previousInferenceFromReceipt } from "./inference-adapter"; import { contrastPacketFromDossier, decideFromDossier, } from "./decision-from-dossier"; import { evidenceLedgerFingerprint } from "./tool-service"; import { latestUserStoppedCollecting, projectRectificationChoiceCard } from "./method-followup"; import { refinementFromDecisionReceipt } from "./refinement-packet"; 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; intent: string; targetDomain: string | null; targetKind: string | null; expectedAnswerSchema?: Readonly> | null; } | null; declinedSkippedTopics: readonly Readonly>[]; }; latestResult: { resultId?: string; decisionReceipt: Readonly> | null; selectionAllowed?: boolean; candidates?: readonly Readonly<{ time: string; relativeSupport?: number }>[]; evidenceLedgerFingerprint?: string | null; } | null; case: { acceptedTime: string | null; }; turns?: readonly Readonly<{ role: string; text: string | null }>[]; }): RectificationChoiceCard | null { const windowScan = windowScanFromDecisionReceipt(dossier.latestResult?.decisionReceipt ?? null); const observations = internalObservationsFromWindowScan(windowScan); const refinement = refinementFromDecisionReceipt(dossier.latestResult?.decisionReceipt ?? null); const inference = previousInferenceFromReceipt(dossier.latestResult?.decisionReceipt ?? null); const contrastPacket = contrastPacketFromDossier(dossier); const decision = decideFromDossier(dossier, { currentEvidenceFingerprint: evidenceLedgerFingerprint(dossier.evidence as never), }); const latestAssistantText = [...(dossier.turns ?? [])] .reverse() .find((turn) => turn.role === "assistant") ?.text ?? null; const holdoutEvents = (inference?.events ?? []) .filter((item) => item.usage === "holdout") .map((item) => ({ domain: item.domain, year: item.year })); return projectRectificationChoiceCard({ evidence: dossier.evidence, activeFocus: dossier.conversationSummary.activeFocus, declinedTopics: dossier.conversationSummary.declinedSkippedTopics, observations, sessionOutcome: decision.sessionOutcome, precisionStage: decision.precisionStage === "collect_events" ? "collect_events" : decision.precisionStage === "ready_to_adopt" ? "ready_to_adopt" : refinement.precision_stage?.current, nakshatraBoundary: refinement.nakshatra_boundary, oosBlindPrompts: refinement.oos_blind_prompts, eventProbes: refinement.discriminating_event_probes, eventClarificationProbes: refinement.event_clarification_probes, evidenceCollectionProbes: refinement.evidence_collection_probes, askedProbeKeys: [ ...askedProbeKeysFromReceipt(dossier.latestResult?.decisionReceipt), ...askedKeysFromLedgerEvidence(dossier.evidence), ], accepted: Boolean(dossier.case.acceptedTime), selectionAllowed: decision.selectionAllowed, proposeAllowed: decision.proposeAllowed, caseRevision: inference?.revision ?? 0, contrastPacket, candidateScores: decision.separation.ranked.map((item) => ({ time: item.time, score: item.score, })), userStopped: latestUserStoppedCollecting(dossier.turns ?? []), latestAssistantText, candidatesSeparated: decision.separation.sufficient, holdoutValidation: decision.holdoutValidation, holdoutEvents, }); } export { decideFromDossier, overlayPublicDecision } from "./decision-from-dossier";