feat: audit DeepSeek Chat across sources
This commit is contained in:
@@ -0,0 +1,347 @@
|
||||
import { createHash } from "node:crypto";
|
||||
import { readFileSync, statSync, writeFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
const root = resolve(import.meta.dirname, "..");
|
||||
const paths = {
|
||||
sampling: resolve(
|
||||
root,
|
||||
"src/data/deepseek-v2-lite-chat-cross-source-sampling.json",
|
||||
),
|
||||
evaluation: resolve(
|
||||
root,
|
||||
"src/data/deepseek-v2-lite-chat-cross-source-sampling-eval.json",
|
||||
),
|
||||
rerun: resolve(
|
||||
root,
|
||||
"src/data/deepseek-v2-lite-chat-cross-source-sampling-repro-r0.json",
|
||||
),
|
||||
reproduction: resolve(
|
||||
root,
|
||||
"src/data/deepseek-v2-lite-chat-cross-source-sampling-reproduction.json",
|
||||
),
|
||||
analysis: resolve(
|
||||
root,
|
||||
"src/data/deepseek-v2-lite-chat-cross-source-sampling-analysis.json",
|
||||
),
|
||||
output: resolve(
|
||||
root,
|
||||
"src/data/deepseek-v2-lite-chat-cross-source-sampling-compact.json",
|
||||
),
|
||||
};
|
||||
|
||||
const readJson = (path) => JSON.parse(readFileSync(path, "utf8"));
|
||||
const sha256 = (path) => createHash("sha256")
|
||||
.update(readFileSync(path))
|
||||
.digest("hex");
|
||||
const artifact = (path) => ({
|
||||
bytes: statSync(path).size,
|
||||
sha256: sha256(path),
|
||||
});
|
||||
|
||||
const sampling = readJson(paths.sampling);
|
||||
const evaluation = readJson(paths.evaluation);
|
||||
const reproduction = readJson(paths.reproduction);
|
||||
const analysis = readJson(paths.analysis);
|
||||
const samplingArtifact = artifact(paths.sampling);
|
||||
const evaluationArtifact = artifact(paths.evaluation);
|
||||
const rerunArtifact = artifact(paths.rerun);
|
||||
const reproductionArtifact = artifact(paths.reproduction);
|
||||
|
||||
if (evaluation.input.sampling_sha256 !== samplingArtifact.sha256) {
|
||||
throw new Error("evaluation → sampling hash contract failed");
|
||||
}
|
||||
if (reproduction.formal.sha256 !== samplingArtifact.sha256) {
|
||||
throw new Error("reproduction → formal hash contract failed");
|
||||
}
|
||||
if (reproduction.rerun.sha256 !== rerunArtifact.sha256) {
|
||||
throw new Error("reproduction → rerun hash contract failed");
|
||||
}
|
||||
if (
|
||||
reproduction.summary.cells !== 64
|
||||
|| reproduction.summary.all_preregistered_fields_exact !== 64
|
||||
|| Object.values(reproduction.summary.by_field).some(
|
||||
(value) => value !== 64,
|
||||
)
|
||||
) {
|
||||
throw new Error("64-cell reproduction gate failed");
|
||||
}
|
||||
if (
|
||||
analysis.inputs.sampling.sha256 !== samplingArtifact.sha256
|
||||
|| analysis.inputs.evaluation.sha256 !== evaluationArtifact.sha256
|
||||
|| analysis.inputs.reproduction.sha256 !== reproductionArtifact.sha256
|
||||
) {
|
||||
throw new Error("analysis input hash chain failed");
|
||||
}
|
||||
if (
|
||||
analysis.contract.sources !== 16
|
||||
|| analysis.contract.sources_per_domain !== 4
|
||||
|| analysis.contract.seeds_per_source_condition !== 4
|
||||
|| analysis.contract.outputs !== 256
|
||||
) {
|
||||
throw new Error("source-blocked analysis grid contract failed");
|
||||
}
|
||||
|
||||
const conditions = analysis.contract.conditions;
|
||||
const conditionLabels = {
|
||||
s0_eos: "S0 · EOS",
|
||||
s1_eos: "S1 · EOS",
|
||||
s0_period: "S0 · 句点",
|
||||
s1_period: "S1 · 句点",
|
||||
};
|
||||
const domainLabels = {
|
||||
english: "English · WikiText-2",
|
||||
chinese: "中文 · TNEWS",
|
||||
code: "Code · HumanEval",
|
||||
math: "Math · GSM8K",
|
||||
};
|
||||
const sourceLabel = (sourceId) => {
|
||||
if (sourceId.startsWith("HumanEval/")) {
|
||||
return sourceId;
|
||||
}
|
||||
if (sourceId.startsWith("gsm8k/")) {
|
||||
return `GSM8K/${sourceId.split("/").at(-1)}`;
|
||||
}
|
||||
if (sourceId.startsWith("tnews/")) {
|
||||
return `TNEWS/${sourceId.split("/").at(-1)}`;
|
||||
}
|
||||
if (sourceId.startsWith("wikitext2/")) {
|
||||
return `WikiText/${sourceId.split("/").at(-1)}`;
|
||||
}
|
||||
return sourceId;
|
||||
};
|
||||
|
||||
const sourceMeta = Object.fromEntries(
|
||||
Object.entries(analysis.source_metadata).map(([sourceId, row]) => [
|
||||
sourceId,
|
||||
{
|
||||
...row,
|
||||
label: sourceLabel(sourceId),
|
||||
},
|
||||
]),
|
||||
);
|
||||
|
||||
const evalRows = evaluation.rows.map((row) => {
|
||||
let task = null;
|
||||
if (row.domain === "math") {
|
||||
task = {
|
||||
predicted: row.task_evaluation.predicted_final,
|
||||
gold: row.task_evaluation.gold_final,
|
||||
covered: row.task_evaluation.evaluator_covered,
|
||||
fixedPass: row.task_evaluation.fixed_budget_numeric_exact,
|
||||
strictPass: row.task_evaluation.strict_complete_numeric_exact,
|
||||
method: row.task_evaluation.extraction_method,
|
||||
};
|
||||
} else if (row.domain === "code") {
|
||||
task = {
|
||||
ast: row.task_evaluation.python_ast_parse,
|
||||
executed: row.task_evaluation.execution.status !== "not_run",
|
||||
status: row.task_evaluation.execution.status,
|
||||
fixedPass: row.task_evaluation.fixed_budget_tests_pass,
|
||||
strictPass: row.task_evaluation.strict_complete_tests_pass,
|
||||
candidateHash: row.task_evaluation.candidate_sha256,
|
||||
cacheHit: row.task_evaluation.execution_cache_hit,
|
||||
};
|
||||
}
|
||||
return {
|
||||
sourceId: row.source_id,
|
||||
domain: row.domain,
|
||||
condition: row.condition,
|
||||
replicate: row.replicate_label,
|
||||
baseSeed: row.base_seed,
|
||||
generatedTokens: row.generated_tokens,
|
||||
hitEos: row.hit_eos,
|
||||
truncated: row.stopped_at_max_new_tokens,
|
||||
trajectoryHash: row.generated_token_ids_sha256,
|
||||
completionClass: row.completion_class,
|
||||
task,
|
||||
};
|
||||
});
|
||||
|
||||
const taskFailures = evalRows
|
||||
.filter((row) => row.task && !row.task.strictPass)
|
||||
.map((row) => ({
|
||||
sourceId: row.sourceId,
|
||||
sourceLabel: sourceLabel(row.sourceId),
|
||||
domain: row.domain,
|
||||
condition: row.condition,
|
||||
replicate: row.replicate,
|
||||
generatedTokens: row.generatedTokens,
|
||||
hitEos: row.hitEos,
|
||||
completionClass: row.completionClass,
|
||||
detail: row.domain === "math"
|
||||
? {
|
||||
predicted: row.task.predicted,
|
||||
gold: row.task.gold,
|
||||
failure: "wrong_numeric_answer",
|
||||
}
|
||||
: {
|
||||
status: row.task.status,
|
||||
candidateHash: row.task.candidateHash,
|
||||
failure: row.task.status,
|
||||
},
|
||||
}));
|
||||
|
||||
const taskTotals = Object.fromEntries(
|
||||
Object.entries(analysis.task_matrix).map(([domain, tasks]) => [
|
||||
domain,
|
||||
tasks.map((task) => ({
|
||||
sourceId: task.source_id,
|
||||
label: sourceLabel(task.source_id),
|
||||
withinDomainIndex: task.within_domain_index,
|
||||
conditions: Object.fromEntries(
|
||||
Object.entries(task.conditions).map(([condition, cell]) => [
|
||||
condition,
|
||||
{
|
||||
pass: cell.strict_complete_success,
|
||||
outputs: 4,
|
||||
anyPass: cell.observed_any_strict_complete_pass,
|
||||
naturalEos: cell.natural_eos,
|
||||
meanGeneratedTokens: cell.generated_tokens.mean,
|
||||
minGeneratedTokens: cell.generated_tokens.min,
|
||||
maxGeneratedTokens: cell.generated_tokens.max,
|
||||
},
|
||||
]),
|
||||
),
|
||||
totalPass: Object.values(task.conditions).reduce(
|
||||
(total, cell) => total + cell.strict_complete_success,
|
||||
0,
|
||||
),
|
||||
totalOutputs: 16,
|
||||
})),
|
||||
]),
|
||||
);
|
||||
|
||||
const periodDirection = Object.fromEntries(
|
||||
Object.entries(analysis.prior_direction_check).map(([domain, row]) => {
|
||||
const values = Object.values(
|
||||
row.period_shortens_mean_tokens.by_source,
|
||||
);
|
||||
return [domain, {
|
||||
shorter: values.filter(Boolean).length,
|
||||
sources: values.length,
|
||||
bySource: row.period_shortens_mean_tokens.by_source,
|
||||
}];
|
||||
}),
|
||||
);
|
||||
const systemEosDirection = Object.fromEntries(
|
||||
Object.entries(analysis.prior_direction_check).map(([domain, row]) => {
|
||||
const values = Object.values(
|
||||
row.system_on_raises_natural_eos_rate.by_source,
|
||||
);
|
||||
return [domain, {
|
||||
raises: values.filter(Boolean).length,
|
||||
sources: values.length,
|
||||
bySource: row.system_on_raises_natural_eos_rate.by_source,
|
||||
}];
|
||||
}),
|
||||
);
|
||||
|
||||
const result = {
|
||||
schemaVersion: 1,
|
||||
capturedAt: sampling.captured_at,
|
||||
contract: {
|
||||
protocolId: sampling.protocol_id,
|
||||
model: sampling.model.repo,
|
||||
revision: sampling.model.revision,
|
||||
conditions,
|
||||
conditionLabels,
|
||||
domains: Object.keys(analysis.contract.sources_by_domain),
|
||||
domainLabels,
|
||||
sources: analysis.contract.sources,
|
||||
sourcesPerDomain: analysis.contract.sources_per_domain,
|
||||
seedsPerCell: analysis.contract.seeds_per_source_condition,
|
||||
outputs: analysis.contract.outputs,
|
||||
baseSeeds: sampling.seed_contract.executed_base_seeds,
|
||||
decode: {
|
||||
doSample: sampling.generation_contract.do_sample,
|
||||
temperature: sampling.generation_contract.temperature,
|
||||
topP: sampling.generation_contract.top_p,
|
||||
topK: sampling.generation_contract.top_k,
|
||||
maxNewTokens: sampling.generation_contract.max_new_tokens,
|
||||
},
|
||||
sourceIsPrimaryCoverageUnit: (
|
||||
analysis.contract.source_is_primary_coverage_unit
|
||||
),
|
||||
seedIsWithinSourceRepeat: (
|
||||
analysis.contract.seed_is_within_source_repeat
|
||||
),
|
||||
noPopulationConfidenceIntervals: (
|
||||
analysis.contract.no_population_confidence_intervals
|
||||
),
|
||||
noPValues: analysis.contract.no_p_values,
|
||||
batchSeedAlignedNotCommonRandomNumbers: (
|
||||
sampling.seed_contract.batch_seed_aligned_not_common_random_numbers
|
||||
),
|
||||
},
|
||||
headline: {
|
||||
...analysis.overall,
|
||||
promptHashExact: sampling.source_contract.prompt_hash_audit.exact,
|
||||
promptHashCells: sampling.source_contract.prompt_hash_audit.cells,
|
||||
firstTwoSeedComparableCells: (
|
||||
sampling.summary.first_two_seeds.comparable_cells
|
||||
),
|
||||
firstTwoSeedDifferentTrajectories: (
|
||||
sampling.summary.first_two_seeds.different_trajectories
|
||||
),
|
||||
reproducedCells: (
|
||||
reproduction.summary.all_preregistered_fields_exact
|
||||
),
|
||||
reproductionCells: reproduction.summary.cells,
|
||||
codeAstParse: evaluation.summary.code.ast_parse,
|
||||
codeExecuted: evaluation.summary.code.executed,
|
||||
codeStatuses: evaluation.summary.code.execution_statuses,
|
||||
codeUniqueExecutionKeys: (
|
||||
evaluation.sandbox.unique_code_cache_entries
|
||||
),
|
||||
},
|
||||
sourceMeta,
|
||||
sourcesByDomain: analysis.contract.sources_by_domain,
|
||||
sourceCells: analysis.source_condition_cells,
|
||||
domainConditions: analysis.domain_condition_summary,
|
||||
sourceContrasts: analysis.source_contrasts,
|
||||
domainContrasts: analysis.domain_contrasts,
|
||||
periodDirection,
|
||||
systemEosDirection,
|
||||
taskTotals,
|
||||
taskFailures,
|
||||
evalRows,
|
||||
reproduction: reproduction.summary,
|
||||
artifacts: {
|
||||
sampling: samplingArtifact,
|
||||
evaluation: evaluationArtifact,
|
||||
rerun: rerunArtifact,
|
||||
reproduction: reproductionArtifact,
|
||||
analysis: artifact(paths.analysis),
|
||||
},
|
||||
execution: {
|
||||
generationSeconds: sampling.sources.reduce(
|
||||
(total, source) => total + source.runs.reduce(
|
||||
(subtotal, run) => subtotal + run.generation_seconds,
|
||||
0,
|
||||
),
|
||||
0,
|
||||
),
|
||||
peakCudaMemoryAllocatedBytes: (
|
||||
sampling.execution.peak_cuda_memory_allocated_bytes
|
||||
),
|
||||
torch: sampling.execution.torch,
|
||||
transformers: sampling.execution.transformers,
|
||||
deviceMap: sampling.execution.device_map,
|
||||
sandbox: evaluation.sandbox,
|
||||
},
|
||||
claimBoundary: [
|
||||
...sampling.claim_boundary,
|
||||
...evaluation.claim_boundary,
|
||||
...analysis.claim_boundary,
|
||||
...reproduction.claim_boundary,
|
||||
],
|
||||
};
|
||||
|
||||
writeFileSync(paths.output, `${JSON.stringify(result, null, 2)}\n`);
|
||||
console.log(JSON.stringify({
|
||||
output: paths.output,
|
||||
...artifact(paths.output),
|
||||
headline: result.headline,
|
||||
periodDirection: result.periodDirection,
|
||||
}, null, 2));
|
||||
@@ -82,6 +82,8 @@ const overview = await evaluate(`(() => ({
|
||||
behaviorEdges: document.querySelectorAll("[data-behavior-map-edge]").length,
|
||||
completionDepthTabs: document.querySelectorAll("[data-cd-tab]").length,
|
||||
completionDepthPanels: document.querySelectorAll("[data-cd-panel]").length,
|
||||
crossSourceTabs: document.querySelectorAll("[data-cs-tab]").length,
|
||||
crossSourcePanels: document.querySelectorAll("[data-cs-panel]").length,
|
||||
hiddenStages: document.querySelectorAll("[data-hidden-stage]").length,
|
||||
routerLayers: document.querySelectorAll("[data-router-layer]").length,
|
||||
branches: document.querySelectorAll(".branch-grid > a").length,
|
||||
@@ -1210,14 +1212,15 @@ console.log(JSON.stringify(report, null, 2));
|
||||
const numeric = (text) => Number.parseFloat(text.replaceAll(",", ""));
|
||||
const failures = [];
|
||||
if (!overview.title.includes("为什么转向")) failures.push("专题标题异常");
|
||||
if (overview.sections !== 29 || overview.tocLinks !== 29) failures.push("二十八个编号专题加阅读链的目录结构异常");
|
||||
if (overview.sections !== 30 || overview.tocLinks !== 30) failures.push("二十九个编号专题加阅读链的目录结构异常");
|
||||
if (overview.ledgers !== 24 || overview.waves !== 10) failures.push("二十四张问题账或十次转向结构异常");
|
||||
if (overview.paperLinks !== 60 || overview.branches !== 5 || overview.followups !== 1) failures.push("论文链、旁支或公开后续标记异常");
|
||||
if (overview.labTabs !== 4 || overview.labPanels !== 4) failures.push("四联实验结构异常");
|
||||
if (overview.artifactTabs !== 13 || overview.artifactPanels !== 13 || overview.artifactLayers !== 27) failures.push("真实权重十三联实验结构异常");
|
||||
if (overview.behaviorTabs !== 4 || overview.behaviorPanels !== 4 || overview.behaviorSources !== 16 || overview.behaviorEdges !== 10) failures.push("Chat 行为实验结构异常");
|
||||
if (overview.completionDepthTabs !== 4 || overview.completionDepthPanels !== 4 || overview.hiddenStages !== 29 || overview.routerLayers !== 26) failures.push("Chat 完成度与全深度实验结构异常");
|
||||
if (overview.heroLabs !== "20 个可操作实验") failures.push("DeepSeek 实验总数账异常");
|
||||
if (overview.crossSourceTabs !== 4 || overview.crossSourcePanels !== 4) failures.push("跨来源采样实验结构异常");
|
||||
if (overview.heroLabs !== "21 个可操作实验") failures.push("DeepSeek 实验总数账异常");
|
||||
if (overview.navLinks !== 20 || home.navLinks !== 20 || mobile.mobileLinks !== 20 || overview.activeNav !== "DeepSeek") failures.push("全站导航未同步 DeepSeek");
|
||||
if (overview.documentOverflow > 1 || mobile.documentOverflow > 1) failures.push("桌面或移动端存在文档级横向溢出");
|
||||
if (capacity.initial.panel !== "capacity" || capacity.initial.total !== "32.1× FFN" || capacity.initial.active !== "1.13× FFN") failures.push("V3 稀疏容量初始账异常");
|
||||
|
||||
@@ -0,0 +1,314 @@
|
||||
import { writeFileSync } from "node:fs";
|
||||
|
||||
const cdpPort = process.env.CDP_PORT ?? "9230";
|
||||
const baseUrl = process.env.SITE_URL ?? "http://127.0.0.1:4327";
|
||||
const pages = await fetch(`http://127.0.0.1:${cdpPort}/json/list`)
|
||||
.then((response) => response.json());
|
||||
const page = pages.find((entry) => entry.type === "page");
|
||||
if (!page) throw new Error(`CDP ${cdpPort} 没有可用页面`);
|
||||
|
||||
const socket = new WebSocket(page.webSocketDebuggerUrl);
|
||||
await new Promise((resolve, reject) => {
|
||||
socket.addEventListener("open", resolve, { once: true });
|
||||
socket.addEventListener("error", reject, { once: true });
|
||||
});
|
||||
|
||||
let nextId = 0;
|
||||
const pending = new Map();
|
||||
const exceptions = [];
|
||||
socket.addEventListener("message", (event) => {
|
||||
const message = JSON.parse(event.data);
|
||||
if (message.id && pending.has(message.id)) {
|
||||
const { resolve, reject } = pending.get(message.id);
|
||||
pending.delete(message.id);
|
||||
if (message.error) reject(new Error(message.error.message));
|
||||
else resolve(message.result);
|
||||
}
|
||||
if (message.method === "Runtime.exceptionThrown") {
|
||||
exceptions.push(
|
||||
message.params.exceptionDetails.exception?.description
|
||||
?? message.params.exceptionDetails.text,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const command = (method, params = {}) => new Promise((resolve, reject) => {
|
||||
const id = ++nextId;
|
||||
pending.set(id, { resolve, reject });
|
||||
socket.send(JSON.stringify({ id, method, params }));
|
||||
});
|
||||
const pause = (milliseconds) => new Promise(
|
||||
(resolve) => setTimeout(resolve, milliseconds),
|
||||
);
|
||||
const evaluate = async (expression) => {
|
||||
const result = await command("Runtime.evaluate", {
|
||||
expression,
|
||||
returnByValue: true,
|
||||
awaitPromise: true,
|
||||
});
|
||||
if (result.exceptionDetails) {
|
||||
throw new Error(
|
||||
result.exceptionDetails.exception?.description
|
||||
?? result.exceptionDetails.text,
|
||||
);
|
||||
}
|
||||
return result.result.value;
|
||||
};
|
||||
const screenshot = async (path) => {
|
||||
const result = await command("Page.captureScreenshot", {
|
||||
format: "png",
|
||||
captureBeyondViewport: false,
|
||||
});
|
||||
writeFileSync(path, Buffer.from(result.data, "base64"));
|
||||
};
|
||||
const assert = (condition, message) => {
|
||||
if (!condition) throw new Error(message);
|
||||
};
|
||||
|
||||
await command("Page.enable");
|
||||
await command("Runtime.enable");
|
||||
await command("Emulation.setDeviceMetricsOverride", {
|
||||
width: 1440,
|
||||
height: 1100,
|
||||
deviceScaleFactor: 1,
|
||||
mobile: false,
|
||||
});
|
||||
await command("Page.navigate", { url: `${baseUrl}/deepseek/` });
|
||||
for (let attempt = 0; attempt < 100; attempt += 1) {
|
||||
await pause(100);
|
||||
if (await evaluate("document.readyState === 'complete'")) break;
|
||||
}
|
||||
|
||||
const overview = await evaluate(`(() => {
|
||||
const root = document.querySelector("[data-cross-source-lab]");
|
||||
if (!root) return null;
|
||||
document.documentElement.style.scrollBehavior = "auto";
|
||||
window.scrollTo(0, root.getBoundingClientRect().top + window.scrollY);
|
||||
const facts = Object.fromEntries(
|
||||
[...root.querySelectorAll(".cs-ledger article")].map((node) => [
|
||||
node.querySelector("span").textContent.trim(),
|
||||
node.querySelector("b").textContent.trim(),
|
||||
]),
|
||||
);
|
||||
return {
|
||||
tabs: root.querySelectorAll("[data-cs-tab]").length,
|
||||
panels: root.querySelectorAll("[data-cs-panel]").length,
|
||||
active: root.querySelector("[data-cs-panel]:not([hidden])")?.dataset.csPanel,
|
||||
sourceCards: root.querySelectorAll("[data-cs-source-cards] > article").length,
|
||||
seedDots: root.querySelectorAll(".seed-dots > i").length,
|
||||
outputCount: root.querySelector("[data-cs-output-count]").textContent.trim(),
|
||||
naturalEos: root.querySelector("[data-cs-natural-eos]").textContent.trim(),
|
||||
facts,
|
||||
labs: [...document.querySelectorAll(".page-facts > div")]
|
||||
.find((node) => node.querySelector("dt")?.textContent.trim() === "LABS")
|
||||
?.querySelector("dd")?.textContent.trim(),
|
||||
status: [...document.querySelectorAll(".page-facts > div")]
|
||||
.find((node) => node.querySelector("dt")?.textContent.trim() === "STATUS")
|
||||
?.querySelector("dd")?.textContent.trim(),
|
||||
overflow: document.documentElement.scrollWidth
|
||||
- document.documentElement.clientWidth,
|
||||
};
|
||||
})()`);
|
||||
await pause(250);
|
||||
await screenshot("/tmp/llm-atlas-cross-source-desktop.png");
|
||||
|
||||
const hierarchySwitch = await evaluate(`(() => {
|
||||
const root = document.querySelector("[data-cross-source-lab]");
|
||||
const domain = root.querySelector("[data-cs-domain]");
|
||||
const condition = root.querySelector("[data-cs-condition]");
|
||||
domain.value = "code";
|
||||
domain.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
condition.value = "s1_period";
|
||||
condition.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
return {
|
||||
cards: [...root.querySelectorAll("[data-cs-source-cards] > article")].map((node) => ({
|
||||
id: node.dataset.sourceId,
|
||||
eos: node.querySelector("header em").textContent.trim(),
|
||||
footer: node.querySelector(":scope > p").textContent.trim(),
|
||||
dots: node.querySelectorAll(".seed-dots > i").length,
|
||||
})),
|
||||
outputCount: root.querySelector("[data-cs-output-count]").textContent.trim(),
|
||||
naturalEos: root.querySelector("[data-cs-natural-eos]").textContent.trim(),
|
||||
};
|
||||
})()`);
|
||||
|
||||
const taskMatrices = await evaluate(`(() => {
|
||||
const root = document.querySelector("[data-cross-source-lab]");
|
||||
root.querySelector('[data-cs-tab="tasks"]').click();
|
||||
const read = () => ({
|
||||
active: root.querySelector("[data-cs-panel]:not([hidden])").dataset.csPanel,
|
||||
total: root.querySelector("[data-cs-task-total]").textContent.trim(),
|
||||
rows: [...root.querySelectorAll("[data-cs-task-matrix] > div")].map((row) => ({
|
||||
id: row.dataset.taskId,
|
||||
cells: [...row.querySelectorAll("b")].map((cell) => cell.textContent.trim()),
|
||||
total: row.querySelector("strong").textContent.trim(),
|
||||
})),
|
||||
range: root.querySelector("[data-cs-task-range]").textContent.trim(),
|
||||
interaction: root.querySelector("[data-cs-task-interaction]").textContent.trim(),
|
||||
failure: root.querySelector("[data-cs-task-failure]").textContent.trim(),
|
||||
});
|
||||
const math = read();
|
||||
root.querySelector('[data-cs-task-domain="code"]').click();
|
||||
const code = read();
|
||||
return { math, code };
|
||||
})()`);
|
||||
await pause(150);
|
||||
await screenshot("/tmp/llm-atlas-cross-source-task-matrix.png");
|
||||
|
||||
const directions = await evaluate(`(() => {
|
||||
const root = document.querySelector("[data-cross-source-lab]");
|
||||
root.querySelector('[data-cs-tab="directions"]').click();
|
||||
const select = root.querySelector("[data-cs-direction-domain]");
|
||||
const read = () => ({
|
||||
active: root.querySelector("[data-cs-panel]:not([hidden])").dataset.csPanel,
|
||||
shorter: root.querySelector("[data-cs-shorter]").textContent.trim(),
|
||||
mean: root.querySelector("[data-cs-domain-mean]").textContent.trim(),
|
||||
median: root.querySelector("[data-cs-domain-median]").textContent.trim(),
|
||||
rows: [...root.querySelectorAll("[data-cs-direction-rows] > article")].map((row) => ({
|
||||
id: row.dataset.directionSource,
|
||||
value: row.querySelector("b").textContent.trim(),
|
||||
dotClass: row.querySelector("u").className,
|
||||
})),
|
||||
});
|
||||
select.value = "english";
|
||||
select.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
const english = read();
|
||||
select.value = "code";
|
||||
select.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
const code = read();
|
||||
return { english, code };
|
||||
})()`);
|
||||
|
||||
const keyboard = await evaluate(`(() => {
|
||||
const root = document.querySelector("[data-cross-source-lab]");
|
||||
const first = root.querySelector('[data-cs-tab="hierarchy"]');
|
||||
first.click();
|
||||
first.focus();
|
||||
first.dispatchEvent(new KeyboardEvent("keydown", {
|
||||
key: "ArrowRight", bubbles: true,
|
||||
}));
|
||||
return {
|
||||
selected: root.querySelector('[data-cs-tab][aria-selected="true"]').dataset.csTab,
|
||||
active: root.querySelector("[data-cs-panel]:not([hidden])").dataset.csPanel,
|
||||
focused: document.activeElement.dataset.csTab,
|
||||
};
|
||||
})()`);
|
||||
|
||||
const reproduction = await evaluate(`(() => {
|
||||
const root = document.querySelector("[data-cross-source-lab]");
|
||||
root.querySelector('[data-cs-tab="reproduction"]').click();
|
||||
return {
|
||||
fields: [...root.querySelectorAll(".repro-fields article")].map((node) => (
|
||||
node.querySelector("b").textContent.trim()
|
||||
)),
|
||||
artifacts: [...root.querySelectorAll(".hash-chain article")].map((node) => ({
|
||||
label: node.querySelector("span").textContent.trim(),
|
||||
hash: node.querySelector("b").textContent.trim(),
|
||||
})),
|
||||
active: root.querySelector("[data-cs-panel]:not([hidden])").dataset.csPanel,
|
||||
};
|
||||
})()`);
|
||||
|
||||
await command("Emulation.setDeviceMetricsOverride", {
|
||||
width: 390,
|
||||
height: 844,
|
||||
deviceScaleFactor: 1,
|
||||
mobile: true,
|
||||
});
|
||||
await pause(300);
|
||||
const mobile = await evaluate(`(() => {
|
||||
const root = document.querySelector("[data-cross-source-lab]");
|
||||
root.querySelector('[data-cs-tab="tasks"]').click();
|
||||
root.scrollIntoView();
|
||||
return {
|
||||
documentOverflow: document.documentElement.scrollWidth
|
||||
- document.documentElement.clientWidth,
|
||||
rootOverflow: root.scrollWidth - root.clientWidth,
|
||||
matrixWidth: root.querySelector("[data-cs-task-matrix]").getBoundingClientRect().width,
|
||||
viewport: window.innerWidth,
|
||||
};
|
||||
})()`);
|
||||
await screenshot("/tmp/llm-atlas-cross-source-mobile.png");
|
||||
|
||||
assert(overview, "找不到跨来源采样实验");
|
||||
assert(overview.tabs === 4 && overview.panels === 4, "四页签/面板合同异常");
|
||||
assert(overview.active === "hierarchy", "初始面板不是 hierarchy");
|
||||
assert(overview.sourceCards === 4 && overview.seedDots === 16, "source/seed 层级渲染异常");
|
||||
assert(overview.outputCount === "16 / 16", "初始输出总账异常");
|
||||
assert(overview.facts.SOURCES === "16", "source headline 异常");
|
||||
assert(overview.facts["SAMPLED OUTPUTS"] === "256", "output headline 异常");
|
||||
assert(overview.facts["NATURAL EOS"] === "250 / 256", "EOS headline 异常");
|
||||
assert(overview.facts["MATH · STRICT"] === "47 / 64", "Math headline 异常");
|
||||
assert(overview.facts["CODE · TESTS"] === "52 / 64", "Code headline 异常");
|
||||
assert(overview.labs === "21 个可操作实验", "DeepSeek LABS 总账异常");
|
||||
assert(overview.status === "七轮 · 512 条采样", "DeepSeek STATUS 总账异常");
|
||||
assert(overview.overflow <= 1, `桌面横向溢出 ${overview.overflow}px`);
|
||||
|
||||
assert(hierarchySwitch.cards.length === 4, "Code source cards 数量异常");
|
||||
assert(hierarchySwitch.cards.every((row) => row.dots === 4), "每题 seed 数不为 4");
|
||||
assert(
|
||||
hierarchySwitch.cards.find((row) => row.id === "HumanEval/133")
|
||||
?.footer.includes("0 / 4 strict task pass"),
|
||||
"HumanEval/133 × s1_period 应为 0/4",
|
||||
);
|
||||
assert(hierarchySwitch.naturalEos === "16 / 16", "Code s1_period EOS 异常");
|
||||
|
||||
assert(taskMatrices.math.total === "47 / 64", "Math total 异常");
|
||||
assert(
|
||||
taskMatrices.math.rows.map((row) => row.cells.join(",")).join("|")
|
||||
=== "3 / 4,4 / 4,3 / 4,4 / 4|4 / 4,4 / 4,4 / 4,4 / 4|2 / 4,2 / 4,3 / 4,1 / 4|1 / 4,4 / 4,1 / 4,3 / 4",
|
||||
"Math 4×4 pass matrix 异常",
|
||||
);
|
||||
assert(taskMatrices.math.range === "8 → 16 / 16", "Math source range 异常");
|
||||
assert(taskMatrices.math.failure === "17 / 64", "Math failure 账异常");
|
||||
assert(taskMatrices.code.total === "52 / 64", "Code total 异常");
|
||||
assert(
|
||||
taskMatrices.code.rows.map((row) => row.cells.join(",")).join("|")
|
||||
=== "4 / 4,4 / 4,4 / 4,4 / 4|2 / 4,1 / 4,1 / 4,4 / 4|4 / 4,4 / 4,4 / 4,0 / 4|4 / 4,4 / 4,4 / 4,4 / 4",
|
||||
"Code 4×4 pass matrix 异常",
|
||||
);
|
||||
assert(taskMatrices.code.interaction === "1↑ · 2= · 1↓", "Code interaction 方向异常");
|
||||
assert(taskMatrices.code.failure === "12 / 64", "Code failure 账异常");
|
||||
|
||||
assert(directions.english.shorter === "1 / 4", "English 方向数异常");
|
||||
assert(directions.english.mean === "−8.5 tokens".replace("−", "-"), "English mean 异常");
|
||||
assert(directions.english.median === "+21.2 tokens", "English median 异常");
|
||||
assert(
|
||||
directions.english.rows.map((row) => row.value).join("|")
|
||||
=== "-121.0 tokens|+44.5 tokens|+41.0 tokens|+1.4 tokens",
|
||||
"English source contrast 异常",
|
||||
);
|
||||
assert(directions.code.shorter === "4 / 4", "Code 方向数异常");
|
||||
assert(directions.code.rows.every((row) => row.dotClass === "negative"), "Code 应四条全负");
|
||||
|
||||
assert(
|
||||
keyboard.selected === "tasks"
|
||||
&& keyboard.active === "tasks"
|
||||
&& keyboard.focused === "tasks",
|
||||
"页签键盘导航异常",
|
||||
);
|
||||
assert(reproduction.active === "reproduction", "复现面板切换异常");
|
||||
assert(reproduction.fields.length === 8, "复现字段数不为 8");
|
||||
assert(reproduction.fields.every((value) => value === "64 / 64"), "复现字段未全部 exact");
|
||||
assert(reproduction.artifacts.length === 5, "hash chain 工件数不为 5");
|
||||
assert(mobile.documentOverflow <= 1, `移动端 document 横向溢出 ${mobile.documentOverflow}px`);
|
||||
assert(mobile.rootOverflow <= 1, `移动端实验横向溢出 ${mobile.rootOverflow}px`);
|
||||
assert(mobile.matrixWidth <= mobile.viewport, "移动端任务矩阵超出 viewport");
|
||||
assert(exceptions.length === 0, `浏览器异常:${exceptions.join(" | ")}`);
|
||||
|
||||
console.log(JSON.stringify({
|
||||
overview,
|
||||
hierarchySwitch,
|
||||
taskMatrices,
|
||||
directions,
|
||||
keyboard,
|
||||
reproduction,
|
||||
mobile,
|
||||
screenshots: [
|
||||
"/tmp/llm-atlas-cross-source-desktop.png",
|
||||
"/tmp/llm-atlas-cross-source-task-matrix.png",
|
||||
"/tmp/llm-atlas-cross-source-mobile.png",
|
||||
],
|
||||
}, null, 2));
|
||||
|
||||
socket.close();
|
||||
Reference in New Issue
Block a user