- src/muse 新版全模块(装配/共享/上下文/任务运行/作品规划/故事世界/正文写作/审校修订/知识方法/作者经验/效果评测/交付连载/资料研究/正式变更/元数据/接入/基础设施/编排)+ 测试树(单元/契约/集成/架构/迁移/端到端/夹具) - 129 项功能全部实现与自动验证(功能覆盖.json/矩阵),含 W31 补齐的规则与代价/节奏安排/伏笔与承诺 - 旧实现按处置清单退出(702 条中 324 删,保护合同与未迁移条目留存有据);web/app.py 旧工作台退役,新工作台为唯一写入口 - 数据库/旧库迁移:真实旧库内容批次迁移链(端点守卫/PG作品正文映射/质量资产缺省投影) - 运行手册 docs/运行手册.md;W30 本机服务阶段一已运行(infra PG 为正式内容权威) - R2 执行证据与私有运行材料在 .agents.local/改造/R2-20260909/(不入库)
273 lines
10 KiB
TypeScript
273 lines
10 KiB
TypeScript
import { readFileSync, writeFileSync } from "node:fs";
|
||
import { expect, test } from "@playwright/test";
|
||
import type { 实验报告 } from "../../src/功能/效果评测/数据";
|
||
|
||
test("NC-browser-evaluation-report:隔离报告与未知费用真实读回", async ({
|
||
page,
|
||
}, info) => {
|
||
const password = process.env.MUSE_AUTHOR_PASSWORD_FILE;
|
||
const id = process.env.MUSE_EVALUATION_ID;
|
||
const sample = process.env.MUSE_EVALUATION_SAMPLE;
|
||
if (!password || !id || !sample)
|
||
throw new Error("需要隔离评测服务、实验、样本与口令位置");
|
||
const errors: string[] = [];
|
||
page.on("pageerror", (e) => errors.push(e.message));
|
||
await page.goto("/");
|
||
await page.getByLabel("访问口令").fill(readFileSync(password, "utf8").trim());
|
||
await page.getByRole("button", { name: "进入工作台" }).click();
|
||
await page.getByRole("link", { name: /效果评测/ }).click();
|
||
await page.getByLabel("实验编号").fill(id);
|
||
const received = page.waitForResponse((r) =>
|
||
r.url().endsWith(`/experiments/${id}/report`),
|
||
);
|
||
await page.getByRole("button", { name: "查看报告" }).click();
|
||
const response = await received;
|
||
expect(response.status()).toBe(200);
|
||
let report: 实验报告 = await response.json();
|
||
const samplePanel = page
|
||
.getByLabel("逐例结果")
|
||
.getByRole("listitem")
|
||
.filter({
|
||
has: page
|
||
.getByRole("heading", { level: 3 })
|
||
.filter({ hasText: `${sample} · ` }),
|
||
});
|
||
await expect(samplePanel).toHaveCount(1);
|
||
if (report.confounders) {
|
||
const panel = page.getByLabel("混淆项观察");
|
||
await panel.getByText(`${sample} · 五类观察`, { exact: true }).click();
|
||
const table = panel.getByRole("table", { name: `${sample}混淆项` });
|
||
await expect(table.getByRole("row")).toHaveCount(6);
|
||
await expect(table).toContainText("疑似漏报");
|
||
await expect(table).toContainText("疑似误报");
|
||
await expect(table).toContainText("输入泄漏审计");
|
||
await expect(table).toContainText("评委不稳定");
|
||
await expect(table).toContainText("声明新角色缺卡");
|
||
for (const row of Object.values(report.confounders.samples[sample])) {
|
||
if (row.finding_count == null)
|
||
await expect(table).toContainText("未计算");
|
||
}
|
||
}
|
||
const completed = process.env.MUSE_EVALUATION_COMPLETED === "1";
|
||
if (completed) {
|
||
expect(report.state).toBe("completed");
|
||
const sampleReport = report.samples.find(
|
||
(row: { sample_id: string }) => row.sample_id === sample,
|
||
);
|
||
if (!sampleReport) throw new Error("报告缺少指定样本");
|
||
const decision = sampleReport.decisions[0];
|
||
if (!decision?.judgment) throw new Error("完成报告缺少实际判断");
|
||
await samplePanel
|
||
.getByText(`${decision.pair.join(" / ")} · ${decision.model}:`, {
|
||
exact: false,
|
||
})
|
||
.click();
|
||
await expect(
|
||
samplePanel
|
||
.getByText(decision.judgment.rationale, { exact: true })
|
||
.first(),
|
||
).toBeVisible();
|
||
for (const evidence of decision.literary
|
||
? []
|
||
: decision.judgment.dimensions[0].evidence) {
|
||
await expect(
|
||
samplePanel
|
||
.getByText(`${decision.sides[evidence.side]} 原文`, {
|
||
exact: true,
|
||
})
|
||
.first(),
|
||
).toBeVisible();
|
||
await expect(
|
||
samplePanel
|
||
.locator("blockquote")
|
||
.filter({ hasText: evidence.quote })
|
||
.first(),
|
||
).toBeVisible();
|
||
}
|
||
if (sampleReport.literary?.["control:treatment"]) {
|
||
const literary = samplePanel.getByLabel("control:treatment文学评分");
|
||
await expect(literary.getByRole("heading")).toContainText(
|
||
sampleReport.literary["control:treatment"].status === "stable_report"
|
||
? "双评稳定"
|
||
: "第三评已收敛",
|
||
);
|
||
await expect(literary.getByRole("row")).toHaveCount(11);
|
||
await expect(literary).toContainText(
|
||
sampleReport.literary["control:treatment"].status === "stable_report"
|
||
? "初评分数分歧 0 项"
|
||
: "初评分数分歧 10 项",
|
||
);
|
||
const scores = samplePanel.getByLabel("评委原始评分").first();
|
||
await expect(scores).toBeVisible();
|
||
await scores
|
||
.getByText("设定与实体保真:", { exact: false })
|
||
.first()
|
||
.click();
|
||
await expect(scores.locator("blockquote").first()).toBeVisible();
|
||
}
|
||
} else {
|
||
await expect(
|
||
page.getByRole("heading", { name: "费用待核对" }),
|
||
).toBeVisible();
|
||
await expect(
|
||
page.locator("dt").filter({ hasText: "实际总费用" }).locator("+ dd"),
|
||
).toHaveText("待核对");
|
||
await expect(
|
||
page.getByRole("heading", { name: `${sample} · 比较未完成` }),
|
||
).toBeVisible();
|
||
}
|
||
await expect(
|
||
page.getByText(`主比较:${report.primary_pair.join(" / ")}`, {
|
||
exact: true,
|
||
}),
|
||
).toBeVisible();
|
||
await page.getByText("实验条件与版本", { exact: true }).click();
|
||
await expect(
|
||
page.getByLabel("实验概况").getByText(/配置合同验证/),
|
||
).toBeVisible();
|
||
await samplePanel.getByText("执行与费用记录", { exact: true }).click();
|
||
if (report.calibration) {
|
||
const calibration = page.getByLabel("标定结果");
|
||
await expect(calibration).toContainText("与本批金标准一致性达标");
|
||
const updated = page.waitForResponse((r) =>
|
||
r.url().endsWith(`/experiments/${id}/report`),
|
||
);
|
||
const saved = page.waitForResponse((r) =>
|
||
r.url().endsWith(`/experiments/${id}/calibration/seal`),
|
||
);
|
||
await calibration.getByRole("button", { name: "保存标定记录" }).click();
|
||
expect((await saved).status()).toBe(200);
|
||
report = await (await updated).json();
|
||
if (!report.calibration) throw new Error("保存后报告丢失标定记录");
|
||
expect(report.calibration.receipt_id).toBeTruthy();
|
||
await expect(calibration).toContainText("标定记录已保存。");
|
||
await calibration.getByText("逐项标定偏差", { exact: true }).click();
|
||
await expect(calibration.getByRole("row")).toHaveCount(
|
||
report.calibration.result.observations.length + 1,
|
||
);
|
||
}
|
||
if (report.calibration_use) {
|
||
const panel = page.getByLabel("本次评委的标定依据");
|
||
await expect(panel).toContainText("下表保留对应的来源和版本");
|
||
const reviewers = Object.values(report.calibration_use.binding.reviewers);
|
||
await expect(panel.getByRole("row")).toHaveCount(reviewers.length + 1);
|
||
for (const reviewer of reviewers) {
|
||
await expect(
|
||
panel.getByText(reviewer.actual_model, { exact: true }),
|
||
).toBeVisible();
|
||
await expect(
|
||
panel
|
||
.locator(`a[href="/evaluations/${reviewer.experiment_id}"]`)
|
||
.first(),
|
||
).toBeVisible();
|
||
}
|
||
}
|
||
if (report.effect) {
|
||
const panel = page.getByLabel("效果判据");
|
||
await expect(
|
||
panel.getByRole("heading", { name: "执行与约束:通过" }),
|
||
).toBeVisible();
|
||
await expect(
|
||
panel.getByRole("heading", { name: "效果阈值:通过" }),
|
||
).toBeVisible();
|
||
await expect(panel.getByLabel("主比较效果").getByRole("row")).toHaveCount(
|
||
6,
|
||
);
|
||
await panel.getByText("场景与角色分层", { exact: true }).click();
|
||
await expect(panel.getByText("老角色回归", { exact: true })).toBeVisible();
|
||
const refreshed = page.waitForResponse((r) =>
|
||
r.url().endsWith(`/experiments/${id}/report`),
|
||
);
|
||
const saved = page.waitForResponse((r) =>
|
||
r.url().endsWith(`/experiments/${id}/effect/seal`),
|
||
);
|
||
await panel.getByRole("button", { name: "保存效果判据" }).click();
|
||
expect((await saved).status()).toBe(200);
|
||
report = await (await refreshed).json();
|
||
expect(report.effect?.receipt_id).toBeTruthy();
|
||
await expect(
|
||
panel.getByText("效果判据已保存。", { exact: true }),
|
||
).toBeVisible();
|
||
if (!report.effect?.receipt_id) throw new Error("保存后缺少效果凭据");
|
||
await panel.getByText("判据与目标记录", { exact: true }).click();
|
||
await expect(
|
||
panel.getByText(report.effect.receipt_id, { exact: true }),
|
||
).toBeVisible();
|
||
await expect(
|
||
panel.getByText(report.effect.assessment.evidence_hash, { exact: true }),
|
||
).toBeVisible();
|
||
}
|
||
for (const sampleReport of report.samples) {
|
||
const panel = page.getByLabel(`${sampleReport.sample_id}语义检测`);
|
||
if (sampleReport.detection_complete != null) {
|
||
await expect(panel).toContainText("检测齐全");
|
||
if (
|
||
!sampleReport.detections ||
|
||
!Object.keys(sampleReport.detections).length
|
||
)
|
||
throw new Error("已检测报告缺少实际检测结果");
|
||
for (const [arm, detection] of Object.entries(sampleReport.detections)) {
|
||
await panel
|
||
.getByText(
|
||
`${arm} · ${detection.report.status === "failed" ? "发现冲突" : "未发现冲突"}`,
|
||
{ exact: true },
|
||
)
|
||
.click();
|
||
for (const finding of detection.report.findings) {
|
||
await expect(
|
||
panel.getByText(finding.message, { exact: true }),
|
||
).toBeVisible();
|
||
await expect(
|
||
panel
|
||
.locator("blockquote")
|
||
.filter({ hasText: finding.candidate_quote }),
|
||
).toBeVisible();
|
||
}
|
||
}
|
||
} else {
|
||
await expect(panel).toContainText("未配置检测器");
|
||
}
|
||
}
|
||
if (!completed)
|
||
await expect(page.getByText("费用未结算", { exact: false })).toBeVisible();
|
||
for (const sampleReport of report.samples) {
|
||
for (const unit of sampleReport.units) {
|
||
if (unit.rejections?.length) {
|
||
await expect(
|
||
page.getByText(`已保留 ${unit.rejections.length} 次判断拒绝。`, {
|
||
exact: true,
|
||
}),
|
||
).toBeVisible();
|
||
await expect(page.getByLabel("引文校验记录")).toContainText(
|
||
unit.rejections[0].call_id,
|
||
);
|
||
}
|
||
}
|
||
}
|
||
if (report.effect) {
|
||
await page
|
||
.getByLabel("效果判据")
|
||
.screenshot({ path: `${info.outputDir}/评测报告.png` });
|
||
} else {
|
||
await page.screenshot({
|
||
path: `${info.outputDir}/评测报告.png`,
|
||
fullPage: true,
|
||
});
|
||
}
|
||
if (report.confounders) {
|
||
await page
|
||
.getByLabel("混淆项观察")
|
||
.screenshot({ path: `${info.outputDir}/混淆观察.png` });
|
||
}
|
||
const refreshed = page.waitForResponse((r) =>
|
||
r.url().endsWith(`/experiments/${id}/report`),
|
||
);
|
||
await page.getByRole("button", { name: "刷新报告" }).click();
|
||
expect((await (await refreshed).json()).report_hash).toBe(report.report_hash);
|
||
writeFileSync(
|
||
`${info.outputDir}/报告回执.json`,
|
||
JSON.stringify({ experiment_id: id, report_hash: report.report_hash }),
|
||
);
|
||
expect(errors).toEqual([]);
|
||
});
|