Files
Jyotisha/frontend/tests/consultation-voice-contract.test.ts
T
jesse-ux 8144fca27d
Independent Staging Quality Gate / validate (push) Failing after 9m47s
Independent Staging Quality Gate / publish (push) Skipped
fix(chat): fold natal reports and drop homepage topic cards
Homepage no longer waits on /api/onboarding for six starter questions.
Natal answers show the spoken layer first; the Level 2 skeleton sits in a
collapsed 完整分析 block. Wide tables scroll sideways on a phone. Form
inputs are 16px so iOS does not zoom on focus.
2026-09-15 12:27:16 +08:00

74 lines
4.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import test from "node:test";
const voice = readFileSync(new URL("../src/mastra/product-voice.ts", import.meta.url), "utf8");
const mastra = readFileSync(new URL("../src/mastra/index.ts", import.meta.url), "utf8");
const route = readFileSync(new URL("../src/app/api/consult/route.ts", import.meta.url), "utf8");
const binding = readFileSync(new URL("../src/mastra/skill-binding.ts", import.meta.url), "utf8");
const workflow = readFileSync(new URL("../src/mastra/consultation-workflow.ts", import.meta.url), "utf8");
test("product voice uses a spoken opener then the skill Level 2 report skeleton", () => {
assert.match(voice, /VISIBLE VOICE/);
assert.match(voice, /natalSpokenReportContract/);
assert.match(voice, /governs METHOD, TECHNIQUE INVOCATION, TRUTH BOUNDARIES/);
assert.match(voice, /Raman six-step house judgment/);
assert.match(voice, /Yoga table/);
assert.match(voice, /Technique Audit Table at the end of the answer body/);
assert.match(voice, /已执行 \/ 阻塞 \/ 不适用/);
assert.match(voice, /governed_support_only_candidate_ready/);
assert.match(voice, /Skip an executed layer the question needs/);
assert.match(voice, /你更适合把已经积累的专业能力做成长期事业/);
assert.match(voice, /36 heading-free sentences/);
assert.match(voice, /one conclusion sentence, then 23 short point-sentences/);
assert.match(voice, /Spoken-layer total ≤ 400 Chinese characters/);
assert.match(voice, /骨架不可省略,但必须以直接回应开场/);
assert.match(mastra, /productConversationVoice/);
assert.match(mastra, /natalSpokenReportContract/);
assert.match(mastra, /skill Level 2 report skeleton/);
assert.match(mastra, /Paste that Technique Audit Table at the end of the answer body/);
assert.match(binding, /Follow this method and its truth boundaries/);
assert.match(binding, /present its Level 2 report template in the chat body after a 3-6 sentence spoken reply/);
assert.match(mastra, /The bound skill method is this product's answering contract/);
assert.match(mastra, /Do not use a restricted technique/);
assert.match(mastra, /must_use_layers is the executed shortlist/);
assert.match(mastra, /do not invent it from model knowledge/);
assert.match(mastra, /search_period is the searched observation window/);
assert.match(voice, /## 统一参数与原始结构/);
assert.match(mastra, /consultationSpokenHeadingRule\("natal"\)/);
assert.match(workflow, /template: "skill_level_2"/);
assert.match(workflow, /raman_six_step/);
assert.doesNotMatch(mastra, /Name the domains you did cover, say plainly that the remaining ones were not calculated/);
assert.doesNotMatch(mastra, /2-5 short paragraphs/);
assert.doesNotMatch(voice, /Do not paste the Technique Audit Table/);
});
test("general and window get voice without the natal Level 2 skeleton", () => {
// 原值: 另切 onboardingInstructions,断言它没有 natal 骨架。
// 新值: onboarding agent 已删除;general 与 window 仍无骨架。
// 原因: 建议问题生成接口下线。
const generalStart = mastra.indexOf("const generalJyotishInstructions");
const windowStart = mastra.indexOf("const windowJyotishInstructions");
const natalStart = mastra.indexOf("const jyotishInstructions");
const general = mastra.slice(generalStart, mastra.indexOf("const dailyStarlanguageInstructions"));
const window = mastra.slice(windowStart, mastra.indexOf("export function getWindowJyotishAgent"));
const natal = mastra.slice(natalStart, mastra.indexOf("export function getJyotishAgent"));
assert.match(natal, /natalSpokenReportContract/);
assert.match(general, /productConversationVoice/);
assert.doesNotMatch(general, /natalSpokenReportContract/);
assert.match(window, /productConversationVoice/);
assert.doesNotMatch(window, /natalSpokenReportContract/);
assert.doesNotMatch(mastra, /const onboardingInstructions/);
});
test("consult user turn no longer dumps tool JSON that the model would parrot", () => {
const chartBranch = route.slice(route.indexOf("const toolInput = consultationInputSchema.parse"));
assert.match(chartBranch, /先用 3–6 句口语直接回答下面的问题[\s\S]*?resolvedQuestion\.modelQuestion/);
assert.doesNotMatch(chartBranch, /JSON\.stringify\(toolInput\)/);
assert.doesNotMatch(chartBranch, /经过服务端校验的工具参数/);
assert.match(route, /文末技法审计表/);
assert.match(chartBranch, /await runConsultationWorkflow\(toolInput/);
});