Files
Jyotisha/frontend/src/lib/rectification-agentic/v9/interview-state.ts
T
Jesse_Chen f5e73ef326
Independent Staging Quality Gate / validate (push) Failing after 22m30s
Independent Staging Quality Gate / publish (push) Has been skipped
fix(web): rank remaining-minute probes by split and match choice kind
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>
2026-08-25 20:44:55 +08:00

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,
});
}