From 3a60f2b8bd461e01dac4af0547147e1772dd2a4b Mon Sep 17 00:00:00 2001 From: Codex Date: Sat, 27 Jun 2026 08:45:45 +0000 Subject: [PATCH] fix: bind workbench terminal api lag to covered turns --- .../hwlab-node-web-observe-analyzer-source.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/scripts/src/hwlab-node-web-observe-analyzer-source.ts b/scripts/src/hwlab-node-web-observe-analyzer-source.ts index 3a106ef3..ae73a72f 100644 --- a/scripts/src/hwlab-node-web-observe-analyzer-source.ts +++ b/scripts/src/hwlab-node-web-observe-analyzer-source.ts @@ -2316,6 +2316,7 @@ function detectWorkbenchTerminalApiDomLag(samples, network) { const overBudget = []; for (const event of terminalEvents) { const pageSamples = rowsByPage.get(event.pageKey) || []; + if (pageSamples.length === 0 || event.tsMs < pageSamples[0].tsMs) continue; const firstAfter = firstWorkbenchSampleAfter(pageSamples, event.tsMs, event.tsMs + windowMs, event); const resolved = firstWorkbenchSampleAfter(pageSamples, event.tsMs, event.tsMs + windowMs, event, (row) => workbenchSampleHasTerminalProjection(row.sample, event)); const deltaMs = resolved ? Math.max(0, Math.round(resolved.tsMs - event.tsMs)) : null; @@ -2363,6 +2364,8 @@ function compactWorkbenchTerminalApiEvent(item) { if (!summary || Number(summary.terminalEvidenceCount ?? 0) <= 0) return null; const parsed = parseApiDomLagUrl(item.url); if (!String(parsed.path || "").startsWith("/v1/workbench/") && parsed.path !== "/v1/agent/chat" && parsed.path !== "/v1/agent/chat/steer") return null; + const routeKind = summary.pathKind ?? apiDomLagRouteKind(parsed.path); + if (!isReliableWorkbenchTerminalApiEvent(summary, routeKind)) return null; const terminalTraceIds = uniqueSorted(Array.isArray(summary.terminalTraceIds) ? summary.terminalTraceIds : []).slice(0, 12); if (terminalTraceIds.length === 0) return null; const tsMs = Date.parse(item.ts || ""); @@ -2375,7 +2378,7 @@ function compactWorkbenchTerminalApiEvent(item) { pageKey: String(item.pageRole || "control") + ":" + String(item.pageId || "default"), method: String(item.method || "GET").toUpperCase(), path: parsed.path, - routeKind: summary.pathKind ?? apiDomLagRouteKind(parsed.path), + routeKind, traceIds: terminalTraceIds, observedTraceIds: uniqueSorted([...(Array.isArray(summary.traceIds) ? summary.traceIds : []), parsed.traceId].filter(Boolean)).slice(0, 12), sessionIds: uniqueSorted([...(Array.isArray(summary.sessionIds) ? summary.sessionIds : []), parsed.sessionId].filter(Boolean)).slice(0, 12), @@ -2388,6 +2391,12 @@ function compactWorkbenchTerminalApiEvent(item) { }; } +function isReliableWorkbenchTerminalApiEvent(summary, routeKind) { + if (!summary || routeKind !== "workbench-turn") return false; + if (Number(summary.terminalEvidenceCount ?? 0) <= 0) return false; + return Number(summary.runningStatusCount ?? 0) <= 0; +} + function firstWorkbenchSampleAfter(rows, startMs, endMs, event, predicate = null) { for (const row of rows || []) { if (row.tsMs < startMs) continue; @@ -2407,7 +2416,8 @@ function workbenchSampleMatchesTerminalEvent(sample, event) { } if (event.traceIds.length > 0) { const traces = sampleTraceIds(sample); - if (traces.size > 0 && !event.traceIds.some((id) => traces.has(id))) return false; + if (traces.size === 0) return false; + if (!event.traceIds.some((id) => traces.has(id))) return false; } return true; } @@ -2415,7 +2425,7 @@ function workbenchSampleMatchesTerminalEvent(sample, event) { function workbenchSampleHasTerminalProjection(sample, event) { const traceIds = event.traceIds.length > 0 ? event.traceIds : Array.from(sampleTraceIds(sample)); if (traceIds.length === 0) return false; - return traceIds.some((traceId) => workbenchFinalMessageVisible(sample, traceId) && workbenchTraceRowsForTrace(sample, traceId).length > 0); + return traceIds.some((traceId) => workbenchTraceRowsForTrace(sample, traceId).length > 0 && (workbenchFinalMessageVisible(sample, traceId) || workbenchTerminalTurnVisible(sample, traceId))); } function compactWorkbenchProjectionSample(sample, event = null) {