diff --git a/scripts/src/hwlab-node-impl.ts b/scripts/src/hwlab-node-impl.ts index 5b01bb8a..97ca7c45 100644 --- a/scripts/src/hwlab-node-impl.ts +++ b/scripts/src/hwlab-node-impl.ts @@ -887,15 +887,18 @@ function nodePerformanceArray(value: unknown): Record[] { } function nodePerformanceAnalysis(performance: Record, rows: Record[]): Record { - const networkErrors = rows.filter((row) => nodePerformanceString(row.outcome) === "network_error" || nodePerformanceString(row.problem) === "network_error" || nodePerformanceString(row.problem) === "network error"); - const blockedRows = rows.filter((row) => nodePerformanceString(row.tone) === "blocked" || nodePerformanceString(row.status) === "blocked"); + const actionableRows = rows.filter(nodePerformanceActionableProblem); + const networkErrors = actionableRows.filter((row) => nodePerformanceString(row.outcome) === "network_error" || nodePerformanceString(row.problem) === "network_error" || nodePerformanceString(row.problem) === "network error"); + const blockedRows = actionableRows.filter((row) => nodePerformanceString(row.tone) === "blocked" || nodePerformanceString(row.status) === "blocked"); const slowApiRows = rows.filter((row) => { const source = nodePerformanceString(row.source) ?? ""; const metric = nodePerformanceString(row.metric) ?? ""; const p95Seconds = nodePerformanceNumber(row.p95Seconds); - return (source.includes("api") || metric.includes("api") || (nodePerformanceString(row.route) ?? "").startsWith("/v1") || (nodePerformanceString(row.route) ?? "").startsWith("/health")) && (p95Seconds === null || p95Seconds >= 5); + return nodePerformanceActionableProblem(row) + && (source.includes("api") || metric.includes("api") || (nodePerformanceString(row.route) ?? "").startsWith("/v1") || (nodePerformanceString(row.route) ?? "").startsWith("/health")) + && (p95Seconds === null || p95Seconds >= 5); }); - const lcpRows = rows.filter((row) => { + const lcpRows = actionableRows.filter((row) => { const metric = `${nodePerformanceString(row.metric) ?? ""} ${nodePerformanceString(row.problem) ?? ""}`.toLowerCase(); return metric.includes("lcp") || metric.includes("largest contentful") || metric.includes("最大内容"); }); @@ -955,6 +958,16 @@ function nodePerformanceAnalysis(performance: Record, rows: Rec }; } +function nodePerformanceActionableProblem(row: Record): boolean { + const tone = nodePerformanceString(row.tone) ?? ""; + const status = nodePerformanceString(row.status) ?? ""; + if (tone === "blocked" || tone === "warn" || status === "blocked" || status === "warn") return true; + const sampleState = nodePerformanceString(row.sampleState) ?? ""; + if (sampleState && sampleState !== "ok") return false; + const problem = (nodePerformanceString(row.problem) ?? "").trim().toLowerCase(); + return Boolean(problem && problem !== "ok" && problem !== "low-sample" && problem !== "no-sample"); +} + function nodePerformanceEvidence(rows: Record[]): Record[] { return rows.slice(0, 8).map((row) => ({ source: nodePerformanceString(row.source),