fix(rectification): rewrite D9/D10 style options and stem spacing
Choice cards were showing type-table tokens as options, dating long-term style questions, and stacking the stem on the first option because legend is outside the fieldset grid. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -54,9 +54,13 @@
|
||||
}
|
||||
],
|
||||
"varga_none_style_option": {
|
||||
"label": "都不是这些特质",
|
||||
"label": "都不太像我",
|
||||
"answer_class": "no"
|
||||
},
|
||||
"varga_unsure_style_option": {
|
||||
"label": "一时说不好",
|
||||
"answer_class": "unsure"
|
||||
},
|
||||
"unsure_style_option": {
|
||||
"label": "这段记不清楚",
|
||||
"answer_class": "unsure"
|
||||
|
||||
@@ -6783,3 +6783,19 @@
|
||||
- 复发自:BUG-440(覆盖未齐时的收口分支存在,但 occupation 记账域错误导致永远走不到;无年份卡仍被同一覆盖门锁死)
|
||||
- 修复版本:待发布
|
||||
|
||||
## BUG-443 | D9/D10 风格卡用了类型表原文、题干贴了年份、题干贴着选项
|
||||
|
||||
- 状态:resolved
|
||||
- 首次发现:2026-08-30
|
||||
- 最近更新:2026-08-30
|
||||
- 影响面:`varga-type-tables` 的 `d9StyleLabel` / `d10StyleLabel`、`completeStyleOptions` 风格题固定项、`choice-card` 题干、`birth-time-choice.css` legend、`.rectification-choice-why`
|
||||
- 用户现象:D9/D10 风格点选卡选项是「和谐、美感、合作」「照顾、情感」这类类型表词条,三个抽象名词并列、维度不统一,无法对号入座。题干出现「2024–2026 年这段里,做事风格更接近其中一种?」;风格题没有「这段」可指。题干与第一个选项几乎没有间隔。
|
||||
- 触发条件:候选在 D9 或 D10 上升上分开,出 `choice_kind=varga_style` 点选卡。
|
||||
- 根因:三段同时成立。(1) `d9StyleLabel` / `d10StyleLabel` 直接输出 `D9_TYPE_TABLE[sign].trait` / `D10_TYPE_TABLE[sign].style`,解读用的占星类型表字段被当成用户选项。(2) `choice-card.ts` 的 `periodFor` 对 `varga_style` 走 `lifePeriodLabel(evidence, domain)`,`eventQuestionPrompt` 再把时间段贴到长期风格题干上;风格描述的是平时怎么做 / 怎么相处,不随年份变化。(3) `.birth-time-choice-question` 用 grid `gap` 分隔子项,但题干是 `<legend>`,legend 不参与 fieldset 的 grid 布局,gap 对题干与选项不生效。
|
||||
- 修复:类型表为 D9/D10 每行新增面向用户的 `userChoice`,不改 `trait` / `occupation` / `style` / `spouse` / `marriage`。标签函数改输出 `userChoice`;`answer_class` 与 sign 的映射不变。风格题 `no` 改为「都不太像我」,unsure 单独为「一时说不好」;existence / event_quality 固定选项文案不变。`varga_style` 不再返回时间段,题干写成长期表述。legend 与 `.rectification-choice-why` 用 `--space-3` 下外边距,不把 legend 改成 `p`、不新增视觉容器。Skill 保持 10.0.13。未改计分、探针身份或 hash。
|
||||
- 验证:`frontend/tests/rectification-varga-style-copy.test.ts` 锁:12×2 `userChoice` 非空且不等于 `trait`/`style`;sign → `answer_class` 仍按组序;风格卡题干无年份/「这段」;existence / event_quality 仍锁年份且固定选项不变;四选项 `isRenderableStyleOptions`;legend / why 源码具有非零下边距。修复前:标签等于类型表原文、题干带 `lifePeriodLabel` 年份、「这段记不清楚」用在风格题、legend 仅 `margin-bottom: var(--space-1)`。合同金标 `contracts/probe-question-v1.json` 同步。
|
||||
- 防复发:面向用户的选项文案不得直接复用占星类型表字段。长期风格题不得锁定时间段。卡片内题干与选项必须有独立于 grid gap 的间距。existence / event_quality 的年份月份锁定(BUG-408、BUG-412)不得被风格题改动带回。
|
||||
- 相关记录:BUG-408、BUG-412
|
||||
- 复发自:无
|
||||
- 修复版本:待发布
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
.birth-time-question-progress b { color: var(--color-ink); font-weight: 600; }
|
||||
.birth-time-choice-surface { min-width: 0; display: grid; gap: var(--space-4); }
|
||||
.birth-time-choice-question { min-width: 0; display: grid; gap: var(--space-3); margin: 0; padding: 0; border: 0; }
|
||||
.birth-time-choice-question legend { width: 100%; margin: 0 0 var(--space-1); color: var(--color-ink); font-family: var(--font-display); font-size: var(--type-title-md); font-weight: 400; line-height: 1.55; text-wrap: pretty; word-break: auto-phrase; }
|
||||
.birth-time-choice-question legend { width: 100%; margin: 0 0 var(--space-3); color: var(--color-ink); font-family: var(--font-display); font-size: var(--type-title-md); font-weight: 400; line-height: 1.55; text-wrap: pretty; word-break: auto-phrase; }
|
||||
.birth-time-primary-choices { display: grid; gap: var(--space-2); }
|
||||
.birth-time-special-choices, .birth-time-reframe-actions, .birth-time-journey-controls { display: flex; flex-wrap: wrap; gap: var(--space-2); }
|
||||
.birth-time-choice-option { min-height: 52px; border: 1px solid var(--color-border); border-radius: var(--radius-md); background: var(--color-canvas); color: var(--color-ink); cursor: pointer; font-size: var(--type-body-sm); line-height: 1.5; text-align: left; text-wrap: pretty; word-break: auto-phrase; transition: border-color 120ms ease-out, background-color 120ms ease-out, transform 120ms ease-out; }
|
||||
|
||||
@@ -2897,7 +2897,7 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
|
||||
margin-inline-start: var(--assistant-content-inset);
|
||||
}
|
||||
.rectification-choice-why {
|
||||
margin: 0;
|
||||
margin: 0 0 var(--space-3);
|
||||
color: var(--color-ink-secondary);
|
||||
font-size: var(--type-caption);
|
||||
line-height: 1.5;
|
||||
|
||||
@@ -881,8 +881,8 @@ function remainingDomain(layer: string): string {
|
||||
}
|
||||
|
||||
function remainingQuestion(layer: string): string {
|
||||
if (layer === "d10") return "平时做事更接近下面哪一种职责风格?";
|
||||
if (layer === "d9") return "亲密关系里更接近下面哪一种相处方式?";
|
||||
if (layer === "d10") return "平时做事,你更接近下面哪一种?";
|
||||
if (layer === "d9") return "亲密关系里,你更接近哪一种相处方式?";
|
||||
if (layer === "d24" || layer === "d5") return "有没有学业或考试发挥明显失常、压力特别大的时候?";
|
||||
if (layer === "d4") return "有没有搬家或长期住到外地?";
|
||||
if (layer === "d7" || layer === "d12") return "家里有没有结婚、添丁或住院这类事?";
|
||||
|
||||
@@ -245,17 +245,17 @@ function pickProbe(
|
||||
}
|
||||
|
||||
function periodFor(
|
||||
evidence: readonly ChoiceCardEvidence[] | undefined,
|
||||
_evidence: readonly ChoiceCardEvidence[] | undefined,
|
||||
domain: string | null,
|
||||
probes: readonly DiscriminatingEventProbe[] | undefined,
|
||||
_birthDate?: string | null,
|
||||
followup?: ChoiceCardFollowup,
|
||||
): string {
|
||||
const probe = pickProbe(probes, domain, followup);
|
||||
const kind = followup?.choice_kind ?? probe?.choice_kind ?? "existence";
|
||||
if (kind === "varga_style") return "";
|
||||
const fromProbe = concreteProbePeriod(probe);
|
||||
if (fromProbe) return fromProbe;
|
||||
const kind = followup?.choice_kind ?? probe?.choice_kind ?? "existence";
|
||||
if (kind === "varga_style") return lifePeriodLabel(evidence ?? [], domain);
|
||||
return "那段时间";
|
||||
}
|
||||
|
||||
@@ -274,17 +274,20 @@ function eventQuestionPrompt(
|
||||
period: string,
|
||||
family: string,
|
||||
kind: EventProbeChoiceKind,
|
||||
domain?: string | null,
|
||||
): string {
|
||||
const time = period.trim();
|
||||
const topic = family.replace(/[??。]+$/g, "").trim();
|
||||
if (kind === "varga_style") {
|
||||
return domain === "relationship"
|
||||
? "亲密关系里,你更接近哪一种相处方式?"
|
||||
: "平时做事,你更接近下面哪一种?";
|
||||
}
|
||||
if (!topic) return time;
|
||||
const dated = isConcreteChoicePeriod(period);
|
||||
if (kind === "event_quality") {
|
||||
return dated ? `${time},有没有${topic}的时候?` : `有没有${topic}的时候?`;
|
||||
}
|
||||
if (kind === "varga_style") {
|
||||
return dated ? `${time},${topic}?` : `${topic}?`;
|
||||
}
|
||||
return dated ? `${time},有没有${topic}?` : `有没有${topic}?`;
|
||||
}
|
||||
|
||||
@@ -336,7 +339,7 @@ function hypothesisFor(
|
||||
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;
|
||||
const prompt = eventQuestionPrompt(period, probe.event_family, kind);
|
||||
const prompt = eventQuestionPrompt(period, probe.event_family, kind, domain);
|
||||
const why = probe.user_meaning?.trim() || followup.user_prompt_hint.trim();
|
||||
if (!why) return null;
|
||||
return withStyleOptionLabels(prompt, why, null, styleOptions.options);
|
||||
|
||||
@@ -63,7 +63,7 @@ export const QUALITY_STYLE_OPTIONS: readonly ProbeStyleOption[] = [
|
||||
];
|
||||
|
||||
export const VARGA_NONE_STYLE_OPTION: ProbeStyleOption = {
|
||||
label: "都不是这些特质",
|
||||
label: "都不太像我",
|
||||
answer_class: "no",
|
||||
};
|
||||
|
||||
@@ -72,6 +72,11 @@ export const UNSURE_STYLE_OPTION: ProbeStyleOption = {
|
||||
answer_class: "unsure",
|
||||
};
|
||||
|
||||
export const VARGA_UNSURE_STYLE_OPTION: ProbeStyleOption = {
|
||||
label: "一时说不好",
|
||||
answer_class: "unsure",
|
||||
};
|
||||
|
||||
export const FORBIDDEN_COPY_TOKENS = ["外貌", "体质", "胎记", "疤痕", "伤疤", "身高", "体型"] as const;
|
||||
export const LABEL_MIN = 4;
|
||||
export const LABEL_MAX = 80;
|
||||
@@ -105,6 +110,7 @@ export function probeQuestionContractPayload(): Readonly<{
|
||||
existence_style_options: typeof EXISTENCE_STYLE_OPTIONS;
|
||||
quality_style_options: typeof QUALITY_STYLE_OPTIONS;
|
||||
varga_none_style_option: typeof VARGA_NONE_STYLE_OPTION;
|
||||
varga_unsure_style_option: typeof VARGA_UNSURE_STYLE_OPTION;
|
||||
unsure_style_option: typeof UNSURE_STYLE_OPTION;
|
||||
}> {
|
||||
return {
|
||||
@@ -116,6 +122,7 @@ export function probeQuestionContractPayload(): Readonly<{
|
||||
existence_style_options: EXISTENCE_STYLE_OPTIONS,
|
||||
quality_style_options: QUALITY_STYLE_OPTIONS,
|
||||
varga_none_style_option: VARGA_NONE_STYLE_OPTION,
|
||||
varga_unsure_style_option: VARGA_UNSURE_STYLE_OPTION,
|
||||
unsure_style_option: UNSURE_STYLE_OPTION,
|
||||
};
|
||||
}
|
||||
@@ -186,7 +193,7 @@ export function completeStyleOptions(input: {
|
||||
const byClass = new Map<AnswerClass, ProbeStyleOption>();
|
||||
if (kind === "varga_style") {
|
||||
for (const option of incoming) byClass.set(option.answer_class, option);
|
||||
if (!byClass.has("unsure")) byClass.set("unsure", UNSURE_STYLE_OPTION);
|
||||
if (!byClass.has("unsure")) byClass.set("unsure", VARGA_UNSURE_STYLE_OPTION);
|
||||
const scoring = ANSWER_CLASSES.filter((item) => item !== "unsure" && byClass.has(item));
|
||||
if (scoring.length < 2) {
|
||||
return { ok: false, reason: incomingReason ?? "varga_insufficient_scoring" };
|
||||
|
||||
@@ -1,38 +1,171 @@
|
||||
/**
|
||||
* D9/D10 type tables for rectification contrast, not fate promises.
|
||||
*
|
||||
* `userChoice` is the only field shown on choice cards. trait / spouse /
|
||||
* marriage / occupation / style stay on the interpretation path.
|
||||
*/
|
||||
|
||||
export type D9TypeRow = Readonly<{ trait: string; spouse: string; marriage: string }>;
|
||||
export type D10TypeRow = Readonly<{ trait: string; occupation: string; style: string }>;
|
||||
export type D9TypeRow = Readonly<{
|
||||
trait: string;
|
||||
spouse: string;
|
||||
marriage: string;
|
||||
userChoice: string;
|
||||
}>;
|
||||
export type D10TypeRow = Readonly<{
|
||||
trait: string;
|
||||
occupation: string;
|
||||
style: string;
|
||||
userChoice: string;
|
||||
}>;
|
||||
|
||||
export const D9_TYPE_TABLE: Readonly<Record<string, D9TypeRow>> = {
|
||||
白羊座: { trait: "主动、热情、冲动", spouse: "独立、有活力", marriage: "早期婚姻、激情型" },
|
||||
金牛座: { trait: "稳定、务实、占有欲强", spouse: "稳重、有经济基础", marriage: "晚婚、稳定型" },
|
||||
双子座: { trait: "沟通、多变、好奇心强", spouse: "聪明、善交流", marriage: "多次恋爱、友谊型" },
|
||||
巨蟹座: { trait: "情感丰富、家庭导向", spouse: "温柔、顾家", marriage: "家庭型" },
|
||||
狮子座: { trait: "骄傲、戏剧性、领导欲", spouse: "有魅力、有地位", marriage: "戏剧性" },
|
||||
处女座: { trait: "完美主义、挑剔、服务型", spouse: "细致、有技能", marriage: "晚婚、服务型" },
|
||||
天秤座: { trait: "和谐、美感、合作", spouse: "优雅、有艺术气质", marriage: "美满、合作型" },
|
||||
天蝎座: { trait: "深刻、占有欲、转化", spouse: "神秘、有深度", marriage: "深刻、转化型" },
|
||||
射手座: { trait: "自由、哲学、冒险", spouse: "开放、有学识", marriage: "自由型、精神伴侣" },
|
||||
摩羯座: { trait: "务实、责任、延迟", spouse: "成熟、有事业", marriage: "晚婚、责任型" },
|
||||
水瓶座: { trait: "独立、非传统、友谊", spouse: "独特、有理想", marriage: "非传统、友谊型" },
|
||||
双鱼座: { trait: "浪漫、牺牲、灵性", spouse: "灵性、有艺术天赋", marriage: "灵性、牺牲型" },
|
||||
白羊座: {
|
||||
trait: "主动、热情、冲动",
|
||||
spouse: "独立、有活力",
|
||||
marriage: "早期婚姻、激情型",
|
||||
userChoice: "相处里爱先开口推进,来得快也容易急",
|
||||
},
|
||||
金牛座: {
|
||||
trait: "稳定、务实、占有欲强",
|
||||
spouse: "稳重、有经济基础",
|
||||
marriage: "晚婚、稳定型",
|
||||
userChoice: "把日子过稳当,也在意关系里的安全感",
|
||||
},
|
||||
双子座: {
|
||||
trait: "沟通、多变、好奇心强",
|
||||
spouse: "聪明、善交流",
|
||||
marriage: "多次恋爱、友谊型",
|
||||
userChoice: "爱聊、爱换话题,新鲜感一过就容易飘",
|
||||
},
|
||||
巨蟹座: {
|
||||
trait: "情感丰富、家庭导向",
|
||||
spouse: "温柔、顾家",
|
||||
marriage: "家庭型",
|
||||
userChoice: "把对方当家人养,情绪来了也藏不住",
|
||||
},
|
||||
狮子座: {
|
||||
trait: "骄傲、戏剧性、领导欲",
|
||||
spouse: "有魅力、有地位",
|
||||
marriage: "戏剧性",
|
||||
userChoice: "相处里要被看见,也爱把气氛带起来",
|
||||
},
|
||||
处女座: {
|
||||
trait: "完美主义、挑剔、服务型",
|
||||
spouse: "细致、有技能",
|
||||
marriage: "晚婚、服务型",
|
||||
userChoice: "对细节很较真,也习惯把对方的事揽下来",
|
||||
},
|
||||
天秤座: {
|
||||
trait: "和谐、美感、合作",
|
||||
spouse: "优雅、有艺术气质",
|
||||
marriage: "美满、合作型",
|
||||
userChoice: "尽量避免冲突,凡事想商量着来",
|
||||
},
|
||||
天蝎座: {
|
||||
trait: "深刻、占有欲、转化",
|
||||
spouse: "神秘、有深度",
|
||||
marriage: "深刻、转化型",
|
||||
userChoice: "投入很深、在意独占,也容易大起大落",
|
||||
},
|
||||
射手座: {
|
||||
trait: "自由、哲学、冒险",
|
||||
spouse: "开放、有学识",
|
||||
marriage: "自由型、精神伴侣",
|
||||
userChoice: "看重各自的空间,不喜欢被绑太紧",
|
||||
},
|
||||
摩羯座: {
|
||||
trait: "务实、责任、延迟",
|
||||
spouse: "成熟、有事业",
|
||||
marriage: "晚婚、责任型",
|
||||
userChoice: "把责任看得很重,进展也愿意慢慢来",
|
||||
},
|
||||
水瓶座: {
|
||||
trait: "独立、非传统、友谊",
|
||||
spouse: "独特、有理想",
|
||||
marriage: "非传统、友谊型",
|
||||
userChoice: "更像朋友那样处,各自留足独立空间",
|
||||
},
|
||||
双鱼座: {
|
||||
trait: "浪漫、牺牲、灵性",
|
||||
spouse: "灵性、有艺术天赋",
|
||||
marriage: "灵性、牺牲型",
|
||||
userChoice: "容易把感情理想化,也愿意为对方让步",
|
||||
},
|
||||
};
|
||||
|
||||
export const D10_TYPE_TABLE: Readonly<Record<string, D10TypeRow>> = {
|
||||
白羊座: { trait: "领导、创业、竞争", occupation: "创业者、运动员、军人", style: "主动、竞争" },
|
||||
金牛座: { trait: "稳定、财富、艺术", occupation: "金融、艺术、农业", style: "稳定、务实" },
|
||||
双子座: { trait: "沟通、写作、教育", occupation: "教师、作家、销售", style: "多变、沟通" },
|
||||
巨蟹座: { trait: "照顾、家庭、情感", occupation: "护理、餐饮、房地产", style: "照顾、情感" },
|
||||
狮子座: { trait: "领导、表演、创意", occupation: "管理、娱乐、政治", style: "领导、表演" },
|
||||
处女座: { trait: "服务、分析、健康", occupation: "医疗、分析、服务", style: "细致、服务" },
|
||||
天秤座: { trait: "合作、美学、法律", occupation: "法律、艺术、咨询", style: "合作、和谐" },
|
||||
天蝎座: { trait: "研究、转化、危机", occupation: "研究、心理学、危机管理", style: "深度、转化" },
|
||||
射手座: { trait: "教育、哲学、国际", occupation: "教育、出版、国际事务", style: "自由、哲学" },
|
||||
摩羯座: { trait: "管理、责任、延迟", occupation: "管理、政府、建筑", style: "务实、责任" },
|
||||
水瓶座: { trait: "创新、科技、人道", occupation: "科技、人道主义、创新", style: "创新、独立" },
|
||||
双鱼座: { trait: "灵性、艺术、服务", occupation: "艺术、灵性、医疗", style: "灵性、服务" },
|
||||
白羊座: {
|
||||
trait: "领导、创业、竞争",
|
||||
occupation: "创业者、运动员、军人",
|
||||
style: "主动、竞争",
|
||||
userChoice: "做事爱抢先上手,也爱跟别人比一把",
|
||||
},
|
||||
金牛座: {
|
||||
trait: "稳定、财富、艺术",
|
||||
occupation: "金融、艺术、农业",
|
||||
style: "稳定、务实",
|
||||
userChoice: "做事求稳、把基础打牢,不爱来回变",
|
||||
},
|
||||
双子座: {
|
||||
trait: "沟通、写作、教育",
|
||||
occupation: "教师、作家、销售",
|
||||
style: "多变、沟通",
|
||||
userChoice: "靠说话和换思路推进,一件事待不久",
|
||||
},
|
||||
巨蟹座: {
|
||||
trait: "照顾、家庭、情感",
|
||||
occupation: "护理、餐饮、房地产",
|
||||
style: "照顾、情感",
|
||||
userChoice: "做事以照顾人为主,在意团队里的感受",
|
||||
},
|
||||
狮子座: {
|
||||
trait: "领导、表演、创意",
|
||||
occupation: "管理、娱乐、政治",
|
||||
style: "领导、表演",
|
||||
userChoice: "习惯带头,也不排斥站到台前",
|
||||
},
|
||||
处女座: {
|
||||
trait: "服务、分析、健康",
|
||||
occupation: "医疗、分析、服务",
|
||||
style: "细致、服务",
|
||||
userChoice: "盯细节、把事做扎实,偏后端支持",
|
||||
},
|
||||
天秤座: {
|
||||
trait: "合作、美学、法律",
|
||||
occupation: "法律、艺术、咨询",
|
||||
style: "合作、和谐",
|
||||
userChoice: "推进事情时爱找人配合,尽量不得罪人",
|
||||
},
|
||||
天蝎座: {
|
||||
trait: "研究、转化、危机",
|
||||
occupation: "研究、心理学、危机管理",
|
||||
style: "深度、转化",
|
||||
userChoice: "爱把问题挖到底,也扛得住推倒重来",
|
||||
},
|
||||
射手座: {
|
||||
trait: "教育、哲学、国际",
|
||||
occupation: "教育、出版、国际事务",
|
||||
style: "自由、哲学",
|
||||
userChoice: "不爱被流程绑死,更想把事情做开去",
|
||||
},
|
||||
摩羯座: {
|
||||
trait: "管理、责任、延迟",
|
||||
occupation: "管理、政府、建筑",
|
||||
style: "务实、责任",
|
||||
userChoice: "把职责扛到底,进度宁可慢也要稳",
|
||||
},
|
||||
水瓶座: {
|
||||
trait: "创新、科技、人道",
|
||||
occupation: "科技、人道主义、创新",
|
||||
style: "创新、独立",
|
||||
userChoice: "爱走自己的路,也爱试还没人做过的办法",
|
||||
},
|
||||
双鱼座: {
|
||||
trait: "灵性、艺术、服务",
|
||||
occupation: "艺术、灵性、医疗",
|
||||
style: "灵性、服务",
|
||||
userChoice: "凭感觉做事,也常把别人的需要放前面",
|
||||
},
|
||||
};
|
||||
|
||||
export function signKey(value: string): string {
|
||||
@@ -43,10 +176,10 @@ export function signKey(value: string): string {
|
||||
|
||||
export function d9StyleLabel(sign: string): string {
|
||||
const row = D9_TYPE_TABLE[signKey(sign)];
|
||||
return row?.trait ?? `${signKey(sign)}相处`;
|
||||
return row?.userChoice ?? `${signKey(sign)}相处`;
|
||||
}
|
||||
|
||||
export function d10StyleLabel(sign: string): string {
|
||||
const row = D10_TYPE_TABLE[signKey(sign)];
|
||||
return row?.style ?? `${signKey(sign)}职责`;
|
||||
return row?.userChoice ?? `${signKey(sign)}职责`;
|
||||
}
|
||||
|
||||
@@ -45,8 +45,8 @@ test("varga-style probes stay dynamic and fail closed without two scoring labels
|
||||
});
|
||||
assert.equal(completed.ok, true);
|
||||
assert.equal(completed.ok ? completed.options.length : 0, 4);
|
||||
assert.equal(completed.ok ? completed.options.find((item) => item.answer_class === "no")?.label : null, "都不是这些特质");
|
||||
assert.equal(completed.ok ? completed.options.find((item) => item.answer_class === "unsure")?.label : null, "这段记不清楚");
|
||||
assert.equal(completed.ok ? completed.options.find((item) => item.answer_class === "no")?.label : null, "都不太像我");
|
||||
assert.equal(completed.ok ? completed.options.find((item) => item.answer_class === "unsure")?.label : null, "一时说不好");
|
||||
});
|
||||
|
||||
test("illegal clock or appearance copy cannot become a renderable probe", () => {
|
||||
|
||||
@@ -0,0 +1,350 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { readFileSync } from "node:fs";
|
||||
import test from "node:test";
|
||||
|
||||
import { buildCandidateContrastPacket, selectDiscriminatorProbe } from "../src/lib/rectification-agentic/core/candidate-contrast-packet.ts";
|
||||
import { buildChoiceFrame, serverOwnedChoiceCopy } from "../src/lib/rectification-agentic/v9/choice-card.ts";
|
||||
import {
|
||||
EXISTENCE_STYLE_OPTIONS,
|
||||
LABEL_MAX,
|
||||
LABEL_MIN,
|
||||
QUALITY_STYLE_OPTIONS,
|
||||
completeStyleOptions,
|
||||
isRenderableStyleOptions,
|
||||
} from "../src/lib/rectification-agentic/v9/probe-question-contract.ts";
|
||||
import type { DiscriminatingEventProbe } from "../src/lib/rectification-agentic/v9/refinement-packet.ts";
|
||||
import {
|
||||
D9_TYPE_TABLE,
|
||||
D10_TYPE_TABLE,
|
||||
d9StyleLabel,
|
||||
d10StyleLabel,
|
||||
} from "../src/lib/rectification-agentic/v9/varga-type-tables.ts";
|
||||
|
||||
const SIGNS = [
|
||||
"白羊座", "金牛座", "双子座", "巨蟹座", "狮子座", "处女座",
|
||||
"天秤座", "天蝎座", "射手座", "摩羯座", "水瓶座", "双鱼座",
|
||||
] as const;
|
||||
|
||||
const FROZEN_D9 = {
|
||||
白羊座: { trait: "主动、热情、冲动", spouse: "独立、有活力", marriage: "早期婚姻、激情型" },
|
||||
金牛座: { trait: "稳定、务实、占有欲强", spouse: "稳重、有经济基础", marriage: "晚婚、稳定型" },
|
||||
双子座: { trait: "沟通、多变、好奇心强", spouse: "聪明、善交流", marriage: "多次恋爱、友谊型" },
|
||||
巨蟹座: { trait: "情感丰富、家庭导向", spouse: "温柔、顾家", marriage: "家庭型" },
|
||||
狮子座: { trait: "骄傲、戏剧性、领导欲", spouse: "有魅力、有地位", marriage: "戏剧性" },
|
||||
处女座: { trait: "完美主义、挑剔、服务型", spouse: "细致、有技能", marriage: "晚婚、服务型" },
|
||||
天秤座: { trait: "和谐、美感、合作", spouse: "优雅、有艺术气质", marriage: "美满、合作型" },
|
||||
天蝎座: { trait: "深刻、占有欲、转化", spouse: "神秘、有深度", marriage: "深刻、转化型" },
|
||||
射手座: { trait: "自由、哲学、冒险", spouse: "开放、有学识", marriage: "自由型、精神伴侣" },
|
||||
摩羯座: { trait: "务实、责任、延迟", spouse: "成熟、有事业", marriage: "晚婚、责任型" },
|
||||
水瓶座: { trait: "独立、非传统、友谊", spouse: "独特、有理想", marriage: "非传统、友谊型" },
|
||||
双鱼座: { trait: "浪漫、牺牲、灵性", spouse: "灵性、有艺术天赋", marriage: "灵性、牺牲型" },
|
||||
} as const;
|
||||
|
||||
const FROZEN_D10 = {
|
||||
白羊座: { trait: "领导、创业、竞争", occupation: "创业者、运动员、军人", style: "主动、竞争" },
|
||||
金牛座: { trait: "稳定、财富、艺术", occupation: "金融、艺术、农业", style: "稳定、务实" },
|
||||
双子座: { trait: "沟通、写作、教育", occupation: "教师、作家、销售", style: "多变、沟通" },
|
||||
巨蟹座: { trait: "照顾、家庭、情感", occupation: "护理、餐饮、房地产", style: "照顾、情感" },
|
||||
狮子座: { trait: "领导、表演、创意", occupation: "管理、娱乐、政治", style: "领导、表演" },
|
||||
处女座: { trait: "服务、分析、健康", occupation: "医疗、分析、服务", style: "细致、服务" },
|
||||
天秤座: { trait: "合作、美学、法律", occupation: "法律、艺术、咨询", style: "合作、和谐" },
|
||||
天蝎座: { trait: "研究、转化、危机", occupation: "研究、心理学、危机管理", style: "深度、转化" },
|
||||
射手座: { trait: "教育、哲学、国际", occupation: "教育、出版、国际事务", style: "自由、哲学" },
|
||||
摩羯座: { trait: "管理、责任、延迟", occupation: "管理、政府、建筑", style: "务实、责任" },
|
||||
水瓶座: { trait: "创新、科技、人道", occupation: "科技、人道主义、创新", style: "创新、独立" },
|
||||
双鱼座: { trait: "灵性、艺术、服务", occupation: "艺术、灵性、医疗", style: "灵性、服务" },
|
||||
} as const;
|
||||
|
||||
const FROZEN_EXISTENCE = [
|
||||
{ label: "明确发生且时间吻合", answer_class: "yes" },
|
||||
{ label: "发生过但程度较弱", answer_class: "weak_yes" },
|
||||
{ label: "明确没有发生", answer_class: "no" },
|
||||
{ label: "这段记不清楚", answer_class: "unsure" },
|
||||
] as const;
|
||||
|
||||
const FROZEN_QUALITY = [
|
||||
{ label: "发挥明显失常或压力很大", answer_class: "yes" },
|
||||
{ label: "有压力但不算明显失常", answer_class: "weak_yes" },
|
||||
{ label: "发挥正常、没有明显失常", answer_class: "no" },
|
||||
{ label: "这段记不清楚", answer_class: "unsure" },
|
||||
] as const;
|
||||
|
||||
const YEAR_OR_SPAN = /\d{4}|这段/;
|
||||
|
||||
function styleCard(
|
||||
domain: "relationship" | "career",
|
||||
signs: readonly [string, string, string],
|
||||
labelFor: (sign: string) => string,
|
||||
): ReturnType<typeof buildChoiceFrame> {
|
||||
const probe: DiscriminatingEventProbe = {
|
||||
year: 2024,
|
||||
year_label: "2024–2026 年这段里",
|
||||
domain,
|
||||
event_family: domain === "relationship" ? "相处方式更接近其中一种" : "做事风格更接近其中一种",
|
||||
source: "dasha_activation",
|
||||
tracks: ["vimshottari", "narayana"],
|
||||
tracks_agree: true,
|
||||
unique_minute_claim: false,
|
||||
user_meaning: "对照类型表只作校时方法,不是命运承诺。",
|
||||
role: "distinguish",
|
||||
information_gain: 1.2,
|
||||
candidate_ids: ["05:00", "05:03", "05:04"],
|
||||
expected_outcomes: [
|
||||
{ answer_class: "yes", supports: ["05:00"], conflicts: ["05:03", "05:04"] },
|
||||
{ answer_class: "weak_yes", supports: ["05:03"], conflicts: ["05:00", "05:04"] },
|
||||
{ answer_class: "no", supports: ["05:04"], conflicts: ["05:00", "05:03"] },
|
||||
],
|
||||
choice_kind: "varga_style",
|
||||
semantic_key: domain === "relationship" ? "varga.d9.05:00|05:03/05:04" : "varga.d10.05:00|05:03/05:04",
|
||||
style_options: [
|
||||
{ sign: signs[0], label: labelFor(signs[0]), answer_class: "yes" },
|
||||
{ sign: signs[1], label: labelFor(signs[1]), answer_class: "weak_yes" },
|
||||
{ sign: signs[2], label: labelFor(signs[2]), answer_class: "no" },
|
||||
],
|
||||
};
|
||||
return buildChoiceFrame({
|
||||
method_id: domain === "relationship" ? "d9_refine" : "d10_career",
|
||||
ask_theme: domain === "relationship" ? "relationship_style" : "career_style",
|
||||
domain,
|
||||
user_prompt_hint: "unused",
|
||||
choice_kind: "varga_style",
|
||||
semantic_key: probe.semantic_key,
|
||||
style_options: probe.style_options,
|
||||
}, {
|
||||
evidence: [
|
||||
{ status: "confirmed", domain, datePrecision: "year", occurredFrom: "2024-01-01", occurredTo: null },
|
||||
{ status: "confirmed", domain, datePrecision: "year", occurredFrom: "2026-01-01", occurredTo: null },
|
||||
],
|
||||
probes: [probe],
|
||||
});
|
||||
}
|
||||
|
||||
test("D9/D10 interpretation fields stay frozen; userChoice is the card label", () => {
|
||||
assert.deepEqual(Object.keys(D9_TYPE_TABLE), [...SIGNS]);
|
||||
assert.deepEqual(Object.keys(D10_TYPE_TABLE), [...SIGNS]);
|
||||
for (const sign of SIGNS) {
|
||||
const d9 = D9_TYPE_TABLE[sign];
|
||||
const d10 = D10_TYPE_TABLE[sign];
|
||||
assert.ok(d9);
|
||||
assert.ok(d10);
|
||||
assert.deepEqual({ trait: d9.trait, spouse: d9.spouse, marriage: d9.marriage }, FROZEN_D9[sign]);
|
||||
assert.deepEqual(
|
||||
{ trait: d10.trait, occupation: d10.occupation, style: d10.style },
|
||||
FROZEN_D10[sign],
|
||||
);
|
||||
assert.ok(d9.userChoice.trim().length >= LABEL_MIN && d9.userChoice.length <= LABEL_MAX);
|
||||
assert.ok(d10.userChoice.trim().length >= LABEL_MIN && d10.userChoice.length <= LABEL_MAX);
|
||||
assert.notEqual(d9.userChoice, d9.trait);
|
||||
assert.notEqual(d10.userChoice, d10.style);
|
||||
assert.notEqual(d10.userChoice, d10.trait);
|
||||
assert.equal(d9StyleLabel(sign), d9.userChoice);
|
||||
assert.equal(d10StyleLabel(sign), d10.userChoice);
|
||||
assert.equal(d9StyleLabel(sign.replace(/座$/, "")), d9.userChoice);
|
||||
assert.equal(d10StyleLabel(sign.replace(/座$/, "")), d10.userChoice);
|
||||
}
|
||||
assert.equal(d9StyleLabel("天秤座"), "尽量避免冲突,凡事想商量着来");
|
||||
assert.equal(d9StyleLabel("天蝎座"), "投入很深、在意独占,也容易大起大落");
|
||||
assert.equal(d9StyleLabel("射手座"), "看重各自的空间,不喜欢被绑太紧");
|
||||
assert.equal(d10StyleLabel("巨蟹座"), "做事以照顾人为主,在意团队里的感受");
|
||||
assert.equal(d10StyleLabel("狮子座"), "习惯带头,也不排斥站到台前");
|
||||
assert.equal(d10StyleLabel("处女座"), "盯细节、把事做扎实,偏后端支持");
|
||||
});
|
||||
|
||||
test("varga_style options keep sign → answer_class mapping and are renderable", () => {
|
||||
const d9 = completeStyleOptions({
|
||||
choiceKind: "varga_style",
|
||||
styleOptions: [
|
||||
{ sign: "天秤座", label: d9StyleLabel("天秤座"), answer_class: "yes" },
|
||||
{ sign: "天蝎座", label: d9StyleLabel("天蝎座"), answer_class: "weak_yes" },
|
||||
{ sign: "射手座", label: d9StyleLabel("射手座"), answer_class: "no" },
|
||||
],
|
||||
});
|
||||
assert.equal(d9.ok, true);
|
||||
if (!d9.ok) return;
|
||||
assert.equal(isRenderableStyleOptions(d9.options), true);
|
||||
assert.equal(d9.options.find((item) => item.answer_class === "yes")?.sign, "天秤座");
|
||||
assert.equal(d9.options.find((item) => item.answer_class === "weak_yes")?.sign, "天蝎座");
|
||||
assert.equal(d9.options.find((item) => item.answer_class === "no")?.sign, "射手座");
|
||||
assert.equal(d9.options.find((item) => item.answer_class === "yes")?.label, D9_TYPE_TABLE.天秤座.userChoice);
|
||||
assert.notEqual(d9.options.find((item) => item.answer_class === "yes")?.label, D9_TYPE_TABLE.天秤座.trait);
|
||||
const no = d9.options.find((item) => item.answer_class === "no")?.label ?? "";
|
||||
const unsure = d9.options.find((item) => item.answer_class === "unsure")?.label ?? "";
|
||||
assert.doesNotMatch(no, /特质/);
|
||||
assert.doesNotMatch(unsure, /特质|这段/);
|
||||
assert.equal(unsure, "一时说不好");
|
||||
|
||||
const d10 = completeStyleOptions({
|
||||
choiceKind: "varga_style",
|
||||
styleOptions: [
|
||||
{ sign: "巨蟹座", label: d10StyleLabel("巨蟹座"), answer_class: "yes" },
|
||||
{ sign: "狮子座", label: d10StyleLabel("狮子座"), answer_class: "weak_yes" },
|
||||
{ sign: "处女座", label: d10StyleLabel("处女座"), answer_class: "no" },
|
||||
],
|
||||
});
|
||||
assert.equal(d10.ok, true);
|
||||
if (!d10.ok) return;
|
||||
assert.equal(isRenderableStyleOptions(d10.options), true);
|
||||
assert.equal(d10.options.find((item) => item.answer_class === "yes")?.sign, "巨蟹座");
|
||||
assert.equal(d10.options.find((item) => item.answer_class === "weak_yes")?.sign, "狮子座");
|
||||
assert.equal(d10.options.find((item) => item.answer_class === "no")?.sign, "处女座");
|
||||
assert.notEqual(d10.options.find((item) => item.answer_class === "yes")?.label, D10_TYPE_TABLE.巨蟹座.style);
|
||||
|
||||
const filled = completeStyleOptions({
|
||||
choiceKind: "varga_style",
|
||||
styleOptions: [
|
||||
{ sign: "天秤座", label: d9StyleLabel("天秤座"), answer_class: "yes" },
|
||||
{ sign: "天蝎座", label: d9StyleLabel("天蝎座"), answer_class: "weak_yes" },
|
||||
],
|
||||
});
|
||||
assert.equal(filled.ok, true);
|
||||
if (!filled.ok) return;
|
||||
assert.equal(filled.options.find((item) => item.answer_class === "no")?.label, "都不太像我");
|
||||
assert.equal(filled.options.find((item) => item.answer_class === "unsure")?.label, "一时说不好");
|
||||
assert.doesNotMatch(filled.options.find((item) => item.answer_class === "no")?.label ?? "", /特质/);
|
||||
assert.doesNotMatch(filled.options.find((item) => item.answer_class === "unsure")?.label ?? "", /这段/);
|
||||
});
|
||||
|
||||
test("existence and event_quality fixed options stay on the old copy", () => {
|
||||
assert.deepEqual(EXISTENCE_STYLE_OPTIONS, [...FROZEN_EXISTENCE]);
|
||||
assert.deepEqual(QUALITY_STYLE_OPTIONS, [...FROZEN_QUALITY]);
|
||||
const existence = completeStyleOptions({ choiceKind: "existence" });
|
||||
const quality = completeStyleOptions({ choiceKind: "event_quality" });
|
||||
assert.equal(existence.ok && quality.ok, true);
|
||||
if (!existence.ok || !quality.ok) return;
|
||||
assert.deepEqual(existence.options, [...FROZEN_EXISTENCE]);
|
||||
assert.deepEqual(quality.options, [...FROZEN_QUALITY]);
|
||||
assert.equal(existence.options.find((item) => item.answer_class === "unsure")?.label, "这段记不清楚");
|
||||
assert.equal(quality.options.find((item) => item.answer_class === "unsure")?.label, "这段记不清楚");
|
||||
});
|
||||
|
||||
test("varga_style stems are long-term; existence and quality still lock the year", () => {
|
||||
const relationship = styleCard("relationship", ["天秤座", "天蝎座", "射手座"], d9StyleLabel);
|
||||
const career = styleCard("career", ["巨蟹座", "狮子座", "处女座"], d10StyleLabel);
|
||||
assert.ok(relationship);
|
||||
assert.ok(career);
|
||||
const relationshipCopy = relationship ? serverOwnedChoiceCopy(relationship) : null;
|
||||
const careerCopy = career ? serverOwnedChoiceCopy(career) : null;
|
||||
assert.ok(relationshipCopy);
|
||||
assert.ok(careerCopy);
|
||||
assert.doesNotMatch(relationship!.prompt, YEAR_OR_SPAN);
|
||||
assert.doesNotMatch(career!.prompt, YEAR_OR_SPAN);
|
||||
assert.doesNotMatch(relationship!.period, YEAR_OR_SPAN);
|
||||
assert.doesNotMatch(career!.period, YEAR_OR_SPAN);
|
||||
assert.equal(relationship!.prompt, "亲密关系里,你更接近哪一种相处方式?");
|
||||
assert.equal(career!.prompt, "平时做事,你更接近下面哪一种?");
|
||||
assert.doesNotMatch(relationshipCopy!.prompt, YEAR_OR_SPAN);
|
||||
assert.doesNotMatch(careerCopy!.prompt, YEAR_OR_SPAN);
|
||||
assert.match(relationship!.why, /校时方法/);
|
||||
assert.match(career!.why, /校时方法/);
|
||||
|
||||
const existence = buildChoiceFrame({
|
||||
method_id: "d4_home",
|
||||
ask_theme: "home_change",
|
||||
domain: "relocation",
|
||||
user_prompt_hint: "unused",
|
||||
choice_kind: "existence",
|
||||
}, {
|
||||
probes: [{
|
||||
year: 2016,
|
||||
year_label: "2016 年前后",
|
||||
domain: "relocation",
|
||||
event_family: "搬家、离乡或长期异地",
|
||||
source: "dasha_activation",
|
||||
tracks: ["vimshottari", "narayana"],
|
||||
tracks_agree: true,
|
||||
unique_minute_claim: false,
|
||||
user_meaning: "年份锁定 2016 年前后。",
|
||||
role: "distinguish",
|
||||
information_gain: 0.4,
|
||||
candidate_ids: ["05:00", "05:20"],
|
||||
expected_outcomes: [
|
||||
{ answer_class: "yes", supports: ["05:00"], conflicts: ["05:20"] },
|
||||
{ answer_class: "no", supports: ["05:20"], conflicts: ["05:00"] },
|
||||
],
|
||||
}],
|
||||
});
|
||||
assert.ok(existence);
|
||||
assert.match(existence!.prompt, /2016 年前后/);
|
||||
assert.match(existence!.prompt, /搬家、离乡或长期异地/);
|
||||
assert.equal(existence!.unsure_label, "这段记不清楚");
|
||||
|
||||
const quality = buildChoiceFrame({
|
||||
method_id: "d24_learn",
|
||||
ask_theme: "education_style",
|
||||
domain: "education",
|
||||
user_prompt_hint: "unused",
|
||||
choice_kind: "event_quality",
|
||||
}, {
|
||||
probes: [{
|
||||
year: 2020,
|
||||
year_label: "2020 年前后",
|
||||
domain: "education",
|
||||
event_family: "学业或考试发挥失常、压力特别大",
|
||||
source: "known_event_quality",
|
||||
tracks: ["vimshottari", "narayana"],
|
||||
tracks_agree: true,
|
||||
unique_minute_claim: false,
|
||||
user_meaning: "年份锁定 2020 年前后。",
|
||||
role: "distinguish",
|
||||
information_gain: 0.5,
|
||||
candidate_ids: ["05:00", "05:20"],
|
||||
expected_outcomes: [
|
||||
{ answer_class: "yes", supports: ["05:00"], conflicts: ["05:20"] },
|
||||
{ answer_class: "no", supports: ["05:20"], conflicts: ["05:00"] },
|
||||
],
|
||||
choice_kind: "event_quality",
|
||||
}],
|
||||
});
|
||||
assert.ok(quality);
|
||||
assert.match(quality!.prompt, /2020 年前后/);
|
||||
assert.equal(quality!.unsure_label, "这段记不清楚");
|
||||
});
|
||||
|
||||
test("remaining D9/D10 packets use userChoice labels and long-term questions", () => {
|
||||
const d9 = selectDiscriminatorProbe(buildCandidateContrastPacket({
|
||||
candidateSetVersion: "05:00-05:04",
|
||||
candidateTimes: ["05:00", "05:03", "05:04"],
|
||||
transitions: [
|
||||
{ layer: "d9", at: "05:03", from_sign: "天秤座", to_sign: "天蝎座" },
|
||||
{ layer: "d9", at: "05:04", from_sign: "天蝎座", to_sign: "射手座" },
|
||||
],
|
||||
}));
|
||||
assert.ok(d9);
|
||||
assert.equal(d9!.choiceKind, "varga_style");
|
||||
assert.doesNotMatch(d9!.question, YEAR_OR_SPAN);
|
||||
assert.equal(d9!.question, "亲密关系里,你更接近哪一种相处方式?");
|
||||
assert.equal(d9!.styleOptions?.find((item) => item.answerClass === "yes")?.sign, "天秤座");
|
||||
assert.equal(d9!.styleOptions?.find((item) => item.answerClass === "weak_yes")?.sign, "天蝎座");
|
||||
assert.equal(d9!.styleOptions?.find((item) => item.answerClass === "no")?.sign, "射手座");
|
||||
assert.equal(d9!.styleOptions?.find((item) => item.answerClass === "yes")?.label, d9StyleLabel("天秤座"));
|
||||
assert.notEqual(d9!.styleOptions?.find((item) => item.answerClass === "yes")?.label, D9_TYPE_TABLE.天秤座.trait);
|
||||
|
||||
const d10 = selectDiscriminatorProbe(buildCandidateContrastPacket({
|
||||
candidateSetVersion: "05:00-05:04",
|
||||
candidateTimes: ["05:00", "05:03", "05:04"],
|
||||
transitions: [
|
||||
{ layer: "d10", at: "05:03", from_sign: "巨蟹座", to_sign: "狮子座" },
|
||||
{ layer: "d10", at: "05:04", from_sign: "狮子座", to_sign: "处女座" },
|
||||
],
|
||||
}));
|
||||
assert.ok(d10);
|
||||
assert.equal(d10!.choiceKind, "varga_style");
|
||||
assert.doesNotMatch(d10!.question, YEAR_OR_SPAN);
|
||||
assert.equal(d10!.question, "平时做事,你更接近下面哪一种?");
|
||||
assert.equal(d10!.styleOptions?.find((item) => item.answerClass === "yes")?.label, d10StyleLabel("巨蟹座"));
|
||||
assert.notEqual(d10!.styleOptions?.find((item) => item.answerClass === "yes")?.label, D10_TYPE_TABLE.巨蟹座.style);
|
||||
});
|
||||
|
||||
test("choice-card legend spacing does not depend on fieldset grid gap", () => {
|
||||
const choiceCss = readFileSync(new URL("../src/app/birth-time-choice.css", import.meta.url), "utf8");
|
||||
const globals = readFileSync(new URL("../src/app/globals.css", import.meta.url), "utf8");
|
||||
const card = readFileSync(new URL("../src/components/rectification-choice-card.tsx", import.meta.url), "utf8");
|
||||
const legendRule = choiceCss.match(/\.birth-time-choice-question legend \{[^}]+\}/)?.[0] ?? "";
|
||||
const whyRule = globals.match(/\.rectification-choice-why \{[^}]+\}/)?.[0] ?? "";
|
||||
assert.match(legendRule, /margin:\s*0\s+0\s+var\(--space-[3-9]\)/);
|
||||
assert.match(whyRule, /margin:\s*0\s+0\s+var\(--space-[3-9]\)/);
|
||||
assert.match(card, /<legend>\{props\.card\.prompt\}<\/legend>/);
|
||||
assert.match(card, /className="rectification-choice-why"/);
|
||||
assert.doesNotMatch(card, /choice-question-wrap|choice-stem-wrap|legend-spacer/);
|
||||
assert.match(card, /<legend>\{props\.card\.prompt\}<\/legend>\s*\{props\.card\.why \? <p className="rectification-choice-why">/);
|
||||
});
|
||||
@@ -25,8 +25,9 @@ QUALITY_STYLE_OPTIONS: tuple[dict[str, str], ...] = (
|
||||
{"label": "发挥正常、没有明显失常", "answer_class": "no"},
|
||||
{"label": "这段记不清楚", "answer_class": "unsure"},
|
||||
)
|
||||
VARGA_NONE_STYLE_OPTION = {"label": "都不是这些特质", "answer_class": "no"}
|
||||
VARGA_NONE_STYLE_OPTION = {"label": "都不太像我", "answer_class": "no"}
|
||||
UNSURE_STYLE_OPTION = {"label": "这段记不清楚", "answer_class": "unsure"}
|
||||
VARGA_UNSURE_STYLE_OPTION = {"label": "一时说不好", "answer_class": "unsure"}
|
||||
FORBIDDEN_COPY_TOKENS = ("外貌", "体质", "胎记", "疤痕", "伤疤", "身高", "体型")
|
||||
LABEL_MIN = 4
|
||||
LABEL_MAX = 80
|
||||
@@ -82,6 +83,7 @@ def probe_question_contract_payload() -> dict[str, Any]:
|
||||
"existence_style_options": [dict(item) for item in EXISTENCE_STYLE_OPTIONS],
|
||||
"quality_style_options": [dict(item) for item in QUALITY_STYLE_OPTIONS],
|
||||
"varga_none_style_option": dict(VARGA_NONE_STYLE_OPTION),
|
||||
"varga_unsure_style_option": dict(VARGA_UNSURE_STYLE_OPTION),
|
||||
"unsure_style_option": dict(UNSURE_STYLE_OPTION),
|
||||
}
|
||||
|
||||
@@ -154,7 +156,7 @@ def complete_style_options(
|
||||
if kind == "varga_style":
|
||||
for option in incoming:
|
||||
by_class[option["answer_class"]] = option
|
||||
by_class.setdefault("unsure", dict(UNSURE_STYLE_OPTION))
|
||||
by_class.setdefault("unsure", dict(VARGA_UNSURE_STYLE_OPTION))
|
||||
scoring = [item for item in ANSWER_CLASSES if item != "unsure" and item in by_class]
|
||||
if len(scoring) < 2:
|
||||
return {"ok": False, "reason": incoming_reason or "varga_insufficient_scoring"}
|
||||
|
||||
@@ -38,7 +38,8 @@ class ProbeQuestionContractTests(unittest.TestCase):
|
||||
self.assertTrue(completed["ok"])
|
||||
options = completed.get("options") or []
|
||||
self.assertEqual(len(options), 4)
|
||||
self.assertEqual(next(item["label"] for item in options if item["answer_class"] == "no"), "都不是这些特质")
|
||||
self.assertEqual(next(item["label"] for item in options if item["answer_class"] == "no"), "都不太像我")
|
||||
self.assertEqual(next(item["label"] for item in options if item["answer_class"] == "unsure"), "一时说不好")
|
||||
|
||||
def test_clock_copy_is_dropped_and_catalog_fills_existence(self) -> None:
|
||||
completed = complete_style_options("existence", [
|
||||
|
||||
Reference in New Issue
Block a user