import { writeFileSync } from "node:fs"; const cdpPort = process.env.CDP_PORT ?? "9231"; const baseUrl = process.env.SITE_URL ?? "http://127.0.0.1:4330"; 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 navigate = async (path) => { await command("Page.navigate", { url: `${baseUrl}${path}` }); for (let attempt = 0; attempt < 100; attempt += 1) { await pause(100); if (await evaluate("document.readyState === 'complete'")) return; } throw new Error(`${path} 加载超时`); }; const screenshot = async (path) => { const result = await command("Page.captureScreenshot", { format: "png", captureBeyondViewport: false }); writeFileSync(path, Buffer.from(result.data, "base64")); }; await command("Page.enable"); await command("Runtime.enable"); await command("Emulation.setDeviceMetricsOverride", { width: 1440, height: 1100, deviceScaleFactor: 1, mobile: false, }); await navigate("/k3/"); const desktop = await evaluate(`(() => { const root = document.querySelector("[data-forward-lab]"); root.scrollIntoView({ block: "start", behavior: "instant" }); window.scrollBy(0, -78); const text = (selector) => root.querySelector(selector)?.textContent.replace(/\\s+/g, " ").trim(); const panel = () => root.querySelector("[data-forward-panel]:not([hidden])")?.dataset.forwardPanel; const setSelect = (selector, value) => { const node = root.querySelector(selector); node.value = value; node.dispatchEvent(new Event("change", { bubbles: true })); }; const initial = { panel: panel(), tabs: root.querySelectorAll("[data-forward-tab]").length, panels: root.querySelectorAll("[data-forward-panel]").length, ledger: root.querySelectorAll(".forward-ledger article").length, targetGroups: root.querySelectorAll(".group-map article.target").length, spikeLayers: root.querySelectorAll(".group-map i.spike").length, variants: root.querySelectorAll(".variant-grid article").length, boundary: root.textContent.includes("K3 的训练尖峰已被定位") && root.textContent.includes("Figure 5(c)") && root.textContent.includes("训练期架构消融"), }; root.querySelector('[data-forward-tab="trajectory"]').click(); const trajectoryInitial = { panel: panel(), state: text("[data-forward-trajectory-state]"), points: root.querySelectorAll("[data-forward-trajectory-series] circle").length, lines: root.querySelectorAll("[data-forward-trajectory-series] polyline").length, readouts: [...root.querySelectorAll("[data-forward-trajectory-readout] article")] .map((node) => node.textContent.replace(/\\s+/g, " ").trim()), }; setSelect("[data-forward-trajectory-seed]", "2026073002"); root.querySelector('[data-forward-trajectory-metric="peak_normalized"]').click(); const trajectoryChanged = { state: text("[data-forward-trajectory-state]"), readouts: [...root.querySelectorAll("[data-forward-trajectory-readout] article")] .map((node) => node.textContent.replace(/\\s+/g, " ").trim()), }; root.querySelector('[data-forward-tab="gate"]').click(); const gate = { panel: panel(), status: text(".status-banner"), rows: root.querySelectorAll(".gate-table tbody tr").length, passedRows: root.querySelectorAll(".gate-table tbody td.good:last-child").length, quality: text(".gate-layout aside"), claims: root.querySelectorAll(".claim-pair article").length, }; root.querySelector('[data-forward-tab="interaction"]').click(); const interactionInitial = { panel: panel(), state: text("[data-forward-interaction-state]"), cells: root.querySelectorAll("[data-forward-interaction-cells] article").length, summary: text("[data-forward-interaction-summary]"), }; root.querySelector('[data-forward-interaction-metric="peak_normalized"]').click(); const interactionChanged = { state: text("[data-forward-interaction-state]"), summary: text("[data-forward-interaction-summary]"), }; root.querySelector('[data-forward-tab="spectrum"]').click(); const spectrumInitial = { panel: panel(), state: text("[data-forward-spectrum-state]"), points: root.querySelectorAll("[data-forward-spectrum-points] circle").length, contrast: text("[data-forward-spectrum-contrast]"), peak: text("[data-forward-spectrum-peak]"), layer: text("[data-forward-spectrum-layer]"), audits: root.querySelectorAll(".audit-grid article").length, replay: root.textContent.includes("scientific exact"), }; setSelect("[data-forward-spectrum-seed]", "2026073002"); setSelect("[data-forward-spectrum-variant]", "uniform_groups_6_7_forward"); const spectrumChanged = { state: text("[data-forward-spectrum-state]"), points: root.querySelectorAll("[data-forward-spectrum-points] circle").length, contrast: text("[data-forward-spectrum-contrast]"), peak: text("[data-forward-spectrum-peak]"), layer: text("[data-forward-spectrum-layer]"), }; const first = root.querySelector('[data-forward-tab="contract"]'); first.focus(); first.dispatchEvent(new KeyboardEvent("keydown", { key: "ArrowRight", bubbles: true })); const keyboard = { selected: root.querySelector('[data-forward-tab][aria-selected="true"]').dataset.forwardTab, panel: panel(), }; return { initial, trajectoryInitial, trajectoryChanged, gate, interactionInitial, interactionChanged, spectrumInitial, spectrumChanged, keyboard, documentOverflow: document.documentElement.scrollWidth - document.documentElement.clientWidth, rootOverflow: root.scrollWidth - root.clientWidth, }; })()`); await pause(180); await screenshot("/tmp/llm-atlas-k3-attnres-forward-desktop.png"); await command("Emulation.setDeviceMetricsOverride", { width: 390, height: 844, deviceScaleFactor: 1, mobile: true, }); await navigate("/k3/"); const mobile = await evaluate(`(() => { const root = document.querySelector("[data-forward-lab]"); root.scrollIntoView({ block: "start", behavior: "instant" }); window.scrollBy(0, -64); root.querySelector('[data-forward-tab="gate"]').click(); const table = root.querySelector(".gate-table-wrap"); const gateTableScrolls = table.scrollWidth > table.clientWidth; root.querySelector('[data-forward-tab="spectrum"]').click(); return { tabs: root.querySelectorAll("[data-forward-tab]").length, visiblePanel: root.querySelector("[data-forward-panel]:not([hidden])")?.dataset.forwardPanel, points: root.querySelectorAll("[data-forward-spectrum-points] circle").length, audits: root.querySelectorAll(".audit-grid article").length, gateTableScrolls, documentOverflow: document.documentElement.scrollWidth - document.documentElement.clientWidth, rootOverflow: root.scrollWidth - root.clientWidth, }; })()`); await pause(180); await screenshot("/tmp/llm-atlas-k3-attnres-forward-mobile.png"); const failures = []; if (desktop.initial.panel !== "contract" || desktop.initial.tabs !== 5 || desktop.initial.panels !== 5 || desktop.initial.ledger !== 6 || desktop.initial.targetGroups !== 2 || desktop.initial.spikeLayers !== 5 || desktop.initial.variants !== 4) { failures.push("五视图、账本、group 或 selector map 结构异常"); } if (!desktop.initial.boundary) failures.push("reduced-model / K3 / Figure 5(c) claim boundary 缺失"); if (desktop.trajectoryInitial.panel !== "trajectory" || desktop.trajectoryInitial.points !== 24 || desktop.trajectoryInitial.lines !== 4 || desktop.trajectoryInitial.readouts.length !== 4 || !desktop.trajectoryInitial.state.includes("2026073001") || !desktop.trajectoryInitial.readouts.some((value) => value.includes("+73.5%"))) { failures.push("seed 1 contrast 训练轨迹异常"); } if (!desktop.trajectoryChanged.state.includes("2026073002") || !desktop.trajectoryChanged.state.includes("PEAK / MEAN") || !desktop.trajectoryChanged.readouts.some((value) => value.includes("+62.0%"))) { failures.push("trajectory seed / metric 切换异常"); } if (desktop.gate.panel !== "gate" || desktop.gate.rows !== 6 || desktop.gate.passedRows !== 6 || desktop.gate.claims !== 2 || !desktop.gate.status.includes("ATTENUATION ESTABLISHED") || !desktop.gate.status.includes("6 / 6") || !desktop.gate.status.includes("4 / 4") || !desktop.gate.quality.includes("+0.0066")) { failures.push("冻结主门或 BPC quality readout 异常"); } if (desktop.interactionInitial.panel !== "interaction" || desktop.interactionInitial.cells !== 3 || !desktop.interactionInitial.state.includes("8,000") || !desktop.interactionInitial.summary.includes("-0.367") || !desktop.interactionChanged.state.includes("PEAK / MEAN") || !desktop.interactionChanged.summary.includes("-0.170")) { failures.push("I67 描述性 residual 切换异常"); } if (desktop.spectrumInitial.panel !== "spectrum" || desktop.spectrumInitial.points !== 32 || desktop.spectrumInitial.contrast !== "3.046×" || desktop.spectrumInitial.peak !== "3.219×" || desktop.spectrumInitial.layer !== "L21" || desktop.spectrumInitial.audits !== 5 || !desktop.spectrumInitial.replay) { failures.push("reference 32 层谱或 replay 审计异常"); } if (desktop.spectrumChanged.points !== 32 || !desktop.spectrumChanged.state.includes("2026073002") || !desktop.spectrumChanged.state.includes("GROUPS 6+7") || desktop.spectrumChanged.contrast !== "0.758×" || desktop.spectrumChanged.peak !== "1.375×" || desktop.spectrumChanged.layer !== "L9") { failures.push("joint variant spectrum 切换异常"); } if (desktop.keyboard.selected !== "trajectory" || desktop.keyboard.panel !== "trajectory") { failures.push("键盘 tab 切换异常"); } if (desktop.documentOverflow > 1 || mobile.documentOverflow > 1) failures.push("页面出现文档级横向溢出"); if (desktop.rootOverflow > 1 || mobile.rootOverflow > 1) failures.push("Round 08 实验室出现横向溢出"); if (mobile.tabs !== 5 || mobile.visiblePanel !== "spectrum" || mobile.points !== 32 || mobile.audits !== 5 || !mobile.gateTableScrolls) { failures.push("390px 移动端布局或局部表格滚动异常"); } if (exceptions.length) failures.push(`运行时异常:${exceptions.join(" | ")}`); console.log(JSON.stringify({ desktop, mobile, exceptions }, null, 2)); socket.close(); if (failures.length) { console.error(`FAIL K3 AttnRes forward-training browser\n- ${failures.join("\n- ")}`); process.exit(1); } console.log("PASS K3 AttnRes forward-training browser interactions");