Files
Jyotisha/frontend/tests/rectification-history-open-20260909.test.ts
T
jesse-ux db5b0a214b
Independent Staging Quality Gate / validate (push) Failing after 6m30s
Independent Staging Quality Gate / publish (push) Skipped
fix(web): 会话列表合同跟着外壳搬家,无活跃会话不再静默吞发送
四条源码合同改到 (app)/layout 与注册载荷两端对断。列表只剩校正会话时普通输入框锁定,发送会打开校正或给出提示。
2026-09-17 23:06:01 +08:00

79 lines
4.8 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";
import { cssDeclarations } from "./css-contract-test-support.ts";
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 仍叫 rectificationErrorSessionIdsetter 仍叫 setRectificationErrorSessionId
// 原因:外壳也要读的校正状态合并成一个对象,散装 useState 下降
assert.match(pageSource, /errorSessionId: rectificationErrorSessionId,/);
assert.match(pageSource, /setRectificationErrorSessionId,/);
assert.match(
pageSource,
/rectificationError=\{rectificationErrorSessionId \? "" : rectificationError\}/,
);
// 原值:page.tsx 把 openErrorSessionId / openErrorMessage 直接传给 AppSidebar
// 新值:layout 从 registration 传给 AppSidebar,首页 registerShellControls 载荷带这两个字段
// 原因:T2 外壳搬家,两端都断才等于侧栏行仍拿得到打开失败
const layout = read("../src/app/(app)/layout.tsx");
const shell = read("../src/hooks/use-home-shell-registration.ts");
assert.match(layout, /openErrorSessionId=\{registration\?\.openErrorSessionId \?\? null\}/);
assert.match(layout, /openErrorMessage=\{registration\?\.openErrorMessage \?\? ""\}/);
assert.match(shell, /openErrorSessionId: rectificationErrorSessionId,/);
assert.match(shell, /openErrorMessage: rectificationErrorSessionId \? rectificationErrorMessage : "",/);
assert.match(starter, /rectificationError && !rectificationSurfaceOpen && \(/);
assert.match(sidebar, /openErrorSessionId/);
assert.match(sidebarRow, /error \? \(/);
assert.match(sidebarRow, /className="session-open-error"/);
assert.match(sidebarRow, /role="alert"/);
assert.match(hook, /setRectificationErrorSessionId\(intent === "session" \? exactSessionId : null\)/);
assert.match(sessions, /setRectificationErrorSessionId\(null\)/);
const notice = cssDeclarations(".session-open-error", styles);
assert.match(notice, /color:\s*var\(--color-danger\)/);
assert.match(notice, /font-size:\s*var\(--type-overline\)/);
assert.match(layout, /openErrorSessionId=\{registration\?\.openErrorSessionId \?\? null\}/);
});