feat(consult): sections presuppose nothing, examples carry no reading rule or job shape, corrections are acknowledged
- natalAnswerShapeBody: NATAL_SECTION_RULE replaces 「这个人是什么样、你们怎么相处、 事情会怎么走」; the shared voice quotes the same constant (BUG-1164) - product-voice / VOICE.md: no 逆行 in examples, parents example leads with the affliction and asks to confirm, married-presupposing Good example removed (BUG-1165) - follow-up shape: a user correction is acknowledged, never defended (BUG-1166) - career examples carry no job shape (升职 / 专业能力 / 做深现有工作) (BUG-1168) - biography backtest golden regenerated with the real engine so the card carries brief 1's aspects, combustion, yoga domains and saturn_from_moon_house; backtest script gains --correction follow-up turns 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:
co-authored by
Claude Opus 5.5
parent
585c7370f8
commit
955bab691a
+13
-9
@@ -251,7 +251,7 @@ Jyotisha 的可见文案是产品的一部分。正确性红线(真实性、
|
||||
4. **同一约束换着说。** 边界句必须在交付/采用轮完整出现一次;中间轮不要逐字复读法务稿。
|
||||
5. **口语化但不轻佻。** 短句、具体事实、少套话。
|
||||
6. **希望纪律。** 占星结果是客观的,表达是主观的。不顺就说不顺,但每次都要说清这段时间能做什么。盘上确有转机、且 `answer_policy.can_answer_precise_timing` 允许精确应期时,把转机说到月份(哪颗星换宫、哪段大运交接);不允许精确应期、或这一段确实没有转机时,说清这段时间是拿来干什么的(攒、守、清账、练手),不编月份。不是每个人都有转机,但每个人这段时间都有能做的事。不写「一切都会好」「相信自己」「加油」「你值得更好的」「宇宙自有安排」。(2026-10-01 起不再用「扮演哪个象」的说法,TASK-consult-plain-answer-20261001 D5。)
|
||||
7. **回答形状:先答,再按对象分段(2026-10-01,BUG-1132,推翻 2026-09-17 的四步开场形状)。** 三种模式(本命 / 无出生分钟 / 申报时段)共用,**不设字数上限,讲清楚为准**,同一件事只说一遍。① **先答**——开场一到三句人话,第一句就是结论,不写标题、不写行动,不给这件事起名字;② **按对象分段**——问题里点到几个人或几个子问题(妈妈、爸爸、他们怎么对我、什么时候),开场之后每个各写一段,二级标题用问题里的词(`## 你和妈妈`、`## 你和爸爸`、`## 他们怎么对你`);问父母时妈妈和爸爸分开写;只问一个人或一件事时不拆段;③ **每段先人话、后依据**——先讲清楚这个人是什么样、你们怎么相处、事情会怎么走,再在括号里给撑住这段判断的盘上依据(宫、宫主、代表星、分盘、大运);问的是别人时写那个人在你盘上对应的宫位与代表星说明了什么,不写那个人的心思(BUG-1070 的目的保留);④ **行动**——一到三条破折号短句,本命解读里只在最后一节出现一次。<br>**人话自检**:把每句话括号里的内容删掉,一个完全不懂占星的人仍能看懂。禁止自造格局名或四字概括(「外X内Y」一类);禁止把大运、行运写成拟人的角色(「推这一段的是……」「修形式的是……」「交给……收尾」)和「去当某颗星的某种样子」的角色修辞;禁止把星名当形容词的主人(「土星的冷」);括号外每段最多一个占星术语,第一次出现时用白话套住(「现在这十年(月亮大运)」)。**推断边界**:空宫不单独下结论,要说它的宫主落在哪、什么状态(BUG-1134)。<br>降级路线(形状照给,只换依据):**申报时段**依据只取窗口内稳定的那一层(行星落座、公开日历),上升、宫位、大运、分盘不作依据,不写月份;**无出生分钟**时间只讲公开日历这一天的大势,不点个人大运、不写月份。<br>为什么推翻:09-17 的四步形状(反差格局名 → 动力层 / 形式层 → 应哪个象 → 行动)来自一段单对象、单时段的流年范文;强制用在所有问题上后,模型逐格填空写出术语叠术语的谜语,问父母时爸妈被揉成一段。
|
||||
7. **回答形状:先答,再按对象分段(2026-10-01,BUG-1132,推翻 2026-09-17 的四步开场形状)。** 三种模式(本命 / 无出生分钟 / 申报时段)共用,**不设字数上限,讲清楚为准**,同一件事只说一遍。① **先答**——开场一到三句人话,第一句就是结论,不写标题、不写行动,不给这件事起名字;② **按对象分段**——问题里点到几个人或几个子问题(妈妈、爸爸、他们怎么对我、什么时候),开场之后每个各写一段,二级标题用问题里的词(`## 你和妈妈`、`## 你和爸爸`、`## 他们怎么对你`);问父母时妈妈和爸爸分开写;只问一个人或一件事时不拆段;③ **每段先说最强的信号、后依据**(2026-10-01 BUG-1164 改,取代「这个人是什么样、你们怎么相处、事情会怎么走」)——先说盘上最强的一两个信号说明了什么,包括这个人在不在你身边、近不近;盘上没有依据的方面不写,不用日常场景凑段落;受冲信号两个及以上时这一段第一句就写这一面,用「可能」,段末一句请用户确认(「如果实际情况不是这样,告诉我,我按真实情况重看。」),全篇最多一处;**不预设处境**:有没有伴侣、是否已婚、是否在上班、做哪类工作、孩子性别、父母是否在身边都不预设,性别未知时不用「他」「她」称伴侣和孩子;再在括号里给撑住这段判断的盘上依据(宫、宫主、代表星、分盘、大运);问的是别人时写那个人在你盘上对应的宫位与代表星说明了什么,不写那个人的心思(BUG-1070 的目的保留);④ **行动**——一到三条破折号短句,本命解读里只在最后一节出现一次。<br>**人话自检**:把每句话括号里的内容删掉,一个完全不懂占星的人仍能看懂。禁止自造格局名或四字概括(「外X内Y」一类);禁止把大运、行运写成拟人的角色(「推这一段的是……」「修形式的是……」「交给……收尾」)和「去当某颗星的某种样子」的角色修辞;禁止把星名当形容词的主人(「土星的冷」);括号外每段最多一个占星术语,第一次出现时用白话套住(「现在这十年(月亮大运)」)。**推断边界**:空宫不单独下结论,要说它的宫主落在哪、什么状态(BUG-1134)。<br>降级路线(形状照给,只换依据):**申报时段**依据只取窗口内稳定的那一层(行星落座、公开日历),上升、宫位、大运、分盘不作依据,不写月份;**无出生分钟**时间只讲公开日历这一天的大势,不点个人大运、不写月份。<br>为什么推翻:09-17 的四步形状(反差格局名 → 动力层 / 形式层 → 应哪个象 → 行动)来自一段单对象、单时段的流年范文;强制用在所有问题上后,模型逐格填空写出术语叠术语的谜语,问父母时爸妈被揉成一段。
|
||||
|
||||
## 好 / 坏对照
|
||||
|
||||
@@ -312,8 +312,8 @@ Jyotisha 的可见文案是产品的一部分。正确性红线(真实性、
|
||||
| (校正会话上普通输入框仍可打字) | 正在打开生时校正… | 校正会话上普通输入框只有禁用态。打开失败时按钮写「重新打开生时校正」。 |
|
||||
| 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 月木星换宫之前,机会多但不稳;之后再谈升职更有把握。 | 坏的那句像顾问报告:只有结论,没有盘上依据。好的那段先答、再给依据和时间,每句删掉括号后都看得懂(盘上数据是示意)。 |
|
||||
| (用户说「你在说什么鬼」)抱歉让你困惑了,我再解释一下:从星盘来看,您的事业宫…… | 说直接点:这份工作还值得留,但你得换个位置,不是换公司。哪句没看懂,指给我。 | 追问轮不重开一遍报告,也不道歉铺垫。一句白话结论 + 一句把球踢回去。 |
|
||||
| 你更适合长期做一件事,而不是频繁换方向。眼下更值得把手上的事做稳,而不是立刻另起一摊。 | 今年事业上机会不少,但真正决定你走多远的是规矩和身体,不是人缘。<br>## 盘上依据<br>机会和帮你的人今年都在;同时事情多、要求严,身体也容易被拖累。(木星行运 10 宫;土星行运 6 宫)<br>## 时间怎么看<br>9 月木星换宫之前,机会多但不稳;之后再定大的方向更有把握。 | 坏的那句像顾问报告:只有结论,没有盘上依据。好的那段先答、再给依据和时间,每句删掉括号后都看得懂(括号里是依据的占位)。2026-10-01(BUG-1168)起事业示例不带职业形态:不写「升职」「专业能力」「做深现有工作」,旧示例让 18 份事业回测答案里 16 份把总统、球星、影星都写成「专业型 / 顾问 / 幕后」。 |
|
||||
| (用户说「你在说什么鬼」)抱歉让你困惑了,我再解释一下:从星盘来看,您的事业宫…… | 说直接点:现在这条路还值得走,但你得换个走法,不是换方向。哪句没看懂,指给我。 | 追问轮不重开一遍报告,也不道歉铺垫。一句白话结论 + 一句把球踢回去。 |
|
||||
|
||||
## 服务端探针 → Agent 题干
|
||||
|
||||
@@ -401,15 +401,19 @@ Jyotisha 的可见文案是产品的一部分。正确性红线(真实性、
|
||||
|
||||
**追问轮直接回答(2026-09-27,BUG-1071,D3;2026-10-01 取消字数上限)。** 本会话已经有过一轮解读之后,后面的问题按直接回答写:第一句回答问的那句话(是非题先答是 / 不是 / 看情况),讲清楚为准、不限字数,只引与这句话直接相关的盘面事实(够说明就停),不写二级标题、不写行动清单、不重述上一轮已经写过的结构。只有用户明确换了领域或要求「完整看一下」才回到完整形状。「追问轮」由服务端按「本会话已有回答」判定,不用正则猜用户意图(BUG-976/977 口径)。
|
||||
|
||||
| 坏 | 好 | 为什么 |
|
||||
|---|---|---|
|
||||
| (用户问「我妈是不是不太在意我」)你其实要的是被听见,她给的是安排;你是否需要的是一种被看见的方式…… | 不是。4 宫主水星逆行落 10 宫,她把心力投在你的前途上——不是不在意,是不会用你想要的方式在意。 | 是非题第一句答是 / 不是;依据是宫位,不是读心;不把问题改写成需求。 |
|
||||
| (首轮)开场三条行动 + `## 先回答你的问题` 再答一遍 + 表格再列一遍 + `## 这周可以做的一件事` 再给三条 | 开场(第一句就是结论)→ 按对象分段 → `## 盘上依据`(只写新依据)→ `## 时间怎么看` → `## 这周可以做的一件事`(三条,一次) | 同一判断只说一遍,行动只给一遍。 |
|
||||
| (问「我和父母关系如何」)你和父母是「外热内冷」:推着这段关系的是金星大运,土星子运负责收尾;别去应火星的「硬」,去当金星的「和」。(改写示意) | 你和父母不疏远,但亲近主要落在「为你的前途操心」上。<br>## 你和妈妈<br>她对你的事很上心,但常把关心说成提醒和安排。(4 宫母亲宫的宫主落在 10 宫事业宫)<br>## 你和爸爸<br>……<br>## 他们怎么对你<br>…… | 坏的那句自造格局名、大运写成角色、星名当形容词,爸妈揉成一段,不懂占星的人一句也看不懂(BUG-1132)。
|
||||
**用户纠正盘上判断(2026-10-01,BUG-1166)。** 用户说「我爸其实没怎么管过我」这类话时,追问轮先认下这件事,再说盘上哪几条和它对得上、原来哪句读偏了;不为原判断辩护,不写「盘上显示你们关系不错」。
|
||||
|
||||
**示例只演示口气与结构(2026-10-01,BUG-1165 / BUG-1168)。** 提示词和本文件里的示例,括号里的盘面依据只用不带读法含义的占位(「(4 宫主落 10 宫)」可以,「逆行 → 反复」不可以);示例不预设读者的处境(已婚、在上班、做专业工作、父母在身边)。模型会把示例里的读法和处境当规则照抄。
|
||||
|
||||
| 坏 | 好 | 为什么 |
|
||||
|---|---|---|
|
||||
| 你的事业宫在第十宫,D10 上升与本命一致。当前大运土星、副运木星,从度数上看今明两年有岗位变动的窗口。下面进入统一参数与原始结构。 | 今年工作上机会不少,但真正决定你走多远的是规矩和身体,不是人缘。<br>- 口头答应的事,补一份书面确认。 | 先回人问的方向,再按形状展开;度数留在依据里。要点不是公文枚举。 |
|
||||
| (用户问「我妈是不是不太在意我」)你其实要的是被听见,她给的是安排;你是否需要的是一种被看见的方式…… | 不是。(4 宫主落 10 宫)她把心力放在你的前途上——不是不在意,是不会用你想要的方式在意。 | 是非题第一句答是 / 不是;依据是宫位,不是读心;不把问题改写成需求。2026-10-01(BUG-1165)起示例括号只放依据占位,不带读法:旧示例「宫主水星逆行」被模型抄成「逆行 = 反复、打回来」。 |
|
||||
| (首轮)开场三条行动 + `## 先回答你的问题` 再答一遍 + 表格再列一遍 + `## 这周可以做的一件事` 再给三条 | 开场(第一句就是结论)→ 按对象分段 → `## 盘上依据`(只写新依据)→ `## 时间怎么看` → `## 这周可以做的一件事`(三条,一次) | 同一判断只说一遍,行动只给一遍。 |
|
||||
| (问「我和父母关系如何」)你和父母是「外热内冷」:推着这段关系的是金星大运,土星子运负责收尾;别去应火星的「硬」,去当金星的「和」。(改写示意) | 你和妈妈这条线近;爸爸这一面盘上受冲多,他可能不常在你身边。<br>## 你和妈妈<br>她离你近,对你的事上心。(4 宫主落 10 宫)<br>## 你和爸爸<br>爸爸这一面可能比较远:他可能不常在你身边。如果实际情况不是这样,告诉我,我按真实情况重看。(9 宫与太阳这一组的两条受冲)<br>## 他们怎么对你<br>…… | 坏的那句自造格局名、大运写成角色、星名当形容词,爸妈揉成一段,不懂占星的人一句也看不懂(BUG-1132)。
|
||||
|
||||
| 坏 | 好 | 为什么 |
|
||||
|---|---|---|
|
||||
| 你的事业宫在第十宫,D10 上升与本命一致。当前大运土星、副运木星,从度数上看今明两年有岗位变动的窗口。下面进入统一参数与原始结构。 | 今年事业上机会不少,但真正决定你走多远的是规矩和身体,不是人缘。<br>- 口头答应的事,补一份书面确认。 | 先回人问的方向,再按形状展开;度数留在依据里。要点不是公文枚举。 |
|
||||
| 事业、财富、变动窗口、土星大运 | 现在这十年(土星大运)偏向慢慢攒、靠规矩立住。 | 句子是完整句子,不是公文枚举;术语第一次出现用白话套住。 |
|
||||
|
||||
## 今日星语句库(2026-09-30,BUG-1109)
|
||||
|
||||
@@ -28,9 +28,14 @@
|
||||
* DS_KEY=... ./node_modules/.bin/tsx scripts/research/consult-biography-backtest.mts \
|
||||
* [--out <dir>] [--repeats 2] [--figures a,b] [--domains parents,marriage,health,career] \
|
||||
* [--model deepseek-flash] [--base-url https://api.deepseek.com] [--concurrency 4] [--dump-cards]
|
||||
* [--correction barack_obama,marilyn_monroe] [--correction-text 我爸其实没怎么管过我]
|
||||
*
|
||||
* --dump-cards writes the model-visible tool result per figure x domain and
|
||||
* calls no model. --recheck <dir> re-runs the deterministic checks of an
|
||||
* calls no model. --correction adds, for each listed figure's parents answer,
|
||||
* one follow-up turn in the same session (history = that question and answer)
|
||||
* with --correction-text (T3 / D4 of the task brief); those answers are written
|
||||
* as parents-correction-run<N>.md and listed in the summary for reading.
|
||||
* --recheck <dir> re-runs the deterministic checks of an
|
||||
* earlier run against the current rubric and rewrites its summary. The key is read from DS_KEY (or BACKTEST_MODEL_KEY) only and
|
||||
* is never written anywhere. Output defaults to <repo>/scratch/ (gitignored);
|
||||
* only the summary may be quoted into docs.
|
||||
@@ -74,7 +79,7 @@ export const GAPS = [
|
||||
"引擎调用换成 golden(同 capture 路径、raman 岁差、mean 交点、参考日 2026-09-27);产品用用户档案的岁差设置。",
|
||||
"用户回合不带「用户称呼」:真实路由会带档案名,这里故意不给名人名字,免得模型凭记忆答生平。",
|
||||
"natalToolInstruction 一句与 currentTimeContext 是 route.ts 内部函数,未导出,脚本里按原文复刻(见 routeToolInstruction / routeCurrentTime)。",
|
||||
"没有内容审核(moderateOutput)、计费、标题旁路事件、历史摘要;单轮、无历史。",
|
||||
"没有内容审核(moderateOutput)、计费、标题旁路事件、历史摘要;主回测单轮、无历史;--correction 纠正追问轮的历史只有上一问一答。",
|
||||
"性别一律按档案未填(性别未知)处理。",
|
||||
"模型经 Mastra 的 OpenAI 兼容通道直连 DeepSeek(model id 由参数给),不经产品数据库的模型目录。",
|
||||
] as const;
|
||||
@@ -123,6 +128,8 @@ function parseArgs(argv: readonly string[]) {
|
||||
concurrency: Math.max(1, Number(value("concurrency") ?? 4)),
|
||||
dumpCards: argv.includes("--dump-cards"),
|
||||
recheck: value("recheck"),
|
||||
correction: value("correction")?.split(",").filter(Boolean) ?? [],
|
||||
correctionText: value("correction-text") ?? "我爸其实没怎么管过我",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -229,7 +236,9 @@ function model(args: ReturnType<typeof parseArgs>, apiKey: string): ResolvedLang
|
||||
};
|
||||
}
|
||||
|
||||
type Job = { figure: GoldenFigure; domain: string; question: string; run: number };
|
||||
/** A follow-up turn in the same session: the earlier question and answer are the history. */
|
||||
type FollowUp = { priorQuestion: string; priorAnswer: string };
|
||||
type Job = { figure: GoldenFigure; domain: string; question: string; run: number; followUp?: FollowUp };
|
||||
|
||||
type Usage = { inputTokens?: number; outputTokens?: number; reasoningTokens?: number; cachedInputTokens?: number };
|
||||
|
||||
@@ -249,17 +258,27 @@ function agentContext(job: Job, state: ConsultationRuntimeState, executed: strin
|
||||
consultationMode: "verified_chart",
|
||||
plan: createConsultationPlan({ userIntent: job.question, theme: job.domain as ConsultationDomain }),
|
||||
theme: job.domain as ConsultationDomain,
|
||||
followUpTurn: false,
|
||||
followUpTurn: Boolean(job.followUp),
|
||||
serverChart: serverChart(job.figure),
|
||||
state,
|
||||
runWorkflow: stubRunWorkflow(job.figure, executed) as never,
|
||||
});
|
||||
}
|
||||
|
||||
function userTurn(question: string) {
|
||||
function historyOf(followUp: FollowUp | undefined) {
|
||||
return followUp
|
||||
? [
|
||||
{ role: "user" as const, text: followUp.priorQuestion },
|
||||
{ role: "assistant" as const, text: followUp.priorAnswer },
|
||||
]
|
||||
: [];
|
||||
}
|
||||
|
||||
function userTurn(question: string, followUp?: FollowUp) {
|
||||
return consultationUserTurnContent({
|
||||
currentTime: routeCurrentTime(REQUEST_TIME),
|
||||
instruction: `${routeToolInstruction}${natalUserTurnShape({ history: [] })}`,
|
||||
// natalUserTurnShape reads the stored history, as route.ts does: a prior answer -> follow-up shape.
|
||||
instruction: `${routeToolInstruction}${natalUserTurnShape({ history: historyOf(followUp) })}`,
|
||||
question,
|
||||
});
|
||||
}
|
||||
@@ -270,7 +289,11 @@ async function runJob(job: Job, resolved: ResolvedLanguageModel) {
|
||||
const ctx = agentContext(job, state, executed);
|
||||
const agent = getJyotishAgent(resolved, ctx);
|
||||
const runId = ctx.requestId;
|
||||
const baseMessages = [{ role: "user" as const, content: userTurn(job.question) }];
|
||||
// route.ts consultationBaseMessages: stored history as plain messages, then this turn.
|
||||
const baseMessages = [
|
||||
...historyOf(job.followUp).map((message) => ({ role: message.role, content: message.text })),
|
||||
{ role: "user" as const, content: userTurn(job.question, job.followUp) },
|
||||
];
|
||||
const streamOptions = {
|
||||
runId,
|
||||
maxSteps: AGENT_MAX_STEPS,
|
||||
@@ -518,8 +541,41 @@ async function main() {
|
||||
console.log(`${job.figure.id} ${job.domain} run${job.run}: ${result.output.length} chars, ${result.seconds.toFixed(0)} s${result.failure ? `, FAILED ${result.failure}` : ""}`);
|
||||
return { figure: job.figure.id, domain: job.domain, run: job.run, chars: result.output.length, ...result, output: undefined, checks };
|
||||
});
|
||||
const corrections = await pool(
|
||||
jobs.filter((job) => job.domain === "parents" && args.correction.includes(job.figure.id)),
|
||||
args.concurrency,
|
||||
async (prior) => {
|
||||
const priorFile = join(args.out, prior.figure.id, `parents-run${prior.run}.md`);
|
||||
const priorText = readFileSync(priorFile, "utf8");
|
||||
const priorAnswer = priorText.slice(priorText.indexOf("\n---\n\n") + 6).trim();
|
||||
const job: Job = { ...prior, question: args.correctionText, followUp: { priorQuestion: prior.question, priorAnswer } };
|
||||
let result: Awaited<ReturnType<typeof runJob>>;
|
||||
try {
|
||||
result = await runJob(job, resolved);
|
||||
} catch (error) {
|
||||
result = { output: "", failure: error instanceof Error ? error.message : String(error), executed: [], seconds: 0, usage: {}, cardChars: null, visibleChars: null, methodologySections: 0, lookups: 0, finish: null };
|
||||
}
|
||||
const file = join(args.out, job.figure.id, `parents-correction-run${job.run}.md`);
|
||||
writeFileSync(file, [
|
||||
`# ${job.figure.label} · parents 纠正追问 · run ${job.run}`,
|
||||
"",
|
||||
`- 上一轮:${priorFile}`,
|
||||
`- 追问:${job.question}`,
|
||||
`- 模型:${args.model};用时 ${result.seconds.toFixed(1)} s;结束:${result.finish ?? "?"};查卡 ${result.lookups} 次`,
|
||||
`- 用量:${JSON.stringify(result.usage)}`,
|
||||
...(result.failure ? [`- 失败:${result.failure}`] : []),
|
||||
"",
|
||||
"---",
|
||||
"",
|
||||
result.output || "(无回答)",
|
||||
"",
|
||||
].join("\n"));
|
||||
console.log(`${job.figure.id} parents correction run${job.run}: ${result.output.length} chars, ${result.seconds.toFixed(0)} s${result.failure ? `, FAILED ${result.failure}` : ""}`);
|
||||
return { figure: job.figure.id, run: job.run, chars: result.output.length, seconds: result.seconds, failure: result.failure, usage: result.usage };
|
||||
},
|
||||
);
|
||||
const total: Usage = {};
|
||||
for (const row of rows) addUsage(total, row.usage);
|
||||
for (const row of [...rows, ...corrections]) addUsage(total, row.usage);
|
||||
const summary = {
|
||||
model: args.model,
|
||||
started_at: new Date(started).toISOString(),
|
||||
@@ -529,6 +585,7 @@ async function main() {
|
||||
usage: total,
|
||||
gaps: GAPS,
|
||||
rows,
|
||||
corrections,
|
||||
};
|
||||
writeSummary(args.out, summary as unknown as Json & { rows: Row[] }, args.model);
|
||||
console.log(`summary: ${join(args.out, "summary.md")}`);
|
||||
|
||||
@@ -371,6 +371,14 @@ export function consultationContinuePrompt(output: string): string {
|
||||
*/
|
||||
const ANSWER_FROM_EVIDENCE = "拿到本轮计算结果后直接写给用户的回答,只用结果里的盘面事实下判断;调用工具前后都不要写过程说明。";
|
||||
|
||||
/**
|
||||
* What each per-person section says (TASK-consult-no-presupposition-and-
|
||||
* backtest-20261001 D1/D2/D7, BUG-1164; replaces 「这个人是什么样、你们怎么
|
||||
* 相处、事情会怎么走」, which presupposed the person is there and in daily
|
||||
* contact). Defined here once; the shared voice quotes this constant.
|
||||
*/
|
||||
export const NATAL_SECTION_RULE = "每段先说盘上最强的一两个信号说明了什么,包括这个人在不在你身边、近不近;盘上没有依据的方面不写,不用日常场景凑段落。受冲信号两个及以上时,这一段第一句就写这一面,用「可能」,段末用一句话请用户确认(例:「如果实际情况不是这样,告诉我,我按真实情况重看。」),全篇这类确认最多一处。不预设有没有伴侣、是否已婚、是否在上班、做哪类工作、孩子性别、父母是否在身边;性别未知时不用「他」「她」称伴侣和孩子。";
|
||||
|
||||
/**
|
||||
* Natal first-turn shape in the user turn (VOICE §7; TASK-consult-plain-
|
||||
* answer-20261001 D2–D4/D8): plain opener, one section per person or
|
||||
@@ -381,7 +389,7 @@ export function natalAnswerShapeBody(): string {
|
||||
return [
|
||||
"开场不要标题,先用一到三句人话回答问题,第一句就是结论;不给这件事起名字,开场不写行动清单。",
|
||||
"问题里点到几个人或几个子问题(比如妈妈、爸爸、他们怎么对我),开场之后每个各写一段,二级标题用问题里的词(例:## 你和妈妈、## 你和爸爸、## 他们怎么对你);问父母时妈妈和爸爸分开写。只问一个人或一件事时不拆段。",
|
||||
"每段先用人话讲清楚这个人是什么样、你们怎么相处、事情会怎么走,再在括号里给撑住这段判断的盘上依据。",
|
||||
`${NATAL_SECTION_RULE}每段的判断后在括号里给撑住它的盘上依据。`,
|
||||
`然后依次写:## ${REPORT_HEADING.support}(只写上面没引过、判断又需要的依据,表格与正文二选一;没有新依据就省掉这一节)、## ${REPORT_HEADING.timing}(卡里没有相关大运或行运就省掉)、## ${REPORT_HEADING.action}(一到三条行动,只在这里出现一次)。`,
|
||||
"不限字数,讲清楚为准;同一件事只说一遍。",
|
||||
"把每句话括号里的内容删掉,不懂占星的人也要能看懂:不起「外X内Y」这类格局名,不把大运写成推着或收尾的角色,不写「去当某颗星的样子」,不把星名当形容词的主人;空宫不单独下结论,要说它的宫主落在哪。名词只用中文、全篇一个叫法(罗睺、计都;大运、子运、小运),不写英文或梵文音译(sade sati、vargottama、rupas 之类),力量只说强、中、弱。",
|
||||
@@ -393,6 +401,9 @@ export function natalAnswerShapeInstruction(): string {
|
||||
return `${ANSWER_FROM_EVIDENCE}${natalAnswerShapeBody()}`;
|
||||
}
|
||||
|
||||
/** D4 / BUG-1166: the user corrects an earlier reading; acknowledge it, never defend the reading. */
|
||||
export const FOLLOW_UP_CORRECTION_RULE = "用户纠正了前面的判断(比如说父亲其实不常在身边):先认下这件事,再说盘上哪几条和它对得上、原来哪句读偏了;不为原判断辩护。";
|
||||
|
||||
/**
|
||||
* Follow-up turn shape (TASK-consult-answer-the-question-20260927 D3 /
|
||||
* BUG-1071): the session already holds a natal answer, so this turn answers
|
||||
@@ -405,6 +416,7 @@ export function followUpAnswerShapeInstruction(): string {
|
||||
return [
|
||||
ANSWER_FROM_EVIDENCE,
|
||||
"这是追问轮:本会话前面已经写过完整解读。第一句就回答用户这句话(是非题先答「是」「不是」或「看情况:……」,再给盘上的依据),讲清楚为准,不限字数;只引与这句话直接相关的盘面事实,够说明就停;用人话说,盘上依据放括号里;名词只用中文、不写英文或梵文音译;不写二级标题,不写行动清单(用户问了才给);不重述上一轮已经写过的结构;不解释用户为什么问,不替用户说他想要什么。",
|
||||
FOLLOW_UP_CORRECTION_RULE,
|
||||
`只有用户明确换了领域或要求完整看一下,才回到完整形状:口语开场、按对象分段,再接二级标题(## ${REPORT_HEADING.support}、## ${REPORT_HEADING.timing}、## ${REPORT_HEADING.action})。`,
|
||||
"不要写「统一参数与原始结构」,不要写技法审计表,不要写思考过程清单,不要复述内部 JSON 字段。",
|
||||
].join("");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { NATAL_ANSWER_SHAPE_SUMMARY, REPORT_HEADING } from "../lib/consultation-thinking-plan.ts";
|
||||
import { NATAL_ANSWER_SHAPE_SUMMARY, NATAL_SECTION_RULE, REPORT_HEADING } from "../lib/consultation-thinking-plan.ts";
|
||||
|
||||
export const productConversationVoice = `VISIBLE VOICE
|
||||
PERSONA: 把对面的人当一个人认真对待——不是工单,不是要被安抚的情绪,不是一张等着填完的表。你不是只会点头的工具人,更像他身边一个行动力很强、嘴有点毒但靠谱的同事:给你一个问题,你自己找路、自己补信息、把脏活干完,把结论丢回他面前。
|
||||
@@ -25,7 +25,7 @@ ANSWER SHAPE (natal / general / declared-window 三种模式共用)
|
||||
不设字数上限,讲清楚为准。同一件事只说一遍;不为显得周全写问题用不到的盘面事实。
|
||||
1. 先答:开场一到三句人话,第一句就是结论,回答用户问的那句话。开场不写标题、不写行动,不给这件事起名字。
|
||||
2. 按对象分段:问题里点到几个对象(妈妈、爸爸、伴侣、老板、孩子……)或几个子问题(关系如何、他们怎么对我、什么时候),开场之后每个各写一段,二级标题用问题里的词(例:## 你和妈妈、## 你和爸爸、## 他们怎么对你)。问「父母」时妈妈和爸爸分开写,不揉成一段。只有一个对象、一个子问题时不拆段。
|
||||
3. 每段先用人话讲清楚:这个人是什么样、你们怎么相处、事情会怎么走,写到讲清楚为止;然后在括号里给出撑住这段判断的盘上依据(宫、宫主、代表星、分盘、大运),够用就停。问的是别人时,写那个人在你盘上对应的宫位与代表星说明了什么,不写那个人的心思。
|
||||
3. ${NATAL_SECTION_RULE}写到讲清楚为止;然后在括号里给出撑住这段判断的盘上依据(宫、宫主、代表星、分盘、大运),够用就停。问的是别人时,写那个人在你盘上对应的宫位与代表星说明了什么,不写那个人的心思。
|
||||
4. 行动:一到三条破折号短句,做完就能看到改变。本命解读里只写在最后一节「这周可以做的一件事」,出现一次;无出生分钟与申报时段没有正文骨架,行动就写在回答结尾。
|
||||
人话自检:把每句话括号里的内容删掉,一个完全不懂占星的人仍然能看懂它在说什么;做不到就重写这句。禁止:
|
||||
- 自造格局名、四字概括(「外X内Y」这一类);
|
||||
@@ -38,41 +38,39 @@ ANSWER SHAPE (natal / general / declared-window 三种模式共用)
|
||||
- 申报时段(declared birth window):依据只取窗口内稳定的那一层——行星落座、公开日历;上升、宫位、大运、分盘不作依据,也不写月份。
|
||||
- 无出生分钟(no birth minute):时间只讲公开日历这一天的大势,不点个人大运,不写月份;能做的事取自公开日历,不取自个人盘。
|
||||
|
||||
Good (父母题首轮,按对象分段;盘上数据是示意):
|
||||
你和父母不疏远,但亲近主要落在「为你的前途操心」上,聊心事的时候少。妈妈管得细、操心多;爸爸话少,关心靠做事来表达。
|
||||
Good (父母题首轮,按对象分段;括号里是依据的占位,只演示口气与结构,不是读法):
|
||||
你和妈妈这条线近、来往多;爸爸这一面盘上受冲多,他可能不常在你身边。
|
||||
## 你和妈妈
|
||||
她对你的事很上心,但常把关心说成提醒和安排,所以你们聊工作、聊打算的时候多,聊感受的时候少。(4 宫母亲宫的宫主水星落在 10 宫事业宫;代表母亲的月亮也在 10 宫)
|
||||
她离你近,对你的事上心,你们之间来往多。(4 宫主落 10 宫;月亮在 10 宫)
|
||||
## 你和爸爸
|
||||
他在你心里分量重,是你做事的标杆;他不太会说软话,你们之间更像互相看着对方做事。(代表父亲的太阳在 10 宫;9 宫父亲宫的宫主木星落 12 宫,他的心力有一部分在远处或在自己的事上)
|
||||
爸爸这一面可能比较远:他可能不常在你身边,或者有一段时间不在。如果实际情况不是这样,告诉我,我按真实情况重看。(9 宫与太阳这一组的两条受冲)
|
||||
## 他们怎么对你
|
||||
两个人对你都是期望多于宠,要求不少,但出发点是想让你立得住。
|
||||
两边给你的不一样:妈妈这一头给得多,爸爸这一头给得少。
|
||||
## 时间怎么看
|
||||
现在这十年(月亮大运,到 2034 年 2 月)和妈妈的来往会比以前多,家里的事更容易落到你身上。
|
||||
现在这十年(月亮大运,到 2034 年 2 月)和妈妈的来往会比以前多。
|
||||
## 这周可以做的一件事
|
||||
- 给妈妈打电话时先问她最近怎样,再说你自己的事。
|
||||
- 有决定要做时,先听听爸爸的意见,哪怕最后不照做。
|
||||
|
||||
Good (单对象事业题首轮,不拆段;盘上数据是示意):
|
||||
今年工作上机会不少,但真正决定你走多远的是规矩和身体,不是人缘。
|
||||
Good (单对象事业题首轮,不拆段;括号里是依据的占位,只演示口气与结构,不是读法;不预设读者在上班、做哪类工作):
|
||||
今年事业上机会不少,但真正决定你走多远的是规矩和身体,不是人缘。
|
||||
## 盘上依据
|
||||
木星今年走过你的事业宫,机会和帮你的人都在(木星行运 10 宫);同时土星压在你的工作宫,事情多、要求严,身体也容易被拖累(土星行运 6 宫)。
|
||||
机会和帮你的人今年都在;同时事情多、要求严,身体也容易被拖累。(木星行运 10 宫;土星行运 6 宫)
|
||||
## 时间怎么看
|
||||
9 月木星换宫之前,机会多但不稳;之后再谈升职更有把握。
|
||||
9 月木星换宫之前,机会多但不稳;之后再定大的方向更有把握。
|
||||
## 这周可以做的一件事
|
||||
- 口头答应的事,补一份书面确认。
|
||||
- 身体的小毛病这周就去看。
|
||||
|
||||
Bad (多对象题,改写示意): 你和父母是「外热内冷」:推着这段关系的是金星大运,土星子运负责收尾;别去应火星的「硬」,去当金星的「和」。(自造格局名、大运写成角色、星名当形容词,爸妈揉成一段;括号外没有一句不懂占星的人能看懂。)
|
||||
|
||||
Good (追问轮,用户说「你在说什么鬼」): 说直接点:这份工作还值得留,但你得换个位置,不是换公司。哪句没看懂,指给我。
|
||||
Good (追问轮,用户说「你在说什么鬼」): 说直接点:现在这条路还值得走,但你得换个走法,不是换方向。哪句没看懂,指给我。
|
||||
|
||||
Good (是非题,用户问「我妈是不是不太在意我」,盘上数据是示意): 不是。4 宫主水星逆行落 10 宫,她把心力投在你的前途上——不是不在意,是不会用你想要的方式在意。
|
||||
Good (是非题,用户问「我妈是不是不太在意我」,括号里是依据的占位): 不是。(4 宫主落 10 宫)她把心力放在你的前途上——不是不在意,是不会用你想要的方式在意。
|
||||
Bad (同一问题): 你其实要的是被听见,她给的是安排;你是否需要的是一种被看见的方式……(替用户说动机,把是非题改写成需求题,第一句没有答「是」还是「不是」。)
|
||||
|
||||
Good: 你这段婚姻更像先把已经在一起的关系过稳,而不是立刻再开一段。眼下更值得把相处里反复出现的摩擦说清楚。
|
||||
Bad: opening a natal answer with infrastructure, 根据当前计算结果, or a degrees table before answering what the person asked.
|
||||
|
||||
Bad: 你更适合把已经积累的专业能力做成长期事业,而不是频繁换赛道。眼下更值得把现有工作做深,而不是立刻另起一摊。(像顾问报告:只有结论,没有盘上依据,读者不知道凭什么这样说。)
|
||||
Bad: 你更适合长期做一件事,而不是频繁换方向。眼下更值得把手上的事做稳,而不是立刻另起一摊。(像顾问报告:只有结论,没有盘上依据,读者不知道凭什么这样说。)
|
||||
Bad: 根据当前计算结果,事业方向总体偏稳定,但副运细节与行运触发未在本轮完整计算。
|
||||
|
||||
Never open with 根据系统计算, 根据当前计算结果, 综合来看, 需要指出的是, 当前状态为, 本轮未完整计算, or 从星盘来看. Never quote JSON keys, English status codes, or field names (core_status, blocked, ready, consumer_context, missing_layers, omitted_domains). Never dump YAML or raw JSON.`;
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
// TASK-consult-no-presupposition-and-backtest-20261001 T1–T3 (BUG-1164~1166, BUG-1168).
|
||||
// The section rule no longer presupposes the person is there; examples carry no
|
||||
// reading rule and no job shape; a correction turn acknowledges, never defends.
|
||||
import assert from "node:assert/strict";
|
||||
import { readdirSync, readFileSync } from "node:fs";
|
||||
import test from "node:test";
|
||||
|
||||
import {
|
||||
FOLLOW_UP_CORRECTION_RULE,
|
||||
NATAL_SECTION_RULE,
|
||||
followUpAnswerShapeInstruction,
|
||||
natalAnswerShapeBody,
|
||||
natalAnswerShapeInstruction,
|
||||
} from "../src/lib/consultation-thinking-plan.ts";
|
||||
import { productConversationVoice } from "../src/mastra/product-voice.ts";
|
||||
|
||||
const OLD_SECTION_RULE = /这个人是什么样、你们怎么相处、事情会怎么走/;
|
||||
|
||||
const SECTION_RULE_TEXT = "每段先说盘上最强的一两个信号说明了什么,包括这个人在不在你身边、近不近;盘上没有依据的方面不写,不用日常场景凑段落。受冲信号两个及以上时,这一段第一句就写这一面,用「可能」,段末用一句话请用户确认(例:「如果实际情况不是这样,告诉我,我按真实情况重看。」),全篇这类确认最多一处。不预设有没有伴侣、是否已婚、是否在上班、做哪类工作、孩子性别、父母是否在身边;性别未知时不用「他」「她」称伴侣和孩子。";
|
||||
|
||||
function source(relative: string) {
|
||||
return readFileSync(new URL(`../${relative}`, import.meta.url), "utf8");
|
||||
}
|
||||
|
||||
/** Every prompt-bearing module: src/mastra/*.ts and src/lib/consultation-*.ts. */
|
||||
function promptSources() {
|
||||
const files = [
|
||||
...readdirSync(new URL("../src/mastra/", import.meta.url)).filter((name) => name.endsWith(".ts")).map((name) => `src/mastra/${name}`),
|
||||
...readdirSync(new URL("../src/lib/", import.meta.url)).filter((name) => /^consultation-.*\.ts$/.test(name)).map((name) => `src/lib/${name}`),
|
||||
];
|
||||
return files.map((file) => ({ file, text: source(file) }));
|
||||
}
|
||||
|
||||
test("T1: each section leads with the strongest signal, asks to confirm an affliction, presupposes nothing (BUG-1164)", () => {
|
||||
assert.equal(NATAL_SECTION_RULE, SECTION_RULE_TEXT);
|
||||
for (const point of ["在不在你身边", "请用户确认", "不预设", "是否在上班、做哪类工作", "性别未知时不用「他」「她」称伴侣和孩子", "全篇这类确认最多一处"]) {
|
||||
assert.ok(NATAL_SECTION_RULE.includes(point), point);
|
||||
}
|
||||
const body = natalAnswerShapeBody();
|
||||
assert.ok(body.includes(NATAL_SECTION_RULE));
|
||||
assert.match(body, /每段的判断后在括号里给撑住它的盘上依据/);
|
||||
assert.doesNotMatch(body, OLD_SECTION_RULE);
|
||||
// The shared voice quotes the same constant; the rule text lives in one file.
|
||||
assert.ok(productConversationVoice.includes(NATAL_SECTION_RULE));
|
||||
assert.doesNotMatch(productConversationVoice, OLD_SECTION_RULE);
|
||||
assert.match(source("src/mastra/product-voice.ts"), /3\. \$\{NATAL_SECTION_RULE\}/);
|
||||
const holders = promptSources().filter(({ text }) => text.includes("包括这个人在不在你身边")).map(({ file }) => file);
|
||||
assert.deepEqual(holders, ["src/lib/consultation-thinking-plan.ts"]);
|
||||
for (const { file, text } of promptSources()) assert.doesNotMatch(text, OLD_SECTION_RULE, file);
|
||||
});
|
||||
|
||||
test("T2: no 逆行 in prompts or examples except the prohibition line and technique names (BUG-1165)", () => {
|
||||
const hits = promptSources().flatMap(({ file, text }) => text.split("\n").flatMap((line, index) => (
|
||||
line.includes("逆行") ? [`${file}:${index + 1}:${line.trim()}`] : []
|
||||
)));
|
||||
const allowed = hits.filter((hit) => (
|
||||
// Brief 2's shared reading forbids the 逆行 = 反复 inference; technique labels are names, not readings.
|
||||
/consultation-condensed-checklist\.ts:.*逆行不等于「反复、打回来」/.test(hit)
|
||||
|| /consultation-technique-audit\.ts:.*"逆行(次限|太阳弧)"/.test(hit)
|
||||
));
|
||||
assert.deepEqual(hits, allowed);
|
||||
assert.equal(allowed.length, 3);
|
||||
assert.match(productConversationVoice, /不是。(4 宫主落 10 宫)她把心力放在你的前途上/);
|
||||
assert.doesNotMatch(productConversationVoice, /已经在一起的关系|这段婚姻/);
|
||||
});
|
||||
|
||||
test("T2b: career examples carry no job shape (BUG-1168)", () => {
|
||||
assert.doesNotMatch(productConversationVoice, /升职|专业能力|做深|现有工作|这份工作|换公司|投简历|涨薪/);
|
||||
const voiceDoc = source("docs/VOICE.md");
|
||||
for (const phrase of ["之后再谈升职更有把握", "把已经积累的专业能力做成长期事业", "这份工作还值得留"]) {
|
||||
assert.ok(!voiceDoc.includes(phrase), phrase);
|
||||
}
|
||||
assert.match(productConversationVoice, /不预设读者在上班、做哪类工作/);
|
||||
});
|
||||
|
||||
test("T3: a correction turn acknowledges first and does not defend the reading (BUG-1166)", () => {
|
||||
assert.equal(
|
||||
FOLLOW_UP_CORRECTION_RULE,
|
||||
"用户纠正了前面的判断(比如说父亲其实不常在身边):先认下这件事,再说盘上哪几条和它对得上、原来哪句读偏了;不为原判断辩护。",
|
||||
);
|
||||
assert.ok(followUpAnswerShapeInstruction().includes(FOLLOW_UP_CORRECTION_RULE));
|
||||
assert.ok(!natalAnswerShapeInstruction().includes(FOLLOW_UP_CORRECTION_RULE));
|
||||
});
|
||||
@@ -217,15 +217,23 @@ test("persona is the sharp-but-reliable colleague, and hope never becomes a plat
|
||||
// 新值: 锁父母题按对象分段的 Good、单对象不拆段的 Good、格局名/大运拟人的 Bad;顾问报告 Bad 保留、理由改成「没有盘上依据」
|
||||
// 原因: TASK-consult-plain-answer-20261001 D1/D2/T1(BUG-1132):09-17 定稿样例随形状一起下线
|
||||
test("the pinned Good examples split by person and stay plain; the coined-pattern opener is Bad", () => {
|
||||
const parentsStart = voice.indexOf("Good (父母题首轮,按对象分段;盘上数据是示意)");
|
||||
const careerStart = voice.indexOf("Good (单对象事业题首轮,不拆段;盘上数据是示意)");
|
||||
// 原值: indexOf("Good (父母题首轮,按对象分段;盘上数据是示意)") / indexOf("Good (单对象事业题首轮,不拆段;盘上数据是示意)")
|
||||
// 新值: 两个标签改为「括号里是依据的占位,只演示口气与结构,不是读法」,事业例再加「不预设读者在上班、做哪类工作」
|
||||
// 原因: TASK-consult-no-presupposition-and-backtest-20261001 D3/D7(BUG-1165/1168):示例不得携带读法规则与职业形态
|
||||
const parentsStart = voice.indexOf("Good (父母题首轮,按对象分段;括号里是依据的占位,只演示口气与结构,不是读法)");
|
||||
const careerStart = voice.indexOf("Good (单对象事业题首轮,不拆段;括号里是依据的占位,只演示口气与结构,不是读法;不预设读者在上班、做哪类工作)");
|
||||
const badStart = voice.indexOf("Bad (多对象题,改写示意)");
|
||||
assert.ok(parentsStart > -1 && careerStart > parentsStart && badStart > careerStart);
|
||||
const parents = voice.slice(parentsStart, careerStart);
|
||||
for (const heading of ["## 你和妈妈", "## 你和爸爸", "## 他们怎么对你", "## 时间怎么看", "## 这周可以做的一件事"]) {
|
||||
assert.ok(parents.includes(heading), heading);
|
||||
}
|
||||
assert.match(parents, /(4 宫母亲宫的宫主水星落在 10 宫事业宫;代表母亲的月亮也在 10 宫)/);
|
||||
// 原值: assert.match(parents, /(4 宫母亲宫的宫主水星落在 10 宫事业宫;代表母亲的月亮也在 10 宫)/)
|
||||
// 新值: 括号只放占位(4 宫主落 10 宫;月亮在 10 宫);爸爸段演示「受冲先说、用可能、段末请确认」;不再有「分量重」「问爸爸的意见」
|
||||
// 原因: TASK-consult-no-presupposition-and-backtest-20261001 D1/D3(BUG-1164/1165):旧例预设父亲在场,回测里缺席的父亲被照抄成「话少、分量重」
|
||||
assert.match(parents, /(4 宫主落 10 宫;月亮在 10 宫)/);
|
||||
assert.match(parents, /他可能不常在你身边[\s\S]*如果实际情况不是这样,告诉我,我按真实情况重看。/);
|
||||
assert.doesNotMatch(parents, /分量重|标杆|爸爸的意见|靠做事/);
|
||||
const career = voice.slice(careerStart, badStart);
|
||||
assert.doesNotMatch(career, /## 你和/);
|
||||
assert.match(career, /## 盘上依据/);
|
||||
@@ -237,9 +245,16 @@ test("the pinned Good examples split by person and stay plain; the coined-patter
|
||||
const bad = voice.slice(badStart, voice.indexOf("\n", badStart));
|
||||
assert.match(bad, /自造格局名、大运写成角色、星名当形容词,爸妈揉成一段/);
|
||||
|
||||
assert.match(voice, /Good \(追问轮,用户说「你在说什么鬼」\): 说直接点:这份工作还值得留/);
|
||||
// 原值: /Good \(追问轮,用户说「你在说什么鬼」\): 说直接点:这份工作还值得留/
|
||||
// 新值: /…说直接点:现在这条路还值得走/
|
||||
// 原因: TASK-consult-no-presupposition-and-backtest-20261001 D7(BUG-1168):示例不预设读者在上班
|
||||
assert.match(voice, /Good \(追问轮,用户说「你在说什么鬼」\): 说直接点:现在这条路还值得走/);
|
||||
|
||||
const badLine = voice.split("\n").find((line) => line.startsWith("Bad: 你更适合把已经积累的专业能力做成长期事业"));
|
||||
// 原值: startsWith("Bad: 你更适合把已经积累的专业能力做成长期事业")
|
||||
// 新值: startsWith("Bad: 你更适合长期做一件事"),理由不变;全篇示例不再有「专业能力」「升职」「做深」「现有工作」
|
||||
// 原因: TASK-consult-no-presupposition-and-backtest-20261001 D7/T2b(BUG-1168):Bad 例的职业形态词被模型反向吸收
|
||||
assert.doesNotMatch(voice, /专业能力|升职|做深|现有工作|这份工作/);
|
||||
const badLine = voice.split("\n").find((line) => line.startsWith("Bad: 你更适合长期做一件事"));
|
||||
assert.ok(badLine, "旧 Good 例必须改挂在 Bad 上");
|
||||
assert.match(badLine!, /像顾问报告:只有结论,没有盘上依据/);
|
||||
});
|
||||
@@ -264,7 +279,11 @@ test("the voice answers the sentence asked: no motive guessing, yes/no first, co
|
||||
assert.match(voice, /无出生分钟与申报时段没有正文骨架,行动就写在回答结尾/);
|
||||
// Yes/no Good and Bad pair, fictional chart.
|
||||
assert.match(voice, /Good \(是非题,用户问「我妈是不是不太在意我」/);
|
||||
assert.match(voice, /不是。4 宫主水星逆行落 10 宫/);
|
||||
// 原值: assert.match(voice, /不是。4 宫主水星逆行落 10 宫/)
|
||||
// 新值: 「不是。(4 宫主落 10 宫)」;示例与提示词里不再有「逆行」,已婚预设的婚姻 Good 例删除
|
||||
// 原因: TASK-consult-no-presupposition-and-backtest-20261001 D2/D3(BUG-1165):「逆行」被照抄成「反复、打回来」
|
||||
assert.match(voice, /不是。(4 宫主落 10 宫)她把心力放在你的前途上/);
|
||||
assert.doesNotMatch(voice, /逆行|已经在一起的关系/);
|
||||
assert.match(voice, /Bad \(同一问题\): 你其实要的是被听见/);
|
||||
// 原值: "…wants, needs, or feels; state where the chart puts them"(Never 列表里第二句读成也被禁止)
|
||||
// 新值: 两句拆开,第二句是替代做法 原因: Claude 验收改措辞
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user