fix: scope onboarding fallback greeting

This commit is contained in:
Jesse_Chen
2026-07-19 21:59:43 +08:00
parent 5ee925cd1e
commit 308e5d532a
4 changed files with 41 additions and 27 deletions
+2 -1
View File
@@ -46,6 +46,7 @@ import { chatMessageViews, type ChatMessage } from "@/lib/chat-message-view";
import {
OnboardingAuthenticationError,
type OnboardingContent,
createOnboardingFallbackGreeting,
createStartGreeting,
isCurrentOnboardingRequest,
onboardingProfileFingerprint,
@@ -2320,7 +2321,7 @@ export default function Home() {
<OnboardingChatMessage role="assistant" text={onboarding?.greeting
|| (onboardingPending
? `${profile.name.trim()},稍等一下,我正在准备几个适合开始的问题。`
: startGreeting || `${profile.name.trim()},从你此刻最关心的问题开始吧。`)} />
: createOnboardingFallbackGreeting(profile.name))} />
)}
{!profileComplete && onboardingStep === "birth" && onboardingCardReady && (
+4
View File
@@ -104,6 +104,10 @@ export function createStartGreeting(
return variants[Math.floor(variantSelection * variants.length)](displayName);
}
export function createOnboardingFallbackGreeting(name: string): string {
return `${name.trim()},从你此刻最关心的问题开始吧。`;
}
export function onboardingProfileFingerprint(profile: OnboardingProfileFingerprintInput): string {
return JSON.stringify([
profile.name,
-26
View File
@@ -3,10 +3,6 @@ import test from "node:test";
import {
OnboardingAuthenticationError,
OnboardingRequestError,
createStartGreeting,
isCurrentOnboardingRequest,
onboardingProfileFingerprint,
onboardingRequestIdentity,
requestOnboardingWithRecovery,
} from "../src/lib/onboarding-client.ts";
@@ -20,28 +16,6 @@ const personalizedOnboarding = {
source: "cache",
} as const;
const completeProfile = {
name: "林遥", date: "1990-06-15", time: "12:30", reportedTime: "12:30",
birthTimeSource: "hospital_record", birthTimePeriod: "", birthTimeClue: "出生证明", birthTimeStatus: "confirmed",
uncertaintyBeforeMinutes: 0, uncertaintyAfterMinutes: 0, rectificationCaseId: "", countryCode: "CN", provinceCode: "110000", cityCode: "110000-city", districtCode: "110101",
} as const;
test("rejects a stale completion after a complete profile changes", () => {
// Given: one account starts onboarding for a complete persisted profile.
const firstIdentity = onboardingRequestIdentity("account-1", onboardingProfileFingerprint(completeProfile));
// When: a presentation-affecting profile field changes before that request completes.
const changedFingerprint = onboardingProfileFingerprint({ ...completeProfile, name: "周宁" });
const currentIdentity = onboardingRequestIdentity("account-1", changedFingerprint);
const committedGreeting = createStartGreeting("周宁", new Date("2026-07-19T08:00:00+08:00"), 0);
// Then: the new profile has a distinct identity and its greeting cannot retain the old name.
assert.notEqual(currentIdentity, firstIdentity);
assert.equal(isCurrentOnboardingRequest(currentIdentity, firstIdentity), false);
assert.match(committedGreeting, /周宁/);
assert.doesNotMatch(committedGreeting, /林遥/);
});
test("returns personalized cache content after a timeout and pending response", async () => {
// Given: the first request times out, the second is provisional, and the third is terminal.
const originalFetch = globalThis.fetch;
@@ -0,0 +1,35 @@
import assert from "node:assert/strict";
import test from "node:test";
import {
createOnboardingFallbackGreeting,
createStartGreeting,
isCurrentOnboardingRequest,
onboardingProfileFingerprint,
onboardingRequestIdentity,
} from "../src/lib/onboarding-client.ts";
const completeProfile = {
name: "林遥", date: "1990-06-15", time: "12:30", reportedTime: "12:30",
birthTimeSource: "hospital_record", birthTimePeriod: "", birthTimeClue: "出生证明", birthTimeStatus: "confirmed",
uncertaintyBeforeMinutes: 0, uncertaintyAfterMinutes: 0, rectificationCaseId: "", countryCode: "CN", provinceCode: "110000", cityCode: "110000-city", districtCode: "110101",
} as const;
test("rejects stale A presentation and derives terminal and fallback greetings from profile B", () => {
// Given: one account starts onboarding for a complete persisted profile A.
const firstIdentity = onboardingRequestIdentity("account-1", onboardingProfileFingerprint(completeProfile));
// When: the name changes before that request completes and profile B is presented.
const changedProfile = { ...completeProfile, name: "周宁" };
const currentIdentity = onboardingRequestIdentity("account-1", onboardingProfileFingerprint(changedProfile));
const terminalGreeting = createStartGreeting(changedProfile.name, new Date("2026-07-19T08:00:00+08:00"), 0);
const fallbackGreeting = createOnboardingFallbackGreeting(changedProfile.name);
// Then: stale work is rejected and neither presentation path can retain A's name.
assert.notEqual(currentIdentity, firstIdentity);
assert.equal(isCurrentOnboardingRequest(currentIdentity, firstIdentity), false);
for (const greeting of [terminalGreeting, fallbackGreeting]) {
assert.match(greeting, /周宁/);
assert.doesNotMatch(greeting, /林遥/);
}
assert.equal(fallbackGreeting, "周宁,从你此刻最关心的问题开始吧。");
});