import { writeFileSync } from "node:fs"; const cdpPort = process.env.CDP_PORT ?? "9225"; const baseUrl = process.env.SITE_URL ?? "http://127.0.0.1:4324"; 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.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.text); return result.result.value; }; const navigate = async (path) => { await command("Page.navigate", { url: `${baseUrl}${path}` }); for (let attempt = 0; attempt < 50; attempt += 1) { await pause(100); if (await evaluate("document.readyState === 'complete'")) return; } throw new Error(`${path} 加载超时`); }; const screenshot = async (path, full = false) => { const params = { format: "png", captureBeyondViewport: full }; if (full) { const metrics = await command("Page.getLayoutMetrics"); params.clip = { x: 0, y: 0, width: metrics.cssContentSize.width, height: metrics.cssContentSize.height, scale: 1, }; } const result = await command("Page.captureScreenshot", params); 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("/training-systems/"); await screenshot("/tmp/llm-atlas-training-systems-desktop.png"); const memory = await evaluate(`(() => { const root = document.querySelector("[data-systems-lab]"); root.querySelector('[data-memory-preset="single"]').click(); const single = { total: root.querySelector("[data-memory-total]").textContent, verdict: root.querySelector("[data-memory-verdict]").textContent, overflow: root.querySelector("[data-hbm-card]").classList.contains("is-overflow"), }; root.querySelector('[data-memory-preset="k3"]').click(); return { single, k3: { total: root.querySelector("[data-memory-total]").textContent, verdict: root.querySelector("[data-memory-verdict]").textContent, offload: root.querySelector('[data-memory-metric="offload"]').textContent, formula: root.querySelector("[data-memory-formula]").textContent, }, }; })()`); const mesh = await evaluate(`(() => { const root = document.querySelector("[data-systems-lab]"); root.querySelector('[data-system-tab="mesh"]').click(); root.querySelector('[data-mesh-preset="v3"]').click(); const v3 = { equation: root.querySelector("[data-mesh-equation]").textContent, status: root.querySelector("[data-mesh-capacity]").textContent, invalid: root.querySelector("[data-mesh-status]").classList.contains("is-invalid"), }; root.querySelector('[data-mesh-preset="invalid"]').click(); return { v3, invalid: { equation: root.querySelector("[data-mesh-equation]").textContent, status: root.querySelector("[data-mesh-capacity]").textContent, invalid: root.querySelector("[data-mesh-status]").classList.contains("is-invalid"), }, }; })()`); const pipeline = await evaluate(`(() => { const root = document.querySelector("[data-systems-lab]"); root.querySelector('[data-system-tab="pipeline"]').click(); root.querySelector('[data-schedule="1f1b"]').click(); const one = { copies: root.querySelector('[data-pipeline-metric="copies"]').textContent, reading: root.querySelector("[data-pipeline-reading]").textContent, rows: root.querySelectorAll(".timeline-row").length, }; root.querySelector('[data-schedule="dual"]').click(); return { one, dual: { copies: root.querySelector('[data-pipeline-metric="copies"]').textContent, reading: root.querySelector("[data-pipeline-reading]").textContent, note: root.querySelector("[data-pipeline-note]").textContent, }, }; })()`); const communication = await evaluate(`(() => { const root = document.querySelector("[data-systems-lab]"); root.querySelector('[data-system-tab="communication"]').click(); const overlap = root.querySelector('[data-comm-input="overlap"]'); overlap.value = "0"; overlap.dispatchEvent(new Event("input", { bubbles: true })); const exposed = { bytes: root.querySelector('[data-comm-metric="bytes"]').textContent, time: root.querySelector('[data-comm-metric="exposed"]').textContent, }; overlap.value = "95"; overlap.dispatchEvent(new Event("input", { bubbles: true })); return { exposed, hidden: { bytes: root.querySelector('[data-comm-metric="bytes"]').textContent, time: root.querySelector('[data-comm-metric="exposed"]').textContent, }, moe: { deep: root.querySelector('[data-moe-metric="deep-buffer"]').textContent, moon: root.querySelector('[data-moe-metric="moon-buffer"]').textContent, slots: root.querySelector('[data-moe-metric="slots"]').textContent, bars: root.querySelectorAll("[data-expert-rank]").length, }, }; })()`); const layout = await evaluate(`(() => { const nav = document.querySelector(".top-nav"); const meta = document.querySelector(".header-meta"); return { documentOverflow: document.documentElement.scrollWidth - document.documentElement.clientWidth, navGap: Number((meta.getBoundingClientRect().left - nav.getBoundingClientRect().right).toFixed(1)), navLinks: document.querySelectorAll(".top-nav a").length, articleSections: document.querySelectorAll(".article-section").length, paperLinks: document.querySelectorAll(".paper-chain a").length, labTabs: document.querySelectorAll("[data-system-tab]").length, }; })()`); await evaluate(`(() => { document.documentElement.style.scrollBehavior = "auto"; document.querySelector("[data-systems-lab]").scrollIntoView({ block: "start", behavior: "instant" }); })()`); await pause(150); await screenshot("/tmp/llm-atlas-training-systems-lab-desktop.png"); await command("Emulation.setDeviceMetricsOverride", { width: 390, height: 844, deviceScaleFactor: 1, mobile: true, }); await navigate("/training-systems/"); await screenshot("/tmp/llm-atlas-training-systems-mobile-closed.png"); const mobile = await evaluate(`(() => { const toggle = document.querySelector("#menu-toggle"); toggle.click(); return { documentOverflow: document.documentElement.scrollWidth - document.documentElement.clientWidth, menuVisible: getComputedStyle(toggle).display !== "none", menuOpen: toggle.getAttribute("aria-expanded"), title: document.querySelector("h1").innerText, }; })()`); await command("Emulation.setDeviceMetricsOverride", { width: 1440, height: 1100, deviceScaleFactor: 1, mobile: false, }); await navigate("/"); const home = await evaluate(`({ documentOverflow: document.documentElement.scrollWidth - document.documentElement.clientWidth, releaseCards: document.querySelectorAll(".release-card").length, firstRelease: document.querySelector(".release-card h2").textContent, navLinks: document.querySelectorAll(".top-nav a").length, })`); await evaluate(`document.querySelector("#new-chapters").scrollIntoView({ block: "start", behavior: "instant" })`); await pause(100); await screenshot("/tmp/llm-atlas-home-training-systems-release.png"); const report = { memory, mesh, pipeline, communication, layout, mobile, home, exceptions }; console.log(JSON.stringify(report, null, 2)); const numeric = (value) => Number.parseFloat(value); const failures = []; if (!memory.single.overflow || !memory.single.verdict.includes("OOM")) failures.push("单卡 OOM 场景未触发"); if (!memory.k3.formula.includes("14P") || !memory.k3.verdict.includes("可以放入")) failures.push("K3 分层存储预设异常"); if (mesh.v3.invalid || !mesh.v3.equation.includes("2,048")) failures.push("V3 设备网格异常"); if (!mesh.invalid.invalid || !mesh.invalid.status.includes("相差")) failures.push("无效设备网格没有被拒绝"); if (pipeline.one.rows !== 4 || pipeline.one.copies !== "1×") failures.push("1F1B 时间轴异常"); if (pipeline.dual.copies !== "2×" || !pipeline.dual.note.includes("near-zero")) failures.push("DualPipe 边界解释缺失"); if (communication.exposed.bytes !== communication.hidden.bytes) failures.push("overlap 错误改变了通信字节"); if (numeric(communication.exposed.time) <= numeric(communication.hidden.time)) failures.push("overlap 没有降低 exposed time"); if (communication.moe.bars !== 12 || !communication.moe.slots.includes("E/R")) failures.push("MoonEP 对照异常"); if (layout.articleSections !== 16 || layout.paperLinks !== 37 || layout.labTabs !== 4) failures.push("章节、论文或实验数量异常"); if (layout.documentOverflow > 0 || mobile.documentOverflow > 0 || home.documentOverflow > 0) failures.push("页面存在横向溢出"); if (layout.navGap < 0) failures.push(`桌面导航碰撞:${layout.navGap}px`); if (!mobile.menuVisible || mobile.menuOpen !== "true") failures.push("移动端菜单不可用"); if (home.releaseCards !== 7 || !home.firstRelease.includes("少几个比特")) failures.push("首页数值新章入口异常"); if (exceptions.length) failures.push(`浏览器脚本异常:${exceptions.join("; ")}`); socket.close(); if (failures.length) { failures.forEach((failure) => console.error(`- ${failure}`)); process.exit(1); }