fix(rectification): stop discriminator followup from dropping user evidence
Independent Staging Quality Gate / validate (push) Successful in 10m10s
Independent Staging Quality Gate / publish (push) Successful in 7m25s

Decision and question ranking now share contrast option completion, so a
missing style card cannot deadlock the interview with a dead-end reply.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-08-29 10:23:34 +08:00
co-authored by Cursor
parent 31b54aa71d
commit 86d6923e6e
15 changed files with 1054 additions and 124 deletions
@@ -4,7 +4,13 @@
*/
import type { AnswerClass, ConflictProbe } from "./types.ts";
import { d9StyleLabel, d10StyleLabel } from "../v9/varga-type-tables.ts";
import {
D9_TYPE_TABLE,
D10_TYPE_TABLE,
d9StyleLabel,
d10StyleLabel,
signKey,
} from "../v9/varga-type-tables.ts";
import {
completeStyleOptions,
isRenderableProbe,
@@ -469,7 +475,7 @@ export function selectDiscriminatorProbe(
return inspectDiscriminatorProbes(packet, options).selected;
}
function withCompletedContrastOptions(
export function withCompletedContrastOptions(
probe: CandidateDiscriminatorProbe,
): { ok: true; probe: CandidateDiscriminatorProbe } | { ok: false; reason: DroppedProbe["reason"] } {
const mapped = probe.styleOptions?.map((item) => ({
@@ -522,22 +528,37 @@ function inferredVargaStyleIncoming(
});
}
function knownVargaSigns(layer: "d9" | "d10", tokens: readonly string[]): string[] {
const table = layer === "d9" ? D9_TYPE_TABLE : D10_TYPE_TABLE;
return tokens.flatMap((token) => {
const key = signKey(token);
return table[key] ? [key] : [];
});
}
function signsFromVargaProbe(
probe: CandidateDiscriminatorProbe,
): { layer: "d9" | "d10"; signs: string[] } | null {
const match = probe.semanticKey.match(/^varga\.(d9|d10)\.(.+)$/);
const layer = match?.[1] === "d9" || match?.[1] === "d10" ? match[1] : null;
const fromKey = match?.[2]
?.split(/[|/]/)
.map((item) => item.trim())
.filter((item) => item && !/^\d{1,2}:\d{2}$/.test(item))
?? [];
const fromOutcomes = probe.expectedOutcomes.flatMap((row) => {
const token = row.outcomeId.replace(/^supports_/, "").trim();
return token && !/^\d{1,2}:\d{2}$/.test(token) ? [token] : [];
});
if (!layer) return null;
const fromKey = knownVargaSigns(
layer,
match?.[2]
?.split(/[|/]/)
.map((item) => item.trim())
.filter((item) => item && !/^\d{1,2}:\d{2}$/.test(item))
?? [],
);
const fromOutcomes = knownVargaSigns(
layer,
probe.expectedOutcomes.flatMap((row) => {
const token = row.outcomeId.replace(/^supports_/, "").trim();
return token && !ANSWER_CLASSES.has(token) && !/^\d{1,2}:\d{2}$/.test(token) ? [token] : [];
}),
);
const signs = (fromKey.length >= 2 ? fromKey : fromOutcomes).slice(0, 3);
if (!layer || signs.length < 2) return null;
if (signs.length < 2) return null;
return { layer, signs };
}
@@ -568,12 +589,29 @@ function withUnsureOutcome(
return rows;
}
function conflictStyleOptions(
probe: CandidateDiscriminatorProbe,
): ConflictProbe["style_options"] {
const rows = probe.styleOptions?.flatMap((item) => {
const label = item.label.trim();
if (!label) return [];
return [{
label,
answer_class: item.answerClass,
...(item.sign ? { sign: item.sign } : {}),
}];
}) ?? [];
return rows.length > 0 ? rows : undefined;
}
export function conflictProbesFromContrast(
packet: CandidateContrastPacket | null | undefined,
): ConflictProbe[] {
return (packet?.probes ?? []).flatMap((probe) => {
if (!probe.semanticKey.startsWith("varga.")) return [];
const outcomes = probe.expectedOutcomes.flatMap((row, index) => {
const completed = withCompletedContrastOptions(probe);
const working = completed.ok ? completed.probe : probe;
const outcomes = working.expectedOutcomes.flatMap((row, index) => {
const answer = ANSWER_CLASSES.has(row.outcomeId)
? row.outcomeId as AnswerClass
: (["yes", "weak_yes", "no"][index] as AnswerClass | undefined);
@@ -585,29 +623,33 @@ export function conflictProbesFromContrast(
}];
});
if (outcomes.length < 2) return [];
if (probe.informationGain <= 0) return [];
const candidateIds = [...new Set(probe.expectedOutcomes.flatMap((row) => [
if (working.informationGain <= 0) return [];
const candidateIds = [...new Set(working.expectedOutcomes.flatMap((row) => [
...row.supportsCandidateIds,
...row.conflictsCandidateIds,
]))];
if (candidateIds.length < 2) return [];
const choiceKind = effectiveContrastChoiceKind(probe);
const choiceKind = completed.ok
? (working.choiceKind ?? effectiveContrastChoiceKind(working))
: effectiveContrastChoiceKind(probe);
const styleOptions = conflictStyleOptions(working);
return [{
id: probe.probeId,
semantic_key: probe.semanticKey,
candidate_split_hash: probe.candidateSplitHash,
domain: probe.domain ?? "career",
year: probe.year ?? 0,
question: probe.question,
id: working.probeId,
semantic_key: working.semanticKey,
candidate_split_hash: working.candidateSplitHash,
domain: working.domain ?? "career",
year: working.year ?? 0,
question: working.question,
candidate_ids: candidateIds,
expected_outcomes: outcomes,
information_gain: probe.informationGain,
information_gain: working.informationGain,
source: "varga_contrast",
...(choiceKind === "varga_style"
|| choiceKind === "event_quality"
|| choiceKind === "existence"
? { choice_kind: choiceKind }
: {}),
...(styleOptions ? { style_options: styleOptions } : {}),
}];
});
}
@@ -20,6 +20,7 @@ export function probeFromEngine(probe: EngineProbeFields): ConflictProbe | null
if (outcomes.length < 2 || candidateIds.length < 2 || (probe.information_gain ?? 0) <= 0) {
return null;
}
const styleOptions = styleOptionsFromEngine(probe.style_options);
return {
id: `probe:${semanticKey}:${splitHash}`,
semantic_key: semanticKey,
@@ -36,9 +37,23 @@ export function probeFromEngine(probe: EngineProbeFields): ConflictProbe | null
|| probe.choice_kind === "existence"
? { choice_kind: probe.choice_kind }
: {}),
...(styleOptions.length > 0 ? { style_options: styleOptions } : {}),
};
}
function styleOptionsFromEngine(
rows: DiscriminatingEventProbe["style_options"],
): NonNullable<ConflictProbe["style_options"]> {
return (rows ?? []).flatMap((row) => {
if (!ANSWER_CLASSES.has(row.answer_class)) return [];
return [{
label: row.label,
answer_class: row.answer_class as AnswerClass,
...(row.sign ? { sign: row.sign } : {}),
}];
});
}
function outcomesFromEngine(
rows: DiscriminatingEventProbe["expected_outcomes"],
): ProbeOutcome[] {
@@ -85,6 +85,11 @@ export type ConflictProbe = Readonly<{
information_gain: number;
source: string;
choice_kind?: ProbeChoiceKind;
style_options?: readonly Readonly<{
label: string;
answer_class: AnswerClass;
sign?: string;
}>[];
}>;
export type ProbeAnswer = Readonly<{