From f51bf6b83091fde94faba5ffeac072c23357f483 Mon Sep 17 00:00:00 2001 From: Lyon <88232613+pikasTech@users.noreply.github.com> Date: Thu, 18 Jun 2026 00:43:45 +0800 Subject: [PATCH] fix: scope web probe trace fetch by project (#1443) --- scripts/web-live-dom-probe.mjs | 47 ++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/scripts/web-live-dom-probe.mjs b/scripts/web-live-dom-probe.mjs index 520eb35c..2cea5db5 100644 --- a/scripts/web-live-dom-probe.mjs +++ b/scripts/web-live-dom-probe.mjs @@ -277,9 +277,10 @@ export async function runProbe(args) { sessionSummary = summarizeSessionRun(actions, dom); traceSummary = summarizeTraceRun(traceSamples, dom, sessionSummary); performanceSummary = summarizeProbePerformance(actions, startedAt, traceSamples, traceSummary); + const degradedReason = runProbeDegradedReason({ traceSummary, sessionSummary, promptValidation }); result = { ok: true, - status: dom.requiredSelectors.workspace && dom.requiredSelectors.commandInput && dom.requiredSelectors.conversationList && promptValidation.ok ? "pass" : "blocked", + status: dom.requiredSelectors.workspace && dom.requiredSelectors.commandInput && dom.requiredSelectors.conversationList && promptValidation.ok && !degradedReason ? "pass" : "blocked", command: "web-live-dom-probe run", generatedAt: new Date().toISOString(), startedAt, @@ -296,7 +297,7 @@ export async function runProbe(args) { traceSamples, dom, promptValidation, - degradedReason: runProbeDegradedReason({ traceSummary, sessionSummary, promptValidation }), + degradedReason, artifacts: { reportPath, screenshotPath }, safety: { repoOwnedLauncher: true, @@ -846,6 +847,7 @@ function summarizeWorkspaceFetch(fetchResult) { error: fetchResult?.error ?? null, bodyPreview: fetchResult?.ok === true ? null : fetchResult?.bodyPreview ?? null, workspaceId: workspace?.workspaceId ?? null, + projectId: normalizeProbeProjectId(workspace?.projectId) ?? null, revision: workspace?.revision ?? null, selectedConversationId: workspace?.selectedConversationId ?? selected?.conversationId ?? null, selectedAgentSessionId: workspace?.selectedAgentSessionId ?? selected?.sessionId ?? null, @@ -870,6 +872,7 @@ function summarizeConversationsFetch(fetchResult) { count: conversations.length, items: conversations.slice(0, 16).map((item) => ({ conversationId: item?.conversationId ?? null, + projectId: normalizeProbeProjectId(item?.projectId) ?? null, sessionId: item?.sessionId ?? null, threadId: item?.threadId ?? null, status: item?.status ?? null, @@ -954,27 +957,37 @@ async function collectTraceTimelineSample(page, args, index) { const conversationId = firstNonEmpty(session.routeConversationId, session.api?.workspace?.selectedConversationId, session.activeTab?.conversationId); const conversation = conversationId ? session.api?.conversations?.items?.find((item) => item.conversationId === conversationId) ?? null : null; const traceId = firstNonEmpty(conversation?.lastTraceId, session.api?.workspace?.activeTraceId); + const traceProjectId = normalizeProbeProjectId(conversation?.projectId) ?? normalizeProbeProjectId(session.api?.workspace?.projectId) ?? normalizeProbeProjectId(args.projectId); const traceFetch = traceId - ? await fetchTraceSummaryWithRetry(page, args, traceId) + ? await fetchTraceSummaryWithRetry(page, args, traceId, traceProjectId) : { ok: false, traceId: null, degradedReason: "trace-id-missing", attempts: [] }; - return { ...dom, conversationId, sessionId: conversation?.sessionId ?? session.activeTab?.sessionId ?? null, traceId, traceFetch }; + return { ...dom, conversationId, projectId: traceProjectId, sessionId: conversation?.sessionId ?? session.activeTab?.sessionId ?? null, traceId, traceFetch }; } -async function fetchTraceSummaryWithRetry(page, args, traceId) { - const path = `/v1/agent/traces/${encodeURIComponent(traceId)}?projectId=${encodeURIComponent(args.projectId)}&sinceSeq=0&limit=20`; +async function fetchTraceSummaryWithRetry(page, args, traceId, projectId) { + const paths = [traceSummaryPath(traceId, projectId), ...(projectId ? [traceSummaryPath(traceId, null)] : [])]; const attempts = []; - for (let attempt = 1; attempt <= 3; attempt += 1) { - const fetched = await fetchJsonFromPage(page, path, { timeoutMs: 8000 }); - const summary = summarizeTraceFetch(fetched, traceId, attempt); - attempts.push(summary); - if (summary.ok) return { ...summary, attempts }; - if (attempt < 3) await page.waitForTimeout(500 * attempt); + for (const candidate of paths) { + for (let attempt = 1; attempt <= 3; attempt += 1) { + const fetched = await fetchJsonFromPage(page, candidate.path, { timeoutMs: 8000 }); + const summary = summarizeTraceFetch(fetched, traceId, attempt, candidate); + attempts.push(summary); + if (summary.ok) return { ...summary, attempts }; + if (summary.errorCode === "trace_project_mismatch" && candidate.projectId) break; + if (attempt < 3) await page.waitForTimeout(500 * attempt); + } } const last = attempts.at(-1) ?? { ok: false, traceId, degradedReason: "trace-fetch-failed" }; return { ...last, attempts, degradedReason: last.degradedReason ?? "trace-fetch-failed" }; } -function summarizeTraceFetch(fetchResult, expectedTraceId, attempt) { +function traceSummaryPath(traceId, projectId) { + const params = new URLSearchParams({ sinceSeq: "0", limit: "20" }); + if (projectId) params.set("projectId", projectId); + return { path: `/v1/agent/traces/${encodeURIComponent(traceId)}?${params.toString()}`, projectId, scoped: Boolean(projectId) }; +} + +function summarizeTraceFetch(fetchResult, expectedTraceId, attempt, request) { const body = fetchResult?.json?.data ?? fetchResult?.json ?? null; const trace = body?.trace ?? body?.runnerTrace ?? body; const events = Array.isArray(trace?.events) ? trace.events : Array.isArray(body?.events) ? body.events : []; @@ -983,6 +996,8 @@ function summarizeTraceFetch(fetchResult, expectedTraceId, attempt) { return { ok, attempt, + requestProjectId: request?.projectId ?? null, + requestScoped: request?.scoped === true, path: fetchResult?.path ?? null, httpStatus: fetchResult?.status ?? null, elapsedMs: fetchResult?.elapsedMs ?? null, @@ -995,6 +1010,7 @@ function summarizeTraceFetch(fetchResult, expectedTraceId, attempt) { latestEventAt: latest?.createdAt ?? latest?.at ?? null, latestEventPreview: latest ? JSON.stringify(latest).replace(/\s+/gu, " ").slice(0, 300) : null, error: fetchResult?.error ?? null, + errorCode: body?.error?.code ?? null, bodyPreview: ok ? null : fetchResult?.bodyPreview ?? null, degradedReason: ok ? null : fetchResult?.status ? "trace-fetch-http-status" : "trace-fetch-failed" }; @@ -1101,6 +1117,11 @@ function firstNonEmpty(...values) { return null; } +function normalizeProbeProjectId(value) { + const text = typeof value === "string" ? value.trim() : ""; + return /^prj_[A-Za-z0-9_.:-]{3,96}$/u.test(text) ? text : null; +} + async function waitForCommandReady(page, args, actions) { const timeoutMs = Math.min(args.timeoutMs, 30000); const before = await collectCommandState(page);