feat(home): warm older-sister greeting voice; daily line says why, plainly
Independent Staging Quality Gate / validate (push) Successful in 12m47s
Independent Staging Quality Gate / publish (push) Successful in 3m47s

Late night no longer remarks on being awake (产品 2026-10-01); every daypart,
weekday and returning line reworded in the same caring voice. Daily line:
each house sentence names where the Moon is in plain words, then one concrete
sentence; no stacked hedges. Sign-fallback moods rewritten the same way.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
This commit is contained in:
Jesse_Chen
2026-10-01 19:34:16 +08:00
co-authored by Claude Opus 5.5
parent fa6d026f12
commit dc45fde613
5 changed files with 106 additions and 84 deletions
+6
View File
@@ -1,5 +1,11 @@
# 印度占星 Skill 更新日志
## 2026-10-01 — 首页开场语换成知心姐姐口吻;今日星语说清为什么
- 开场语:深夜不再说「夜猫子」「还没睡呀」,改成「这会儿很安静」「夜里好,{名字}」「慢慢说,{名字}」;其余时段同样改成关心的口吻,例如「中午好,记得吃饭」「今天辛苦了」「周五了,松口气」。
- 今日星语:每句先交代原因(今天月亮走到你盘上管哪类事的位置),再给一句具体的话,不再叠「更容易」「被放大」;没确认出生时间时按星座写的那句也改成具体建议。
- 不走模型、不改数据库结构;Skill 版本不变。
## 2026-10-01 — 普通对话不再夹英文,名词叫法统一
- 回答里不再出现 sade sati、vargottama、rupas 这类英文或梵文音译;计都不再写成「克图」;大运下面的时段统一叫子运、小运;行星力量只说强、中、弱(BUG-1148)。
+2 -2
View File
@@ -310,7 +310,7 @@ Jyotisha 的可见文案是产品的一部分。正确性红线(真实性、
| 这一页是天象本身,不是对你的判断。 | (不写) | 星历页只放日期、五要素、行运、九十天事件和底部提问提示卡。「带这天去提问」在页面最底部的提示卡里(2026-09-26 从顶栏挪下来)。不另印定性句。 |
| (校正会话上普通输入框仍可打字) | 正在打开生时校正… | 校正会话上普通输入框只有禁用态。打开失败时按钮写「重新打开生时校正」。 |
| 9月14日 · 生时校正 / 生时校正 · 9月14日 / 生时校正 · 09:35(创建钟点) | 生时校正 · 05:07 / 生时校正 · 05:00–05:15 / 生时校正 | 校正标题写结果:已确认优先于已采用,写 `生时校正 · HH:MM`;否则当前范围写 `生时校正 · HH:MM–HH:MM`(间隔号,不是连字符);都没有则只写「生时校正」。今日节奏仍是 `今日节奏 · M月D日`。同日不再用墙钟去重。副标题仍是最后活动时间。旧标题按结果批量改;手改过的名字不动。 |
| 这么晚还醒着,{名字}。直接说说最在意的问题吧。 | 还没睡呀,{名字} | 开场只一行、不追问、不写场景;提问交给输入框占位符 |
| 这么晚还醒着,{名字}。直接说说最在意的问题吧。 | 夜里好,{名字} | 开场只一行、不追问、不写场景;提问交给输入框占位符。2026-10-01 起开场语是知心姐姐的口吻:只打招呼、关心,不评论用户(不写「夜猫子」「还没睡呀」——深夜打开的人可能失眠、可能心里有事,不需要被点评) |
| 你更适合把已经积累的专业能力做成长期事业,而不是频繁换赛道。眼下更值得把现有工作做深,而不是立刻另起一摊。 | 今年工作上机会不少,但真正决定你走多远的是规矩和身体,不是人缘。<br>## 盘上依据<br>木星今年走过你的事业宫,机会和帮你的人都在(木星行运 10 宫);同时土星压在你的工作宫,事情多、要求严,身体也容易被拖累(土星行运 6 宫)。<br>## 时间怎么看<br>9 月木星换宫之前,机会多但不稳;之后再谈升职更有把握。 | 坏的那句像顾问报告:只有结论,没有盘上依据。好的那段先答、再给依据和时间,每句删掉括号后都看得懂(盘上数据是示意)。 |
| (用户说「你在说什么鬼」)抱歉让你困惑了,我再解释一下:从星盘来看,您的事业宫…… | 说直接点:这份工作还值得留,但你得换个位置,不是换公司。哪句没看懂,指给我。 | 追问轮不重开一遍报告,也不道歉铺垫。一句白话结论 + 一句把球踢回去。 |
@@ -414,7 +414,7 @@ Jyotisha 的可见文案是产品的一部分。正确性红线(真实性、
## 今日星语句库(2026-09-30,BUG-1109)
- 首页问候下面的今日星语来自固定句库 `frontend/src/lib/daily-starlanguage-library.ts`,不走模型。改句子只改这个文件,全部句子的审阅表在 `docs/tasks/PROGRESS-daily-line-library-20260930.md`。
- 一句 trend = 宫位句(说今天的心思落在哪类事上)+ 月相尾句(说今天适合推进还是收尾)。宫位句不写「第几宫」「宫主」「相位」「大运」,用生活里的词:工作、家、钱、朋友、休息。
- 一句 trend = 宫位句 + 月相尾句。宫位句先用半句交代为什么(「今天月亮走到你盘上管钱的位置」),再给一句具体的判断或建议(「买东西、谈价钱前多算一遍,今天容易花多」);一句里不叠「可能」「更容易」「被放大」(2026-10-01 产品:「含含糊糊」)。不写「第几宫」「宫主」「相位」「大运」,用生活里的词:工作、家、钱、朋友、休息。月相尾句说今天适合推进还是收尾。
- action 是一件今天就能做完的具体小事;caution 是一件要留意的事,不吓人、不断言会发生什么。
- 不写健康诊断、投资建议、法律意见;不写「一定」「必然」「注定」。
- 出生时间没确认时不用宫位,只按月亮所在星座写,caution 固定为「出生时间尚未确认,这里只看大方向,不依赖具体分钟。」
+52 -52
View File
@@ -21,72 +21,72 @@ export type LunarPhase = "new" | "waxing" | "full" | "waning";
export const HOUSE_LINES: Readonly<Record<number, Line3>> = {
1: [
"今天注意力更多回到自己身上,精神和身体的状态都更容易被察觉。",
"今天适合照顾自己的节奏,先把状态调顺,再去应付别的事。",
"今天你的想法和情绪都更直接,别人也更容易注意到你。",
"今天月亮走到你盘上管自己的位置,身体和心情都更敏感,先把自己照顾好。",
"月亮今天回到管你自己的那一块,想做的事今天开头最顺手。",
"今天月亮落在管你自己的位置,情绪会直接写在脸上,累了就说累。",
],
2: [
"今天钱和说话这两件事更容易被放大,花出去的和说出口的都值得多想一下。",
"今天适合盘一盘手头的资源,也适合把想说的话说得更稳一点。",
"今天对价格、收入这些具体数字更敏感,适合算清楚再决定。",
"今天月亮走到你盘上管钱的位置,买东西、谈价钱前多算一遍,今天容易花多。",
"月亮今天在管钱和说话的那一块,想说的话先在心里过一遍,再开口。",
"今天月亮落在管收入的位置,适合把这个月的账理一理,心里会踏实很多。",
],
3: [
"今天行动力不错,适合跑腿、联络,把拖着的小事一件件办掉。",
"今天消息往来多,短途出行和身边的兄弟朋友都可能找上你。",
"今天适合主动一点,写、说、发,都比等别人来找更有效。",
"今天月亮走到你盘上管沟通和跑腿的位置,拖着的消息和小事,今天最好办。",
"月亮今天在管联络的那一块,想找谁就主动找,别等对方先开口。",
"今天月亮落在管出门办事的位置,短途走一趟、见个人,都比待着有收获。",
],
4: [
"今天心思更容易回到家里,情绪起伏也更容易被家人察觉。",
"今天适合把住处或自己的情绪收拾一下,里面安定了,外面的事才顺。",
"今天更需要一个让自己安心的角落,别把所有事都排得太满。",
"今天月亮走到你盘上管家的位置,心思会往家里跑,给家人打个电话会很安心。",
"月亮今天在管家和情绪的那一块,把住的地方收拾一下,人也会跟着静下来。",
"今天月亮落在管安全感的位置,别把日程排太满,给自己留个角落。",
],
5: [
"今天适合做点让自己开心的事,创作、玩乐或和喜欢的人相处都更顺。",
"今天表达欲更强,适合把一个想法做成小作品拿出来。",
"今天和孩子、恋人或兴趣有关的事,更容易带来好心情。",
"今天月亮走到你盘上管开心和恋爱的位置,做点纯粹喜欢的事,不用有用。",
"月亮今天在管表达的那一块,有个想法就写下来、画出来,今天手感好。",
"今天月亮落在管心动和孩子的位置,和喜欢的人待一会儿,心情会亮起来。",
],
6: [
"今天适合处理日常杂事和待办清单,按部就班反而最省力。",
"今天身体和作息的小信号更明显,适合把一个习惯调整回来。",
"今天工作里的琐碎事会多一些,一件件处理掉就好。",
"今天月亮走到你盘上管日常琐事的位置,按清单一件件来,反而最省力。",
"月亮今天在管身体小信号的那一块,哪里不舒服别硬扛,早点休息。",
"今天月亮落在管工作杂事的位置,事会多一点,先做完最烦的那件。",
],
7: [
"今天身边的人更重要,合作和相处里的细节更容易被放大。",
"今天适合和伴侣或合作方把事情对齐,一起商量比自己硬扛好。",
"今天别人的态度会影响你的心情,先听清对方想要什么。",
"今天月亮走到你盘上管伴侣和合作的位置,有话想跟对方说,今天开口比憋着好。",
"月亮今天在管身边人的那一块,别人的态度会影响你,先听完再回应。",
"今天月亮落在管合作的位置,两个人商量着来,比一个人硬扛轻松。",
],
8: [
"今天情绪可能更深一点,适合面对一件一直不愿碰的事。",
"今天容易想得多,把担心写下来,比在脑子里打转轻松。",
"今天适合处理共同的钱物或旧账,慢一点、细一点。",
"今天月亮走到你盘上管心里压力的位置,想得会多一点,写下来比憋着好受。",
"月亮今天在管共同钱物的那一块,和别人有关的账,今天适合慢慢对清楚。",
"今天月亮落在管深处情绪的位置,适合面对一件一直不想碰的小事。",
],
9: [
"今天适合学点新东西,读一篇长文或听一次课都会有收获。",
"今天视野更容易打开,远方的人和事可能带来新想法。",
"今天适合想想更长远的方向,别只盯着眼前这一件。",
"今天月亮走到你盘上管学习和远方的位置,读点东西、听一堂课,都会有收获。",
"月亮今天在管长远打算的那一块,适合想想半年后的自己,别只盯着眼前。",
"今天月亮落在管老师和长辈的位置,拿不准的事,去问问比你有经验的人。",
],
10: [
"今天工作和对外的事更显眼,你的表现更容易被人看到。",
"今天适合把一项成果推进一步,让该知道的人知道。",
"今天责任感会重一点,先做最要紧的那件,别被杂事拉走。",
"今天月亮走到你盘上管工作的位置,你做的事更容易被看见,把成果拿出来。",
"月亮今天在管事业的那一块,先做最要紧的那件,别被杂事拉走。",
"今天月亮落在管对外形象的位置,说话做事稍微正式一点,会给你加分。",
],
11: [
"今天朋友和圈子更活跃,一次交流可能带来有用的消息。",
"今天适合联系老朋友或参加一次聚会,关系会带来机会。",
"今天心里的愿望更容易说出口,也更容易得到别人的回应。",
"今天月亮走到你盘上管朋友的位置,和朋友聊一聊,会听到有用的消息。",
"月亮今天在管圈子和心愿的那一块,想要什么就说出来,会有人接住。",
"今天月亮落在管人脉的位置,联系一个很久没聊的人,正是时候。",
],
12: [
"今天更需要休息和独处,把节奏放慢不是偷懒。",
"今天适合收尾和整理,不急着开新头。",
"今天花钱和精力都容易悄悄流走,留意一下去向。",
"今天月亮走到你盘上管休息的位置,精力偏低,重要的事放明天,今晚早点收工。",
"月亮今天在管独处的那一块,想一个人待着很正常,不用解释。",
"今天月亮落在管花销的位置,钱和精力都容易悄悄流走,留意一下去向。",
],
};
export const PHASE_TAILS: Readonly<Record<LunarPhase, Line2>> = {
new: ["新月前后,适合定一个小开头。", "月亮刚要重新变圆,先想清楚再动手。"],
waxing: ["月亮渐盈,适合往前推一步。", "月亮渐盈,做加法比做减法顺。"],
full: ["满月前后,情绪容易满,先稳住再回应。", "满月前后,适合把结果摆出来看看。"],
waning: ["月亮渐亏,适合收尾和清理。", "月亮渐亏,做减法比开新头顺。"],
new: ["这两天是新月,适合开个小头。", "这两天是新月,先想清楚再动手。"],
waxing: ["月亮正在变圆,往前推一步会顺。", "月亮正在变圆,做加法比做减法顺。"],
full: ["这两天是满月,情绪容易满,先缓一缓再回话。", "这两天是满月,适合把结果摆出来看看。"],
waning: ["月亮正在变缺,适合收尾和清理。", "月亮正在变缺,做减法比开新头顺。"],
};
export const HOUSE_ACTIONS: Readonly<Record<number, Line2>> = {
@@ -126,18 +126,18 @@ const SIGN_ZH: Readonly<Record<string, string>> = {
/** Used when the house cannot be counted (birth time not confirmed, or no ascendant). */
export const SIGN_MOODS: Readonly<Record<string, string>> = {
Aries: "整体节奏偏快,适合先动起来。",
Taurus: "整体节奏偏稳,适合把手上的事做扎实。",
Gemini: "消息和想法都多,适合沟通和学习。",
Cancer: "情绪更柔软,适合照顾家和身边的人。",
Leo: "表现欲更强,适合把自己的想法拿出来。",
Virgo: "适合整理细节,把清单一件件勾掉。",
Libra: "更在意关系和分寸,适合商量和协调。",
Scorpio: "感受更深,适合专注处理一件要紧事。",
Sagittarius: "心情更开阔,适合学习或出门走走。",
Capricorn: "更务实,适合推进需要耐心的事。",
Aquarius: "更想跳出常规,适合换个角度想问题。",
Pisces: "更感性也更容易累,适合放慢一点。",
Aries: "做事会急一点,想到就先做一小步,别一口气全揽下。",
Taurus: "人会想要安稳,把手上的事做扎实,比开新事舒服。",
Gemini: "消息和想法都多,适合聊天、学东西,重要的事记下来。",
Cancer: "心会软一点,照顾一下家人,也照顾一下自己。",
Leo: "想被看见很正常,把你做好的东西拿出来给人看。",
Virgo: "适合整理细节,列个清单一件件勾掉,心里会清爽。",
Libra: "会更在意别人怎么想,有分歧时先商量,不急着定。",
Scorpio: "感受会深一点,专心做一件要紧事,别分心太多处。",
Sagittarius: "心情会开阔,出门走走或学点新东西,都很合适。",
Capricorn: "人会务实一点,适合推进需要耐心的事,一步一步来就好。",
Aquarius: "想跳出常规,换个角度看老问题,会有新办法。",
Pisces: "更感性也更容易累,今天对自己宽松一点。",
};
const SIGN_ACTIONS: Line2 = ["把今天要做的事收成一件,做完再看下一件。", "给自己留一段安静的时间,想清楚再动。"];
+13 -10
View File
@@ -1,7 +1,9 @@
type GreetingPeriod = "morning" | "noon" | "afternoon" | "evening" | "late-night";
/**
* One line, two to five words, no follow-up question.
* One line, two to five words, no follow-up question. Since 2026-10-01 the voice
* is a warm older sister's (知心姐姐): it greets and cares, never comments on the
* user (no 夜猫子 / 还没睡呀).
*
* The homepage opening used to be a salutation plus a question ("这么晚还醒着,
* {名字}。直接说说最在意的问题吧。") — an office voice that answered for the user
@@ -11,26 +13,27 @@ type GreetingPeriod = "morning" | "noon" | "afternoon" | "evening" | "late-night
const NAME_TOKEN = "{名字}";
const periodGreetings: Record<GreetingPeriod, readonly string[]> = {
morning: ["早上好", "早上好,{名字}", "早呀,{名字}"],
noon: ["中午好", "中午好,{名字}"],
afternoon: ["下午好", "下午好,{名字}"],
evening: ["晚上好", "晚上好,{名字}", "今天过得怎么样?"],
"late-night": ["夜猫子,晚上好", "还没睡呀,{名字}", "晚安前再聊一会"],
morning: ["早安", "早安,{名字}", "早呀,今天慢慢来"],
noon: ["中午好,记得吃饭", "午安,{名字}"],
afternoon: ["下午好,歇口气吧", "下午好,{名字}"],
evening: ["今天辛苦了", "晚上好,{名字}", "晚上好,歇一歇"],
// Late night never remarks on being awake (产品 2026-10-01: 「你管别人睡不睡」).
"late-night": ["这会儿很安静", "夜里好,{名字}", "慢慢说,{名字}"],
};
/** Keyed by `Date#getDay()`. Days with nothing worth saying stay out of the pool. */
const weekdayGreetings: Readonly<Record<number, readonly string[]>> = {
0: ["周日,慢一点"],
1: ["周一了,{名字}"],
5: ["周五快乐"],
6: ["周末愉快,{名字}"],
1: ["周一了,别太累"],
5: ["周五了,松口气"],
6: ["周末好好歇歇"],
};
/** Only reachable once the account has at least one session behind it. */
const returningGreetings: readonly string[] = [
"又见面了,{名字}",
"你来啦,{名字}",
"欢迎回来",
"嗨,{名字}",
"最近还好吗,{名字}?",
];
+33 -20
View File
@@ -30,7 +30,8 @@ test("terminal and fallback greetings follow the current profile name", () => {
assert.match(greeting, /周宁/);
assert.doesNotMatch(greeting, /林遥/);
}
assert.equal(terminalGreeting, "早上好,周宁");
// 原值 "早上好,周宁" / 新值 "早安,周宁" / 原因:开场语改知心姐姐口吻(产品 2026-10-01)。
assert.equal(terminalGreeting, "早安,周宁");
assert.equal(fallbackGreeting, "欢迎,周宁");
});
@@ -41,36 +42,46 @@ test("the starter greeting is one line drawn from daypart, weekday and returning
// 原因:产品把开场语改成 claude.ai 式的单行问候,追问句移到输入框占位符,
// 「招呼语 + 问句」两半这个形状本身被取消,问句池不再存在。
const noon = WEDNESDAY(12);
assert.equal(createStartGreetingParts("周宁", noon, 0).text, "中午好");
assert.equal(createStartGreetingParts("周宁", noon, 0.5).text, "中午好,周宁");
// 原值 "中午好" / "中午好,周宁" / 新值 "中午好,记得吃饭" / "午安,周宁"
// / 原因:开场语改知心姐姐口吻(产品 2026-10-01);下标与池长不变。
assert.equal(createStartGreetingParts("周宁", noon, 0).text, "中午好,记得吃饭");
assert.equal(createStartGreetingParts("周宁", noon, 0.5).text, "午安,周宁");
assert.equal(createStartGreeting("周宁", noon, 0.5), createStartGreetingParts("周宁", noon, 0.5).text);
// 边界不越界:1 与 0.999999 都落在池内最后一条。
assert.equal(createStartGreetingParts("周宁", noon, 1).text, "中午好,周宁");
assert.equal(createStartGreetingParts("周宁", noon, 0.999999).text, "中午好,周宁");
assert.equal(createStartGreetingParts("周宁", noon, 1).text, "午安,周宁");
assert.equal(createStartGreetingParts("周宁", noon, 0.999999).text, "午安,周宁");
});
test("late night has its own three lines and none of them asks a follow-up", () => {
test("late night has its own three lines and none of them remarks on being awake", () => {
// 原值 "夜猫子,晚上好" / "还没睡呀,周宁" / "晚安前再聊一会"
// / 新值 "这会儿很安静" / "夜里好,周宁" / "慢慢说,周宁"
// / 原因:产品 2026-10-01「夜猫子、还不睡,用户会觉得你管别人睡不睡」;断言加严:深夜池任何一条都不得提睡觉。
const lateNight = WEDNESDAY(2);
assert.equal(createStartGreetingParts("周宁", lateNight, 0).text, "夜猫子,晚上好");
assert.equal(createStartGreetingParts("周宁", lateNight, 1 / 3).text, "还没睡呀,周宁");
assert.equal(createStartGreetingParts("周宁", lateNight, 0.7).text, "晚安前再聊一会");
assert.equal(createStartGreetingParts("周宁", lateNight, 0).text, "这会儿很安静");
assert.equal(createStartGreetingParts("周宁", lateNight, 1 / 3).text, "夜里好,周宁");
assert.equal(createStartGreetingParts("周宁", lateNight, 0.7).text, "慢慢说,周宁");
// 23 点与 4 点同属深夜。
assert.equal(createStartGreetingParts("周宁", WEDNESDAY(23), 1 / 3).text, "还没睡呀,周宁");
assert.equal(createStartGreetingParts("周宁", WEDNESDAY(4), 1 / 3).text, "还没睡呀,周宁");
assert.equal(createStartGreetingParts("周宁", WEDNESDAY(23), 1 / 3).text, "夜里好,周宁");
assert.equal(createStartGreetingParts("周宁", WEDNESDAY(4), 1 / 3).text, "夜里好,周宁");
for (let step = 0; step < 100; step += 1) {
assert.doesNotMatch(createStartGreetingParts("周宁", lateNight, step / 100).text, /睡|夜猫子|晚安/);
}
});
test("a blank name leaves only the lines that carry no name", () => {
const lateNight = WEDNESDAY(2);
assert.equal(createStartGreetingParts("", lateNight, 0).text, "夜猫子,晚上好");
assert.equal(createStartGreetingParts(" ", lateNight, 0.9).text, "晚安前再聊一会");
// 原值 "夜猫子,晚上好" / "晚安前再聊一会" / 新值 "这会儿很安静"(深夜池唯一不带称呼的一条)
// / 原因:深夜池换句(产品 2026-10-01)。
assert.equal(createStartGreetingParts("", lateNight, 0).text, "这会儿很安静");
assert.equal(createStartGreetingParts(" ", lateNight, 0.9).text, "这会儿很安静");
// 周一的星期条目带称呼,名字为空时整条不可达;回访池同理。
// 原值:断言名字为空时不出现「周一了」/ 新值:只断言带称呼的回访条目不可达
// / 原因:周一条目改成不带称呼的「周一了,别太累」,名字为空也该出现;带称呼条目不可达的断言保留。
for (let step = 0; step < 100; step += 1) {
for (const hasSessions of [false, true]) {
const text = createStartGreetingParts("", MONDAY(9), step / 100, hasSessions).text;
assert.doesNotMatch(text, /周一了/);
assert.doesNotMatch(text, /又见面了|嗨,|最近还好吗/);
assert.doesNotMatch(text, /又见面了|你来啦|最近还好吗/);
assert.ok(text.length > 0);
assert.doesNotMatch(text, /\{名字\}/);
assert.doesNotMatch(text, /,$|^,/);
@@ -82,22 +93,24 @@ test("the weekday pool only opens on its own day", () => {
const friday = FRIDAY(9);
const fridayLines = new Set(Array.from({ length: 100 }, (_, step) =>
createStartGreetingParts("周宁", friday, step / 100).text));
assert.ok(fridayLines.has("周五快乐"));
// 原值 "周五快乐" / "周一了,周宁" / 新值 "周五了,松口气" / "周一了,别太累" / 原因:知心姐姐口吻(产品 2026-10-01)。
assert.ok(fridayLines.has("周五了,松口气"));
const wednesdayLines = new Set(Array.from({ length: 100 }, (_, step) =>
createStartGreetingParts("周宁", WEDNESDAY(9), step / 100).text));
assert.ok(!wednesdayLines.has("周五快乐"));
assert.ok(!wednesdayLines.has("周五了,松口气"));
assert.equal(wednesdayLines.size, 3);
assert.ok(new Set(Array.from({ length: 100 }, (_, step) =>
createStartGreetingParts("周宁", MONDAY(9), step / 100).text)).has("周一了,周宁"));
createStartGreetingParts("周宁", MONDAY(9), step / 100).text)).has("周一了,别太累"));
assert.ok(new Set(Array.from({ length: 100 }, (_, step) =>
createStartGreetingParts("周宁", SUNDAY(9), step / 100).text)).has("周日,慢一点"));
});
test("the returning pool needs at least one session behind the account", () => {
const evening = WEDNESDAY(20);
const returning = ["又见面了,周宁", "欢迎回来", "嗨,周宁", "最近还好吗,周宁?"];
// 原值 "嗨,周宁" / 新值 "你来啦,周宁" / 原因:知心姐姐口吻(产品 2026-10-01);池长不变。
const returning = ["又见面了,周宁", "你来啦,周宁", "欢迎回来", "最近还好吗,周宁?"];
const firstVisit = new Set(Array.from({ length: 100 }, (_, step) =>
createStartGreetingParts("周宁", evening, step / 100, false).text));