f5e73ef326
Choice cards used a hardcoded domain menu and always asked existence. Rank scoring layers by remaining-minute entropy, keep finance and health volunteer-only, and ask D9/D10 style or exam quality so taps match outcomes. Co-authored-by: Cursor <cursoragent@cursor.com>
116 lines
4.8 KiB
TypeScript
116 lines
4.8 KiB
TypeScript
/**
|
|
* 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.
|
|
*/
|
|
|
|
import {
|
|
askedKeysFromLedgerEvidence,
|
|
buildCandidateContrastPacket,
|
|
volunteeredDomainsFromEvidence,
|
|
} from "../core/candidate-contrast-packet.ts";
|
|
import { evaluateCandidateSeparation } from "../core/candidate-separation.ts";
|
|
import { askedProbeKeysFromReceipt, previousInferenceFromReceipt } from "./inference-adapter";
|
|
import { latestUserStoppedCollecting, projectRectificationChoiceCard } from "./method-followup";
|
|
import { refinementFromDecisionReceipt } from "./refinement-packet";
|
|
import {
|
|
internalObservationsFromWindowScan,
|
|
windowScanFromDecisionReceipt,
|
|
} from "./varga-observations";
|
|
import type { RectificationChoiceCard } from "./choice-card";
|
|
|
|
function candidateScoresFromDossier(latest: {
|
|
decisionReceipt: Readonly<Record<string, unknown>> | null;
|
|
candidates?: readonly Readonly<{ time: string; relativeSupport?: number; posterior_score?: number }>[];
|
|
} | null) {
|
|
const inference = previousInferenceFromReceipt(latest?.decisionReceipt ?? null);
|
|
if (inference && inference.candidates.length > 0) {
|
|
return inference.candidates.map((item) => ({ time: item.time, score: item.posterior_score }));
|
|
}
|
|
return (latest?.candidates ?? []).map((item) => ({
|
|
time: item.time,
|
|
score: item.relativeSupport ?? item.posterior_score ?? 0,
|
|
}));
|
|
}
|
|
|
|
export function choiceCardFromCaseDossier(dossier: {
|
|
evidence: readonly Readonly<{
|
|
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<Record<string, unknown>> | null;
|
|
} | null;
|
|
declinedSkippedTopics: readonly Readonly<Record<string, unknown>>[];
|
|
};
|
|
latestResult: {
|
|
resultId?: string;
|
|
decisionReceipt: Readonly<Record<string, unknown>> | null;
|
|
selectionAllowed?: boolean;
|
|
candidates?: readonly Readonly<{ time: string; relativeSupport?: number }>[];
|
|
} | 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 candidateScores = candidateScoresFromDossier(dossier.latestResult);
|
|
const askedProbeKeys = [
|
|
...askedProbeKeysFromReceipt(dossier.latestResult?.decisionReceipt),
|
|
...askedKeysFromLedgerEvidence(dossier.evidence),
|
|
];
|
|
const contrastPacket = buildCandidateContrastPacket({
|
|
candidateSetVersion: inference?.candidate_set_id ?? dossier.latestResult?.resultId ?? "none",
|
|
calculationResultId: dossier.latestResult?.resultId ?? null,
|
|
engineProbes: refinement.discriminating_event_probes,
|
|
vargaDifferences: [
|
|
...(windowScan?.d9_candidates_differ && windowScan.d9_sign_names.length >= 2
|
|
? [{ layer: "d9", signs: windowScan.d9_sign_names }]
|
|
: []),
|
|
...(windowScan?.d10_candidates_differ && windowScan.d10_sign_names.length >= 2
|
|
? [{ layer: "d10", signs: windowScan.d10_sign_names }]
|
|
: []),
|
|
],
|
|
candidateTimes: candidateScores.map((item) => item.time),
|
|
transitions: windowScan?.transitions ?? [],
|
|
askedKeys: askedProbeKeys,
|
|
volunteeredDomains: volunteeredDomainsFromEvidence(dossier.evidence),
|
|
});
|
|
const userStopped = latestUserStoppedCollecting(dossier.turns ?? []);
|
|
return projectRectificationChoiceCard({
|
|
evidence: dossier.evidence,
|
|
activeFocus: dossier.conversationSummary.activeFocus,
|
|
declinedTopics: dossier.conversationSummary.declinedSkippedTopics,
|
|
observations,
|
|
sessionOutcome: dossier.case.acceptedTime ? "adopt_representative" : "collect_evidence",
|
|
precisionStage: refinement.precision_stage?.current,
|
|
nakshatraBoundary: refinement.nakshatra_boundary,
|
|
oosBlindPrompts: refinement.oos_blind_prompts,
|
|
eventProbes: refinement.discriminating_event_probes,
|
|
askedProbeKeys,
|
|
accepted: Boolean(dossier.case.acceptedTime),
|
|
selectionAllowed: dossier.latestResult?.selectionAllowed === true,
|
|
proposeAllowed: dossier.latestResult?.decisionReceipt?.propose_allowed === true,
|
|
caseRevision: inference?.revision ?? 0,
|
|
contrastPacket,
|
|
candidateScores,
|
|
userStopped,
|
|
candidatesSeparated: evaluateCandidateSeparation(candidateScores).sufficient,
|
|
});
|
|
}
|