fix(rectification): stop yearless ungrounded varga contrast from minting cards
Only sign-bound varga_style questions may omit a concrete period. Remaining-layer existence and quality probes now drop as yearless_ungrounded_contrast instead of scoring by group order. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -437,6 +437,7 @@ export function inspectDiscriminatorProbes(
|
||||
expectedOutcomeCount: completed.probe.expectedOutcomes.length,
|
||||
choiceKind: completed.probe.choiceKind,
|
||||
styleOptions: completed.probe.styleOptions,
|
||||
year: completed.probe.year,
|
||||
});
|
||||
if (!renderable.ok) {
|
||||
dropped.push({
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*/
|
||||
|
||||
import type { AnswerClass } from "../core/types";
|
||||
import { completeStyleOptions, clippedProbeLabel } from "./probe-question-contract";
|
||||
import { completeStyleOptions, clippedProbeLabel, canRenderYearlessChoice } from "./probe-question-contract";
|
||||
import type { DiscriminatingEventProbe, EventProbeChoiceKind, EventProbeStyleOption } from "./refinement-packet";
|
||||
import type { InternalVargaObservation } from "./varga-observations";
|
||||
|
||||
@@ -337,8 +337,11 @@ function hypothesisFor(
|
||||
if (!styleOptions.ok) return null;
|
||||
const period = periodFor(evidence, domain, probes, birthDate, followup);
|
||||
const kind = followup.choice_kind ?? probe.choice_kind ?? "existence";
|
||||
const yearlessVarga = (followup.semantic_key ?? probe.semantic_key ?? "").startsWith("varga.");
|
||||
if (kind !== "varga_style" && !isConcreteChoicePeriod(period) && !yearlessVarga) return null;
|
||||
if (kind === "varga_style") {
|
||||
if (!canRenderYearlessChoice({ choiceKind: kind, styleOptions: styleOptions.options })) return null;
|
||||
} else if (!isConcreteChoicePeriod(period)) {
|
||||
return null;
|
||||
}
|
||||
const prompt = eventQuestionPrompt(period, probe.event_family, kind, domain);
|
||||
const why = probe.user_meaning?.trim() || followup.user_prompt_hint.trim();
|
||||
if (!why) return null;
|
||||
|
||||
@@ -47,13 +47,14 @@
|
||||
* do not stamp a ledger year onto a yearless scoring card. An open varga
|
||||
* discriminator must resolve from the contrast packet when Python event
|
||||
* probes have no row in that domain. Scoring reverse-inference cards need
|
||||
* the engine year or month. Yearless varga cards stay out of the dated
|
||||
* ranking until the training gate is open. Uncovered relationship, career,
|
||||
* and family still ask a same-domain card or spoken collect first.
|
||||
* Occupation collect must not block those yearless cards once training
|
||||
* events already pass. If the next ask would be a spoken
|
||||
* collect in the same domain, prefer a renderable yearless scoring card
|
||||
* instead of an unscoreable collect question.
|
||||
* the engine year or month. Yearless contrast is renderable only when
|
||||
* choice_kind is varga_style and scoring options carry signs. Other
|
||||
* remaining-layer probes stay in the packet but are dropped as
|
||||
* yearless_ungrounded_contrast. Uncovered relationship, career, and
|
||||
* family still ask a same-domain signed style card or dated spoken
|
||||
* collect first. Occupation collect must not block signed D9/D10 cards
|
||||
* once training events already pass. Do not re-widen yearless existence
|
||||
* or quality cards to keep the interview moving.
|
||||
*/
|
||||
|
||||
import {
|
||||
@@ -600,8 +601,10 @@ function renderableEventProbe(
|
||||
expectedOutcomeCount: probe.expected_outcomes?.length,
|
||||
choiceKind: probe.choice_kind,
|
||||
styleOptions: styleOptions.options,
|
||||
year: probe.year,
|
||||
yearLabel: probe.year_label,
|
||||
});
|
||||
if (!renderable.ok) {
|
||||
if (!renderable.ok && renderable.reason !== "yearless_ungrounded_contrast") {
|
||||
return { row: null, dropped: droppedFromProbe(key, probe.information_gain ?? 0, renderable.reason) };
|
||||
}
|
||||
const layer = vargaLayerFromSemanticKey(key);
|
||||
@@ -620,7 +623,9 @@ function renderableEventProbe(
|
||||
topCandidateTimes,
|
||||
}),
|
||||
},
|
||||
dropped: null,
|
||||
dropped: renderable.ok
|
||||
? null
|
||||
: droppedFromProbe(key, probe.information_gain ?? 0, renderable.reason),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -653,8 +658,9 @@ function renderableContrastProbe(
|
||||
expectedOutcomeCount: working.expectedOutcomes.length,
|
||||
choiceKind: working.choiceKind,
|
||||
styleOptions,
|
||||
year: working.year,
|
||||
});
|
||||
if (!renderable.ok) {
|
||||
if (!renderable.ok && renderable.reason !== "yearless_ungrounded_contrast") {
|
||||
return {
|
||||
row: null,
|
||||
dropped: droppedFromProbe(working.semanticKey, working.informationGain, renderable.reason),
|
||||
@@ -677,7 +683,9 @@ function renderableContrastProbe(
|
||||
topCandidateTimes,
|
||||
}),
|
||||
},
|
||||
dropped: null,
|
||||
dropped: renderable.ok
|
||||
? null
|
||||
: droppedFromProbe(working.semanticKey, working.informationGain, renderable.reason),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -853,10 +861,12 @@ function agentHint(
|
||||
}
|
||||
|
||||
export function shouldAttachChoiceFrame(
|
||||
item: Pick<MethodFollowup, "intent" | "ask_theme" | "source">,
|
||||
item: Pick<MethodFollowup, "intent" | "ask_theme" | "source" | "probe_year" | "year_label">,
|
||||
evidence: readonly MethodFollowupEvidence[] = [],
|
||||
): boolean {
|
||||
if (item.intent === "out_of_sample_check" || item.source === "oos_blind") return true;
|
||||
if (item.intent === "out_of_sample_check" || item.source === "oos_blind") {
|
||||
return (item.probe_year ?? 0) > 0;
|
||||
}
|
||||
if (item.intent === "reverse_verify" || item.source === "reverse_verify") return true;
|
||||
if (item.intent === "clarify_event") return true;
|
||||
if (item.source === "event_probe") return true;
|
||||
@@ -1377,7 +1387,7 @@ export function buildMethodFollowupPlan(input: {
|
||||
);
|
||||
return {
|
||||
methods,
|
||||
next_followup: fields ? makeFollowup(fields, false, true) : null,
|
||||
next_followup: fields ? makeFollowup(fields, false) : null,
|
||||
deferred_followup: null,
|
||||
session_outcome: sessionOutcome ?? "collect_evidence",
|
||||
stop_domain_rotation: true,
|
||||
@@ -1816,7 +1826,7 @@ export function buildMethodFollowupPlan(input: {
|
||||
input.oosBlindPrompts?.[0],
|
||||
(input.holdoutEvents ?? []).find((item) => item.year !== null) ?? null,
|
||||
);
|
||||
if (fields) next = makeFollowup(fields, false, true);
|
||||
if (fields) next = makeFollowup(fields, false);
|
||||
} else if (horaryStatus === "uncovered") {
|
||||
next = sameDomainYearlessCard("horary") ?? makeFollowup({
|
||||
method_id: "horary",
|
||||
|
||||
@@ -32,7 +32,8 @@ export type ProbeRejectReason =
|
||||
| StyleOptionsRejectReason
|
||||
| "zero_gain"
|
||||
| "insufficient_candidates"
|
||||
| "insufficient_outcomes";
|
||||
| "insufficient_outcomes"
|
||||
| "yearless_ungrounded_contrast";
|
||||
|
||||
export type StyleOptionsResult =
|
||||
| { ok: true; options: ProbeStyleOption[] }
|
||||
@@ -78,8 +79,11 @@ export const VARGA_UNSURE_STYLE_OPTION: ProbeStyleOption = {
|
||||
};
|
||||
|
||||
export const FORBIDDEN_COPY_TOKENS = ["外貌", "体质", "胎记", "疤痕", "伤疤", "身高", "体型"] as const;
|
||||
export const YEARLESS_PERIOD_COPY_MARKERS = ["时间吻合", "这段"] as const;
|
||||
export const LABEL_MIN = 4;
|
||||
export const LABEL_MAX = 80;
|
||||
const PLACEHOLDER_PERIOD_LABEL = /^(当前这几个候选|那段时间)$/;
|
||||
const CONCRETE_YEAR_IN_LABEL = /(?:19|20)\d{2}/;
|
||||
|
||||
const FORBIDDEN_COPY = /外貌|体质|胎记|疤痕|伤疤|身高|体型|(?:[01]?\d|2[0-3]):[0-5]\d/;
|
||||
|
||||
@@ -220,12 +224,51 @@ export function isRenderableStyleOptions(options: readonly ProbeStyleOption[] |
|
||||
&& options.every((item) => !/·(?:yes|weak_yes|no|unsure)$/.test(item.label));
|
||||
}
|
||||
|
||||
export function probeHasConcretePeriod(input: {
|
||||
year?: number | null;
|
||||
yearLabel?: string | null;
|
||||
}): boolean {
|
||||
if ((input.year ?? 0) <= 0) return false;
|
||||
const label = (input.yearLabel ?? "").trim();
|
||||
if (!label) return true;
|
||||
if (PLACEHOLDER_PERIOD_LABEL.test(label)) return false;
|
||||
return CONCRETE_YEAR_IN_LABEL.test(label);
|
||||
}
|
||||
|
||||
export function scoringOptionsHaveSigns(options: readonly ProbeStyleOption[]): boolean {
|
||||
const yes = options.find((item) => item.answer_class === "yes");
|
||||
const weakYes = options.find((item) => item.answer_class === "weak_yes");
|
||||
if (!yes?.sign?.trim() || !weakYes?.sign?.trim()) return false;
|
||||
const none = options.find((item) => item.answer_class === "no");
|
||||
if (!none) return false;
|
||||
if (none.sign?.trim()) return true;
|
||||
return none.label === VARGA_NONE_STYLE_OPTION.label;
|
||||
}
|
||||
|
||||
export function optionCopyPresupposesPeriod(options: readonly ProbeStyleOption[]): boolean {
|
||||
return options.some((item) => (
|
||||
YEARLESS_PERIOD_COPY_MARKERS.some((marker) => item.label.includes(marker))
|
||||
));
|
||||
}
|
||||
|
||||
export function canRenderYearlessChoice(input: {
|
||||
choiceKind?: string | null;
|
||||
styleOptions: readonly ProbeStyleOption[];
|
||||
}): boolean {
|
||||
if (probeQuestionKind(input.choiceKind) !== "varga_style") return false;
|
||||
if (!scoringOptionsHaveSigns(input.styleOptions)) return false;
|
||||
return !optionCopyPresupposesPeriod(input.styleOptions);
|
||||
}
|
||||
|
||||
export function isRenderableProbe(input: {
|
||||
informationGain?: number | null;
|
||||
candidateIds?: readonly string[] | null;
|
||||
expectedOutcomeCount?: number | null;
|
||||
choiceKind?: string | null;
|
||||
styleOptions?: readonly unknown[] | null;
|
||||
year?: number | null;
|
||||
yearLabel?: string | null;
|
||||
hasConcretePeriod?: boolean;
|
||||
}): ProbeRenderResult {
|
||||
const gain = typeof input.informationGain === "number" && Number.isFinite(input.informationGain)
|
||||
? input.informationGain
|
||||
@@ -238,6 +281,19 @@ export function isRenderableProbe(input: {
|
||||
styleOptions: input.styleOptions,
|
||||
});
|
||||
if (!styles.ok) return { ok: false, reason: styles.reason };
|
||||
const kind = probeQuestionKind(input.choiceKind);
|
||||
const concrete = kind === "varga_style"
|
||||
? false
|
||||
: input.hasConcretePeriod ?? probeHasConcretePeriod({
|
||||
year: input.year,
|
||||
yearLabel: input.yearLabel,
|
||||
});
|
||||
if (!concrete && !canRenderYearlessChoice({
|
||||
choiceKind: input.choiceKind,
|
||||
styleOptions: styles.options,
|
||||
})) {
|
||||
return { ok: false, reason: "yearless_ungrounded_contrast" };
|
||||
}
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user