Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
70 lines
4.5 KiB
TypeScript
70 lines
4.5 KiB
TypeScript
import assert from "node:assert/strict";
|
||
import { readFileSync } from "node:fs";
|
||
import test from "node:test";
|
||
|
||
import { homeSurface as page } from "./home-surface.ts";
|
||
|
||
const read = (relativePath: string) => readFileSync(new URL(relativePath, import.meta.url), "utf8");
|
||
const sidebar = read("../src/components/app-sidebar.tsx");
|
||
const sidebarRow = read("../src/components/sidebar-session-row.tsx");
|
||
const starter = read("../src/components/starter-home.tsx");
|
||
const styles = read("../src/app/globals.css");
|
||
const pageSource = read("../src/app/(app)/page.tsx");
|
||
const hook = read("../src/hooks/use-rectification-surface.ts");
|
||
const sessions = read("../src/hooks/use-session-management.ts");
|
||
const caseService = read("../src/lib/rectification-agentic/v9/case-service.ts");
|
||
|
||
test("history session open uses the bound skill identity instead of the live registry version", () => {
|
||
// 原值:openRectificationCase 对 session 也把 resolveActiveSkillPackage() 交给 v2
|
||
// 新值:session 先 v1 取 Case,再读绑定身份,注册表核验后把绑定身份交给 v2
|
||
// 决策 1:打开 RPC 不再要求等于当前版本
|
||
assert.match(caseService, /request\.intent === "session"/);
|
||
assert.match(caseService, /open_agentic_rectification_case"/);
|
||
assert.match(caseService, /get_agentic_rectification_skill_identity"/);
|
||
assert.match(caseService, /resolveExactSkillPackage\(/);
|
||
assert.match(caseService, /skill_identity_missing/);
|
||
const homepageOpen = caseService.slice(
|
||
caseService.indexOf("export async function openRectificationCase"),
|
||
caseService.indexOf("export async function getRectificationEntrySummary"),
|
||
);
|
||
assert.match(homepageOpen, /intent === "homepage" \|\| request\.intent === "new"/);
|
||
assert.match(homepageOpen, /open_agentic_rectification_case_v2/);
|
||
});
|
||
|
||
test("skill_identity_mismatch maps to 409 instead of the 500 fallback", () => {
|
||
// 原值:KNOWN_RPC_ERROR_CODES 没有 mismatch,落到 校正服务暂时不可用
|
||
// 新值:409 skill_identity_mismatch,文案要求刷新
|
||
// 决策 2:修完决策 1 后不应再出现;映射只为不再露 500
|
||
assert.match(
|
||
caseService,
|
||
/"agentic_rectification_skill_identity_mismatch", \{ status: 409, code: "skill_identity_mismatch", message: "该校正绑定的规则版本与当前不一致,请刷新后重试" \}/,
|
||
);
|
||
});
|
||
|
||
test("a history-list open failure shows under the clicked row, not on the starter card", () => {
|
||
// 原值:rectificationError 只由 starter-home 画;selectSession 不切会话,表现为点了没反应
|
||
// 新值:session 失败绑到被点的那一行;首页起始卡不重复同一条
|
||
// 决策 3:错误就地显示
|
||
// 原值:const [rectificationErrorSessionId, setRectificationErrorSessionId] = useState(...)
|
||
// 新值:外壳 9 个校正字段合成一个 rectification 对象;errorSessionId 仍叫 rectificationErrorSessionId,setter 仍叫 setRectificationErrorSessionId
|
||
// 原因:外壳也要读的校正状态合并成一个对象,散装 useState 下降
|
||
assert.match(pageSource, /errorSessionId: rectificationErrorSessionId,/);
|
||
assert.match(pageSource, /setRectificationErrorSessionId,/);
|
||
// 原值:失败写在被点的侧栏行下(.session-open-error,role="alert",layout / 外壳注册 / AppSidebar 传
|
||
// openErrorSessionId + openErrorMessage),首页起始卡画 rectificationError(.rectification-entry-error)
|
||
// 新值:打开失败在 assignOpenError 里弹一次 error toast(notifyError(message)),侧栏行与起始卡都不再画;
|
||
// rectificationError / rectificationErrorSessionId 状态保留给输入框上方的「重新打开」卡
|
||
// 原因:2026-09-30 产品「报错和提示不要占页面布局」;BUG-621 的主语「点了要有反馈、不能没反应」由 toast 保证
|
||
const layout = read("../src/app/(app)/layout.tsx");
|
||
const shell = read("../src/hooks/use-home-shell-registration.ts");
|
||
assert.match(hook, /function assignOpenError\(message: string\) \{[\s\S]{0,160}notifyError\(message\);\n\s*setRectificationError\(message\);/);
|
||
assert.match(hook, /setRectificationErrorSessionId\(intent === "session" \? exactSessionId : null\)/);
|
||
assert.match(sessions, /setRectificationErrorSessionId\(null\)/);
|
||
assert.doesNotMatch(layout, /openErrorSessionId|openErrorMessage/);
|
||
assert.doesNotMatch(shell, /openErrorSessionId|openErrorMessage/);
|
||
assert.doesNotMatch(sidebar, /openErrorSessionId/);
|
||
assert.doesNotMatch(sidebarRow, /session-open-error/);
|
||
assert.doesNotMatch(starter, /rectification-entry-error/);
|
||
assert.doesNotMatch(styles, /\.session-open-error/);
|
||
});
|