feat(rectification): server-written lines in the same warm voice (BUG-1258)
Independent Staging Quality Gate / validate (push) Successful in 13m22s
Independent Staging Quality Gate / publish (push) Successful in 3m42s

About 30 fixed rectification lines lose the receipt tone: no 「已记录。」
openings (收到 when the range holds, 好 when it moves), 麻烦 instead of 请,
时间 instead of 候选 in what the user reads, and no 「新建对话」 after
adoption. Numbers, clocks, ranges and the honesty boundaries are unchanged.
CHOICE_ACK_RE also recognises the new acknowledgements, so a model sentence
that repeats one is still dropped; the delivery guard matches the delivery
sentence by containment and does not depend on the opening.

Full suite 4973 / fail 24, identical to 61d6f248; build keeps / Static.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
This commit is contained in:
Jesse_Chen
2026-10-07 11:39:34 +08:00
co-authored by Claude Opus 5.5
parent 61d6f248e4
commit 6ec8efd5d2
28 changed files with 199 additions and 78 deletions
@@ -120,7 +120,8 @@ test("a single-minute range is not spoken twice as range and representative", ()
assert.doesNotMatch(text, /代表分钟 05:15/);
assert.doesNotMatch(text, /更站得住的范围是 05:15/);
assert.equal(containsBoundarySemantics(text), true);
assert.equal(RECTIFICATION_USER_COPY.adoptCue, "我按你说的经历认真分析过了,下面是这次的结果。");
// 原值: 我按你说的经历认真分析过了,下面是这次的结果。 / 新值: 你说的这些经历我都对照过了,下面是这次的结果。 / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.equal(RECTIFICATION_USER_COPY.adoptCue, "你说的这些经历我都对照过了,下面是这次的结果。");
});
test("default range narration stays semantic even without an opening window", () => {
@@ -145,7 +146,8 @@ test("delivery range narration puts the stop reason before the progress clause",
openingRange: ["14:00", "15:00"],
stopReason: "user_uncertainty_too_high",
});
assert.match(text, /^前面几道题你多半选了"说不好"/);
// 原值: /^前面几道题你多半选了"说不好"/ / 新值: /^前面几道题大多说不好/ / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.match(text, /^前面几道题大多说不好/);
assert.match(text, /已经从最初的 60 分钟收到 14:02–14:43 这 41 分钟/);
assert.ok(listUserVisibleCopy().includes(RECTIFICATION_USER_COPY.uncertaintyStop));
assert.ok(listUserVisibleCopy().includes(RECTIFICATION_USER_COPY.tiedFirstStop));
@@ -774,7 +774,8 @@ test("adoptDeliveryFacts names the representative, range, stop class, and post-a
assert.equal(facts.post_adopt_verification[0]?.domain, acceptedPlan.next_followup.domain);
} else {
assert.deepEqual(facts.post_adopt_verification, []);
assert.match(templatePostAdoptExplain(facts), /没有还能核对的前事/);
// 原值: /没有还能核对的前事/ / 新值: /没有还能核对的过去的事/ / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.match(templatePostAdoptExplain(facts), /没有还能核对的过去的事/);
}
});
@@ -806,7 +806,8 @@ test("clicking A applies the choice without invoking a language model", async ()
start: "2015-01-01",
end: "2015-12-31",
});
assert.match(applied.narration, /已记录,/);
// 原值: /已记录,/ / 新值: /(?:收到|好),/ / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.match(applied.narration, /(?:收到|好),/);
// 原值: 旁白下一问是家人采集「家里如果有结婚、添丁或住院」
// 新值: 训练门未开时邀请优先「还有吗?比如…」
// 原因: BUG-648 邀请优先于领域轮盘;撤回 BUG-642 年龄带年份
@@ -888,14 +889,16 @@ test("answering a discriminator persists the next dated card so GET still has a
const persistedPrompt = schema.choice?.prompt;
assert.ok(persistedPrompt);
assert.notEqual(applied.narration, persistedPrompt);
assert.match(applied.narration, /已记录,/);
// 原值: /已记录,/ / 新值: /(?:收到|好),/ / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.match(applied.narration, /(?:收到|好),/);
// 原值: doesNotMatch(applied.narration, /2014/)
// 新值: 正文是 ack+stem,含 2014
// 原因: BUG-969 可渲染选择题不得只靠 GET 挂题干
assert.match(applied.narration, /2014/);
assert.equal(
applied.narration,
composeCollectSpokenAssistantText("已记录,范围没变;05:10 领先,05:00 落后。", persistedPrompt),
// 原值: 已记录,范围没变; / 新值: 收到,这一题没有让范围变窄; / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
composeCollectSpokenAssistantText("收到,这一题没有让范围变窄;05:10 领先,05:00 落后。", persistedPrompt),
);
const turn = accounting.calls.find((call) => call.fn === "append_agentic_rectification_turn");
assert.equal(turn?.args.p_assistant_message, applied.narration);
@@ -926,7 +929,8 @@ test("answering a discriminator persists the next dated card so GET still has a
);
assert.equal(live?.question?.prompt, persistedPrompt);
assert.equal(live?.text.includes(persistedPrompt), false);
assert.match(live?.text ?? "", /^已记录,/);
// 原值: /^已记录,/ / 新值: /^(?:收到|好),/ / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.match(live?.text ?? "", /^(?:收到|好),/);
const refreshed = parseV9CaseDossier(twoProbeDossier());
assert.ok(refreshed);
@@ -1040,7 +1044,8 @@ test("one unsure discriminator answer does not adopt and persists the next quest
// 原值: applied.narration === "已记录。这题先不计分,换一件事问。"
// 新值: 同一句后面追加下一题题干
// 原因: BUG-969 确定性回复流里要带选择题干
assert.match(applied.narration, /^已记录。这题先不计分,换一件事问。/);
// 原值: 已记录。这题先不计分,换一件事问。 / 新值: 好,这题先不算分,我们换一件事。 / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.match(applied.narration, /^好,这题先不算分,我们换一件事。/);
assert.match(applied.narration, /2014 年前后/);
assert.notEqual(applied.nextAction.session_outcome, "adopt_representative");
assert.equal(applied.nextAction.type, "ask_candidate_discriminator");
@@ -1093,11 +1098,13 @@ test("answering the last discriminator persists a year-locked family collect foc
assert.equal(setFocus, undefined);
assert.match(applied.narration, /目前范围 05:00–05:10/);
assert.equal(applied.nextInterviewPersisted, true);
assert.match(applied.narration, /已记录,/);
// 原值: /已记录,/ / 新值: /(?:收到|好),/ / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.match(applied.narration, /(?:收到|好),/);
assert.doesNotMatch(applied.narration, /2021 年前后/);
assert.doesNotMatch(applied.narration, /D24/);
const turn = accounting.calls.find((call) => call.fn === "append_agentic_rectification_turn");
assert.match(String(turn?.args.p_assistant_message ?? ""), /已记录,/);
// 原值: /已记录,/ / 新值: /(?:收到|好),/ / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.match(String(turn?.args.p_assistant_message ?? ""), /(?:收到|好),/);
assert.doesNotMatch(String(turn?.args.p_assistant_message ?? ""), /2021 年前后/);
// 原值: 没有任何 focus 写入带 p_asked_turn_id === TURN_ID
// 新值: 写入的 focus 只能是新问题本身(linkFocusAskedTurn 把新问题挂到
@@ -1160,7 +1167,8 @@ test("keeps the applied answer when narration persistence fails", async () => {
assert.equal(applied.applied, true);
assert.equal(applied.status, "applied");
assert.equal(applied.narrationPersisted, false);
assert.match(applied.narration, /已记录,/);
// 原值: /已记录,/ / 新值: /(?:收到|好),/ / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.match(applied.narration, /(?:收到|好),/);
});
test("stop_and_review does not write an inference transition", async () => {
@@ -1402,7 +1410,8 @@ test("an unsure choice keeps applied inference and does not claim scores changed
answerClass: "unsure",
});
// 旧:appliedInference 仍说「更新了候选比较」→ 新:unsure 不计分旁白 → 保留 inference 行仍持久化
assert.equal(narration, "已记录。这题先不计分,换一件事问。");
// 原值: 已记录。这题先不计分,换一件事问。 / 新值: 好,这题先不算分,我们换一件事。 / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.equal(narration, "好,这题先不算分,我们换一件事。");
assert.doesNotMatch(narration, /更新了候选比较/);
});
@@ -1422,7 +1431,8 @@ test("a scoring choice narrates cluster movement and range change", () => {
});
// 旧:领先/落后 +「范围从 04:31–05:07 收到 04:31–04:39」
// 新:范围变了仍只说收到/变为,不讲领先落后(BUG-606);范围不变才补领先/落后(BUG-634)
assert.equal(narrowed, "已记录,范围收到 04:31–04:39。");
// 原值: 已记录,范围收到 / 新值: 好,范围收到 / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.equal(narrowed, "好,范围收到 04:31–04:39。");
assert.doesNotMatch(narrowed, /领先|落后/);
assert.doesNotMatch(narrowed, /范围从 /);
const unchanged = composeChoiceNarration({
@@ -1433,7 +1443,8 @@ test("a scoring choice narrates cluster movement and range change", () => {
credibleBefore: ["04:31", "04:39"],
credibleAfter: ["04:31", "04:39"],
});
assert.equal(unchanged, "已记录,范围没变;04:31–04:39 领先。");
// 原值: 已记录,范围没变; / 新值: 收到,这一题没有让范围变窄; / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.equal(unchanged, "收到,这一题没有让范围变窄;04:31–04:39 领先。");
const unchangedZero = composeChoiceNarration({
optionId: "A",
scoring: true,
@@ -1442,7 +1453,8 @@ test("a scoring choice narrates cluster movement and range change", () => {
credibleBefore: ["04:31", "04:39"],
credibleAfter: ["04:31", "04:39"],
});
assert.equal(unchangedZero, "已记录,范围没变。");
// 原值: 已记录,范围没变。 / 新值: 收到,这一题没有让范围变窄。 / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.equal(unchangedZero, "收到,这一题没有让范围变窄。");
const movement = composeChoiceNarration({
optionId: "A",
scoring: true,
@@ -1454,7 +1466,8 @@ test("a scoring choice narrates cluster movement and range change", () => {
credibleBefore: ["04:45", "05:15"],
credibleAfter: ["04:45", "05:15"],
});
assert.equal(movement, "已记录,范围没变;04:52–04:53 领先,05:08–05:12 落后。");
// 原值: 已记录,范围没变; / 新值: 收到,这一题没有让范围变窄; / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.equal(movement, "收到,这一题没有让范围变窄;04:52–04:53 领先,05:08–05:12 落后。");
const widened = composeChoiceNarration({
optionId: "A",
scoring: true,
@@ -1462,7 +1475,8 @@ test("a scoring choice narrates cluster movement and range change", () => {
credibleBefore: ["04:45", "04:50"],
credibleAfter: ["04:40", "05:00"],
});
assert.equal(widened, "已记录,范围变为 04:40–05:00。");
// 原值: 已记录,范围变为 / 新值: 好,范围变为 / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.equal(widened, "好,范围变为 04:40–05:00。");
const unsure = composeChoiceNarration({
optionId: "D",
scoring: true,
@@ -1471,7 +1485,8 @@ test("a scoring choice narrates cluster movement and range change", () => {
credibleBefore: ["04:31", "04:39"],
credibleAfter: ["04:31", "04:39"],
});
assert.equal(unsure, "已记录。这题先不计分,换一件事问。");
// 原值: 已记录。这题先不计分,换一件事问。 / 新值: 好,这题先不算分,我们换一件事。 / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.equal(unsure, "好,这题先不算分,我们换一件事。");
});
test("answering A narrates the credible range even when the search window stays put", async () => {
@@ -1506,7 +1521,8 @@ test("answering A narrates the credible range even when the search window stays
// 旧:整段旁白等于「已记录,范围收到 04:31–04:31。」
// 新:旁白以该句开头;若下一问未能单独落库,服务端仍可能把采集题干接在后面
// 原因:BUG-606 决策 3(b) 锁的是点选旁白,不是下一问是否挂上同一条消息
assert.match(applied.narration, /^已记录,范围收到 04:31–04:31。/);
// 原值: 已记录,范围收到 / 新值: 好,范围收到 / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.match(applied.narration, /^好,范围收到 04:31–04:31。/);
assert.doesNotMatch(applied.narration, /范围没变/);
assert.doesNotMatch(applied.narration, /领先|落后/);
const source = readFileSync(new URL("../src/lib/rectification-agentic/v9/answer-choice.ts", import.meta.url), "utf8");
@@ -1542,7 +1558,8 @@ test("answering A says the range did not change when the credible range stays pu
optionId: "A",
expectedRevision: previous.revision,
});
assert.match(applied.narration, /范围没变/);
// 原值: /范围没变/ / 新值: /没有让范围变窄/ / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.match(applied.narration, /没有让范围变窄/);
assert.doesNotMatch(applied.narration, /范围从 /);
});
@@ -0,0 +1,42 @@
// BUG-1258 (2026-10-07): the server-written rectification lines speak in the
// same warm voice as the agent (BUG-1257). No 「已记录。」 receipts, no 「请」,
// no 「新建对话」, and a model sentence that repeats a new server
// acknowledgement is still dropped.
import assert from "node:assert/strict";
import test from "node:test";
import { RECTIFICATION_USER_COPY, postAdoptCheckLead, postAdoptVerifyDoneCopy } from "../src/lib/rectification-agentic/user-copy.ts";
import { composeChoiceNarration } from "../src/lib/rectification-agentic/v9/choice-action.ts";
import { bindSpokenToOpenQuestion } from "../src/lib/rectification-agentic/v9/turn-narration.ts";
test("choice acknowledgements open with 收到 / 好, never a 已记录 receipt (BUG-1258)", () => {
const lines = [
composeChoiceNarration({ optionId: "skip_probe" } as never),
composeChoiceNarration({ optionId: "A", answerClass: "unsure" } as never),
composeChoiceNarration({ optionId: "A", scoring: false } as never),
composeChoiceNarration({ optionId: "A", scoring: true, appliedInference: true } as never),
composeChoiceNarration({ optionId: "A", scoring: true, appliedInference: false } as never),
];
for (const line of lines) {
assert.doesNotMatch(line, /^已记录/, line);
assert.match(line, /^(收到|好)/, line);
}
assert.match(composeChoiceNarration({ optionId: "stop" } as never), /^好,这次校正先到这里/);
});
test("server lines carry no 请-style orders and no 新建对话 (BUG-1258)", () => {
for (const [key, value] of Object.entries(RECTIFICATION_USER_COPY)) {
if (typeof value !== "string") continue;
assert.doesNotMatch(value, /新建对话/, key);
assert.doesNotMatch(value, /请再说|请先到/, key);
}
assert.equal(postAdoptVerifyDoneCopy("05:00", false), "已采用 05:00,之后的对话都按这个时间来看。");
assert.doesNotMatch(postAdoptVerifyDoneCopy("05:00", true), /新建对话/);
assert.match(postAdoptCheckLead("05:00"), /^已采用 05:00。我们再核对一件过去的事。/);
});
test("a model sentence repeating a new server acknowledgement is dropped (BUG-1258)", () => {
const spoken = "收到,这一题没有让范围变窄。\n\n2016 年 9 月上大学记下了。";
const kept = bindSpokenToOpenQuestion(spoken, "2014 年前后,有没有升学、转学或换学习环境?");
assert.doesNotMatch(kept, /这一题没有让范围变窄/);
});
@@ -45,7 +45,8 @@ test("skipping the last reverse-verify keeps the original post-adopt sentence",
);
assert.equal(
postAdoptVerifyDoneCopy("05:07", false),
"已采用 05:07,新建对话即按这个时间排盘。",
// 原值: 已采用 05:07,新建对话即按这个时间排盘。 / 新值: 已采用 05:07,之后的对话都按这个时间来看。 / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
"已采用 05:07,之后的对话都按这个时间来看。",
);
});
@@ -221,7 +221,8 @@ test("an interior cluster leaving the range is narrated as 排除了, never 范
credibleAfter: ["14:35", "15:05"],
excludedRanges: excluded,
});
assert.equal(narration, "已记录,排除了 14:40–14:43。");
// 原值: 已记录,排除了 / 新值: 好,排除了 / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.equal(narration, "好,排除了 14:40–14:43。");
assert.doesNotMatch(narration, /范围没变/);
// Split into segments (tuple null) also reads as an exclusion.
const split = composeChoiceNarration({
@@ -233,7 +234,8 @@ test("an interior cluster leaving the range is narrated as 排除了, never 范
credibleAfter: null,
excludedRanges: excluded,
});
assert.equal(split, "已记录,排除了 14:40–14:43。");
// 原值: 已记录,排除了 / 新值: 好,排除了 / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.equal(split, "好,排除了 14:40–14:43。");
// Nothing left the range: the old sentence stays.
assert.deepEqual(excludedClusterRanges(before, before), []);
assert.equal(composeChoiceNarration({
@@ -244,7 +246,8 @@ test("an interior cluster leaving the range is narrated as 排除了, never 范
credibleBefore: ["14:35", "15:05"],
credibleAfter: ["14:35", "15:05"],
excludedRanges: [],
}), "已记录,范围没变。");
// 原值: 已记录,范围没变。 / 新值: 收到,这一题没有让范围变窄。 / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
}), "收到,这一题没有让范围变窄。");
});
// ---- BUG-1087: delivery and a skipped-line re-ask in the same turn --------
@@ -143,7 +143,8 @@ test("existence prompts cover the whole domain for every collect kind", () => {
assert.equal(TARGETED_COLLECT_OPTION_B, "这类事都没有过");
assert.equal(GUIDED_WINDOW_OPTION_B, "这段没有");
assert.match(RECTIFICATION_USER_COPY.collectDeclinedAck, /没有发生过/);
assert.match(RECTIFICATION_USER_COPY.collectSkippedAck, /换个问法再问一次/);
// 原值: /换个问法再问一次/ / 新值: /换个问法再问你/ / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.match(RECTIFICATION_USER_COPY.collectSkippedAck, /换个问法再问你/);
});
test("a layer that cannot split candidates still leaves that domain in the open pool", () => {
@@ -335,7 +335,8 @@ test("narrator failure still leaves the choice applied and does not ask the user
scoring: true,
appliedInference: true,
});
assert.match(applied, /已记录,范围没变/);
// 原值: /已记录,范围没变/ / 新值: /收到,这一题没有让范围变窄/ / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.match(applied, /收到,这一题没有让范围变窄/);
assert.doesNotMatch(applied, /请再选一次|重新回答/);
const stopped = composeChoiceNarration({
optionId: "stop",
@@ -343,8 +344,10 @@ test("narrator failure still leaves the choice applied and does not ask the user
appliedInference: false,
});
// Previously asserted “独立核对尚未完成 / 不是最终校正结果”; task 6 makes range delivery a completed terminal.
assert.match(stopped, /已记录你的选择/);
assert.match(stopped, /交付当前可信区间和代表性工作时间/);
// 原值: /已记录你的选择/ / 新值: /这次校正先到这里/ / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.match(stopped, /这次校正先到这里/);
// 原值: /交付当前可信区间和代表性工作时间/ / 新值: /目前最可信的时间范围/ / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.match(stopped, /目前最可信的时间范围/);
assert.match(stopped, /当前最优结果是候选时间段/);
assert.doesNotMatch(stopped, /未完成|失败|遗憾/);
assert.doesNotMatch(stopped, /已完成验证/);
@@ -107,7 +107,8 @@ test("采用 writes its own turn, hangs the post-adopt check on it and quiets th
const turn = accounting.calls.find((call) => call.fn === "append_agentic_rectification_turn");
assert.equal(turn?.args.p_request_id, adoptTurnRequestId("req-1"));
assert.equal(turn?.args.p_user_message, null);
assert.equal(turn?.args.p_assistant_message, "已采用 05:00。再核对一件过去的事。2018 年前后,有没有入职或职责明显加重?");
// 原值: 已采用 05:00。再核对一件过去的事。 / 新值: 已采用 05:00。我们再核对一件过去的事。 / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.equal(turn?.args.p_assistant_message, "已采用 05:00。我们再核对一件过去的事。2018 年前后,有没有入职或职责明显加重?");
const link = accounting.calls.find((call) => call.fn === "set_agentic_rectification_conversation_focus");
assert.equal(link?.args.p_asked_turn_id, "44444444-4444-4444-8444-444444444444");
assert.equal(alreadyDelivered({ caseId: CASE, resultId: RESULT, hasUserMessage: false }), true);
@@ -136,7 +137,8 @@ test("segment product: choice ack has no minute leaderboard", () => {
};
const minute = composeChoiceNarration(base as never);
const segment = composeChoiceNarration({ ...base, segmentProduct: true } as never);
assert.equal(segment, "已记录,范围没变。");
// 原值: 已记录,范围没变。 / 新值: 收到,这一题没有让范围变窄。 / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.equal(segment, "收到,这一题没有让范围变窄。");
assert.doesNotMatch(segment, /领先|落后/);
assert.match(minute, /领先/, "the minute product still reads the movement");
});
@@ -42,9 +42,11 @@ test("verdict: fits, does not fit, cannot tell, and unsure", () => {
assert.equal(postAdoptCheckVerdict({ ...base, answerClass: "yes" }), "这件事和 04:55 对得上。");
// Minute product (no chart summary): the card is where a re-pick happens.
assert.equal(postAdoptCheckVerdict({ ...base, answerClass: "no" }),
"这件事和 04:55 对不上;如果别的经历也对不上,可以回到上面的卡片改选。");
// 原值: 这件事和 04:55 对不上;如果别的经历也对不上,可以回到上面的卡片改选。 / 新值: 这件事和 04:55 对不上。要是别的经历也对不上,可以回到上面的卡片换一个时间。 / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
"这件事和 04:55 对不上。要是别的经历也对不上,可以回到上面的卡片换一个时间。");
assert.equal(postAdoptCheckVerdict({ ...base, answerClass: "weak_yes" }), "这件事分不出 04:55 和别的时间。");
assert.equal(postAdoptCheckVerdict({ ...base, answerClass: "unsure" }), "这件事记不清,不算。");
// 原值: 这件事记不清,不算。 / 新值: 这件记不清也没关系,不算进去。 / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.equal(postAdoptCheckVerdict({ ...base, answerClass: "unsure" }), "这件记不清也没关系,不算进去。");
assert.equal(postAdoptCheckVerdict({ ...base, answerClass: null }), null);
assert.equal(postAdoptCheckVerdict({ ...base, acceptedTime: null, answerClass: "yes" }), null);
assert.equal(postAdoptCheckVerdict({ ...base, probe: null, answerClass: "yes" }), null, "no probe, no claim");
@@ -142,7 +142,8 @@ test("empty reverse-verify list forbids a 会拿…核对 promise", () => {
minutes: ["05:00", "05:06"],
years: [],
};
assert.match(templatePostAdoptExplain(facts), /没有还能核对的前事/);
// 原值: /没有还能核对的前事/ / 新值: /没有还能核对的过去的事/ / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
assert.match(templatePostAdoptExplain(facts), /没有还能核对的过去的事/);
const denied = validateAdoptNarration("采用后会拿 2016 年教育题来核对。", facts);
assert.equal(denied.ok, false);
if (!denied.ok) assert.equal(denied.reason, "promise");
@@ -188,7 +188,8 @@ test("collect_spoken stem lives on turn.question inside the same assistant artic
assert.doesNotMatch(chat, /showQuestionSlot/);
assert.match(
chat,
/\(liveQuestionOnMessages \|\| questionGap === "persisted_question"\) && collectSpokenPrompt\n\s+\? "请回答上面的问题…"/,
// 原值: "请回答上面的 / 新值: "回答上面的问题就好 / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
/\(liveQuestionOnMessages \|\| questionGap === "persisted_question"\) && collectSpokenPrompt\n\s+\? "回答上面的问题就好…"/,
);
// 原值: messages.some(同 focus_id)
// 新值: 只认 latestSettledAssistant
@@ -69,7 +69,8 @@ test("choice-focus declared window is answered from the route before the model",
assert.deepEqual(ordinary.rpcCalls, []);
assert.equal(
RECTIFICATION_USER_COPY.declaredWindowLockedReply,
"搜索范围是开始时按你的资料定的,校正过程中不改。想按别的时间段重来,请先到资料里改出生时间,再新建一次校正。",
// 原值: 搜索范围是开始时按你的资料定的,校正过程中不改。想按别的时间段重来,请先到资料里改出生时间,再新建一次校正。 / 新值: 找的范围是开始时按你的资料定的,中途不改。想换个时间段,先在资料里改出生时间,再重新开始一次校正就好。 / 原因: BUG-1258:校正固定文案改为知心姐姐口吻(产品 2026-10-07 认可样稿)
"找的范围是开始时按你的资料定的,中途不改。想换个时间段,先在资料里改出生时间,再重新开始一次校正就好。",
);
});