fix: mark browser memory freezes red

This commit is contained in:
Codex
2026-06-30 02:48:02 +00:00
parent cee5f9aecc
commit 2c4022d306
6 changed files with 739 additions and 7 deletions
@@ -43,6 +43,7 @@ const promptNetworkRows = applyAnalysisFocus(filterRowsByTimeWindow(sourceNetwor
const consoleEvents = applyAnalysisFocus(filterRowsByTimeWindow(await readJsonl(dataFile("console.jsonl"), { tail: smallJsonlTailLimit }), sampleWindow), analysisFocus);
const errors = applyAnalysisFocus(filterRowsByTimeWindow(await readJsonl(dataFile("errors.jsonl"), { tail: smallJsonlTailLimit }), sampleWindow), analysisFocus);
const artifacts = applyAnalysisFocus(filterRowsByTimeWindow(await readJsonl(dataFile("artifacts.jsonl"), { tail: smallJsonlTailLimit }), sampleWindow), analysisFocus);
const browserProcessRows = applyAnalysisFocus(filterRowsByTimeWindow(await readJsonl(dataFile("browser-process.jsonl"), { tail: smallJsonlTailLimit }), sampleWindow), analysisFocus);
const manifest = await readJson(path.join(stateDir, "manifest.json"));
const heartbeat = await readJson(path.join(stateDir, "heartbeat.json"));
const commandState = await readCommandState(stateDir);
@@ -55,6 +56,7 @@ const pagePerformance = buildPagePerformanceReport(samples, manifest);
const promptNetwork = buildPromptNetworkReport(control, promptNetworkRows);
const runtimeAlerts = buildRuntimeAlerts(samples, control, network, consoleEvents, errors);
const apiDomLag = buildApiDomLagReport(samples, network);
const browserProcess = buildBrowserProcessReport(browserProcessRows);
const projectManagement = buildProjectManagementReport(samples, control, network, pagePerformance, projectManagementConfig);
const runnerErrors = errors.slice(-8).map((item) => {
const details = item.error?.details && typeof item.error.details === "object" ? item.error.details : {};
@@ -105,9 +107,9 @@ const runnerErrors = errors.slice(-8).map((item) => {
});
const commandFailures = summarizeCommandFailures(control);
const toolFindings = buildToolFindings({ manifest, heartbeat, commandState });
const findings = [...toolFindings, ...buildProjectManagementFindings(projectManagement), ...buildFindings(samples, control, network, errors, sampleMetrics, promptNetwork, runtimeAlerts, pagePerformance, pageProvenance, commandFailures, manifest, apiDomLag)];
const findings = [...toolFindings, ...buildProjectManagementFindings(projectManagement), ...buildFindings(samples, control, network, errors, sampleMetrics, promptNetwork, runtimeAlerts, pagePerformance, pageProvenance, commandFailures, manifest, apiDomLag, browserProcess)];
if (jsonlReadIssues.length > 0) findings.unshift({ id: "jsonl-read-issues", severity: "red", summary: "observer analyzer hit JSONL read/parse issues", count: jsonlReadIssues.length, issues: jsonlReadIssues.slice(0, 20) });
const recentWindow = buildRecentAnalysisWindow({ samples, control, network, consoleEvents, errors, manifest });
const recentWindow = buildRecentAnalysisWindow({ samples, control, network, consoleEvents, errors, browserProcessRows, manifest });
const commandTimeline = control.filter((item) => item.phase === "completed" || item.phase === "failed").map((item) => ({ ts: item.ts, phase: item.phase, commandId: item.commandId, type: item.type, input: item.input, afterUrl: item.afterUrl }));
const report = {
ok: findings.filter((item) => item.severity === "red").length === 0,
@@ -118,7 +120,7 @@ const report = {
alertThresholds,
manifest: compactManifest(manifest),
heartbeat: compactHeartbeat(heartbeat),
counts: { samples: samples.length, control: control.length, network: network.length, console: consoleEvents.length, errors: errors.length, artifacts: artifacts.length },
counts: { samples: samples.length, control: control.length, network: network.length, console: consoleEvents.length, errors: errors.length, artifacts: artifacts.length, browserProcess: browserProcessRows.length },
commandTimeline,
transitions,
sampleMetrics,
@@ -128,6 +130,7 @@ const report = {
promptNetwork,
runtimeAlerts,
apiDomLag,
browserProcess,
runnerErrors,
commandFailures,
commandState,
@@ -157,6 +160,7 @@ console.log(JSON.stringify({
projectManagement: projectManagement.summary,
runtimeAlerts: runtimeAlerts.summary,
apiDomLag: apiDomLag.summary,
browserProcess: browserProcess.summary,
findingCount: findings.length,
redFindingCount: findings.filter((item) => item.severity === "red").length,
redFindings: prioritizeFindings(findings.filter((item) => item.severity === "red")).slice(0, 12).map((item) => ({ kind: item.id ?? item.kind ?? item.code, severity: item.severity, count: item.count ?? item.sampleCount ?? null, summary: String(item.summary ?? item.message ?? "").slice(0, 180) })),
@@ -177,6 +181,7 @@ console.log(JSON.stringify({
promptNetwork: recentWindow.promptNetwork.summary,
runtimeAlerts: recentWindow.runtimeAlerts.summary,
apiDomLag: compactApiDomLagForOutput(apiDomLag),
browserProcess: recentWindow.browserProcess.summary,
runnerErrors,
commandFailures: commandFailures.slice(-8),
commandState,
@@ -561,6 +566,14 @@ function parseAlertThresholds(value) {
domEvaluateTimeoutRedWindowMs: requiredPositiveThreshold(raw, "domEvaluateTimeoutRedWindowMs"),
screenshotTimeoutRedCount: requiredPositiveThreshold(raw, "screenshotTimeoutRedCount"),
pageErrorRedCount: requiredPositiveThreshold(raw, "pageErrorRedCount"),
browserProcessSampleIntervalMs: requiredPositiveThreshold(raw, "browserProcessSampleIntervalMs"),
browserTotalRssRedMb: requiredPositiveThreshold(raw, "browserTotalRssRedMb"),
browserProcessRssRedMb: requiredPositiveThreshold(raw, "browserProcessRssRedMb"),
browserRssGrowthRedMb: requiredPositiveThreshold(raw, "browserRssGrowthRedMb"),
browserRssGrowthWindowMs: requiredPositiveThreshold(raw, "browserRssGrowthWindowMs"),
playwrightResponsivenessRedMs: requiredPositiveThreshold(raw, "playwrightResponsivenessRedMs"),
playwrightResponsivenessTimeoutRedCount: requiredPositiveThreshold(raw, "playwrightResponsivenessTimeoutRedCount"),
cdpMetricsTimeoutRedCount: requiredPositiveThreshold(raw, "cdpMetricsTimeoutRedCount"),
uncommandedStateChangeCommandWindowMs: requiredPositiveThreshold(raw, "uncommandedStateChangeCommandWindowMs"),
scrollJumpCommandWindowMs: requiredPositiveThreshold(raw, "scrollJumpCommandWindowMs"),
scrollJumpFromY: requiredPositiveThreshold(raw, "scrollJumpFromY"),
@@ -2725,11 +2738,12 @@ function promptCommandHasAuthoritativeSubmitSideEffect(control, promptRound) {
|| Number(sideEffect.messageCountDelta ?? 0) > 0;
}
function buildFindings(samples, control, network, errors, sampleMetrics, promptNetwork, runtimeAlerts, pagePerformance, pageProvenance, commandFailures = [], manifest = {}, apiDomLag = null) {
function buildFindings(samples, control, network, errors, sampleMetrics, promptNetwork, runtimeAlerts, pagePerformance, pageProvenance, commandFailures = [], manifest = {}, apiDomLag = null, browserProcess = null) {
const findings = [];
const effectiveApiDomLag = apiDomLag || buildApiDomLagReport(samples, network);
if (commandFailures.length > 0) findings.push({ id: "observer-command-failed", severity: "red", summary: "observer control commands failed; analyze must surface command failure instead of hiding it in command artifacts", count: commandFailures.length, commands: commandFailures.slice(0, 20) });
findings.push(...buildFrontendFreezeFindings(errors, control));
findings.push(...buildBrowserProcessFindings(browserProcess));
findings.push(...buildControlledNavigationRootCauseFindings(control, manifest));
findings.push(...buildSessionInvariantFindings(control, manifest));
const commandTimes = control
@@ -3092,6 +3106,314 @@ function buildFrontendFreezeFindings(errors, control) {
return findings;
}
function buildBrowserProcessReport(rows) {
const samples = (Array.isArray(rows) ? rows : [])
.filter((item) => item && (item.type === "browser-process-sample" || item.process || item.pages))
.map((item) => ({ ...item, tsMs: Date.parse(String(item.ts || "")) }))
.filter((item) => Number.isFinite(item.tsMs))
.sort((a, b) => a.tsMs - b.tsMs);
const memorySamples = samples.map((item) => {
const process = item.process && typeof item.process === "object" ? item.process : {};
const growth = item.growth && typeof item.growth === "object" ? item.growth : {};
const totalRssBytes = browserMetricNumber(process.totalRssBytes);
const maxProcessRssBytes = browserMetricNumber(process.maxProcessRssBytes);
return {
ts: item.ts,
tsMs: item.tsMs,
seq: item.seq ?? null,
sampleSeq: item.sampleSeq ?? null,
commandId: item.commandId ?? null,
processCount: browserMetricNumber(process.chromiumProcessCount),
totalRssBytes,
totalRssMb: bytesToMb(totalRssBytes),
maxProcessRssBytes,
maxProcessRssMb: bytesToMb(maxProcessRssBytes),
maxProcess: compactBrowserProcessRow(process.maxProcess),
totalRssGrowthBytes: browserMetricNumber(growth.totalRssGrowthBytes),
totalRssGrowthMb: bytesToMb(growth.totalRssGrowthBytes),
maxProcessRssGrowthBytes: browserMetricNumber(growth.maxProcessRssGrowthBytes),
maxProcessRssGrowthMb: bytesToMb(growth.maxProcessRssGrowthBytes),
roles: process.roles && typeof process.roles === "object" ? process.roles : {},
valuesRedacted: true,
};
});
const computedGrowth = computeBrowserProcessGrowth(memorySamples, alertThresholds.browserRssGrowthWindowMs);
const pageEvents = [];
const cdpTimeoutEvents = [];
for (const sample of samples) {
for (const page of Array.isArray(sample.pages) ? sample.pages : []) {
const responsiveness = page?.responsiveness && typeof page.responsiveness === "object" ? page.responsiveness : {};
const cdp = page?.cdp && typeof page.cdp === "object" ? page.cdp : {};
const calls = Array.isArray(cdp.calls) ? cdp.calls : [];
const event = {
ts: sample.ts,
tsMs: sample.tsMs,
seq: sample.seq ?? null,
sampleSeq: sample.sampleSeq ?? null,
commandId: sample.commandId ?? null,
pageRole: page?.pageRole ?? null,
pageId: page?.pageId ?? null,
pageEpoch: page?.pageEpoch ?? null,
url: safeReportUrl(page?.url),
timeoutMs: browserMetricNumber(page?.timeoutMs),
responsivenessOk: responsiveness.ok === true,
responsivenessTimeout: responsiveness.timeout === true,
responsivenessLatencyMs: browserMetricNumber(responsiveness.latencyMs),
cdpTimeoutCount: browserMetricNumber(cdp.timeoutCount),
cdpErrorCount: browserMetricNumber(cdp.errorCount),
heapUsedMb: page?.heapUsage ? bytesToMb(page.heapUsage.usedSize) : null,
heapTotalMb: page?.heapUsage ? bytesToMb(page.heapUsage.totalSize) : null,
domNodes: page?.domCounters ? browserMetricNumber(page.domCounters.nodes) : null,
valuesRedacted: true,
};
pageEvents.push(event);
for (const call of calls) {
if (call?.timeout !== true || call?.method === "Runtime.evaluate") continue;
cdpTimeoutEvents.push({
...event,
method: call.method ?? null,
latencyMs: browserMetricNumber(call.latencyMs),
errorMessage: limitText(call.error?.message ?? "", 180),
valuesRedacted: true,
});
}
const callTimeoutCount = calls.filter((call) => call?.timeout === true && call?.method !== "Runtime.evaluate").length;
if (Number(event.cdpTimeoutCount || 0) > callTimeoutCount && calls.length === 0) {
cdpTimeoutEvents.push({ ...event, method: "cdp-session", latencyMs: event.responsivenessLatencyMs, errorMessage: "CDP session or metric collection timed out", valuesRedacted: true });
}
}
}
const responsivenessEvents = pageEvents.filter((item) => item.responsivenessTimeout === true || Number(item.responsivenessLatencyMs ?? 0) >= alertThresholds.playwrightResponsivenessRedMs);
const maxTotal = maxByNumber(memorySamples, (item) => item.totalRssBytes);
const maxProcess = maxByNumber(memorySamples, (item) => item.maxProcessRssBytes);
const maxGrowth = maxByNumber(computedGrowth, (item) => item.totalRssGrowthBytes);
const maxProcessGrowth = maxByNumber(computedGrowth, (item) => item.maxProcessRssGrowthBytes);
return {
summary: {
sampleCount: samples.length,
memorySampleCount: memorySamples.length,
pageMetricCount: pageEvents.length,
cdpMetricsTimeoutCount: cdpTimeoutEvents.length,
responsivenessSlowCount: responsivenessEvents.length,
responsivenessTimeoutCount: responsivenessEvents.filter((item) => item.responsivenessTimeout === true).length,
maxTotalRssMb: maxTotal ? bytesToMb(maxTotal.totalRssBytes) : null,
maxProcessRssMb: maxProcess ? bytesToMb(maxProcess.maxProcessRssBytes) : null,
maxTotalRssGrowthMb: maxGrowth ? bytesToMb(maxGrowth.totalRssGrowthBytes) : null,
maxProcessRssGrowthMb: maxProcessGrowth ? bytesToMb(maxProcessGrowth.maxProcessRssGrowthBytes) : null,
totalRssRedMb: alertThresholds.browserTotalRssRedMb,
processRssRedMb: alertThresholds.browserProcessRssRedMb,
growthRedMb: alertThresholds.browserRssGrowthRedMb,
growthWindowMs: alertThresholds.browserRssGrowthWindowMs,
responsivenessRedMs: alertThresholds.playwrightResponsivenessRedMs,
valuesRedacted: true,
},
memorySamples: memorySamples.slice(-60),
growthSamples: computedGrowth.slice(-60),
maxTotalRssSample: maxTotal,
maxProcessRssSample: maxProcess,
maxGrowthSample: maxGrowth,
maxProcessGrowthSample: maxProcessGrowth,
responsivenessEvents: responsivenessEvents.slice(-80),
cdpTimeoutEvents: cdpTimeoutEvents.slice(-80),
latestPageEvents: pageEvents.slice(-20),
valuesRedacted: true,
};
}
function buildBrowserProcessFindings(report) {
const summary = report?.summary || {};
if (!summary || Number(summary.sampleCount ?? 0) <= 0) return [];
const findings = [];
const maxTotalRssMb = Number(summary.maxTotalRssMb ?? 0);
const maxProcessRssMb = Number(summary.maxProcessRssMb ?? 0);
if (maxTotalRssMb >= alertThresholds.browserTotalRssRedMb || maxProcessRssMb >= alertThresholds.browserProcessRssRedMb) {
findings.push({
id: "frontend-browser-memory-rss-red",
severity: "red",
summary: "Chromium RSS exceeded YAML red threshold during observation; browser memory growth is freeze evidence and must not be hidden by page refresh/fallback",
maxTotalRssMb,
maxProcessRssMb,
totalRssRedMb: alertThresholds.browserTotalRssRedMb,
processRssRedMb: alertThresholds.browserProcessRssRedMb,
maxTotalRssSample: report.maxTotalRssSample,
maxProcessRssSample: report.maxProcessRssSample,
rootCause: "frontend_browser_process_memory_pressure",
rootCauseStatus: "confirmed-from-runner-process-rss",
rootCauseConfidence: "high",
fallbackAllowed: false,
valuesRedacted: true,
});
}
const maxTotalRssGrowthMb = Number(summary.maxTotalRssGrowthMb ?? 0);
const maxProcessRssGrowthMb = Number(summary.maxProcessRssGrowthMb ?? 0);
if (maxTotalRssGrowthMb >= alertThresholds.browserRssGrowthRedMb || maxProcessRssGrowthMb >= alertThresholds.browserRssGrowthRedMb) {
findings.push({
id: "frontend-browser-memory-growth-red",
severity: "red",
summary: "Chromium RSS grew beyond YAML window budget; this matches the reported freeze pattern of browser memory rapidly climbing",
maxTotalRssGrowthMb,
maxProcessRssGrowthMb,
growthRedMb: alertThresholds.browserRssGrowthRedMb,
windowMs: alertThresholds.browserRssGrowthWindowMs,
maxGrowthSample: report.maxGrowthSample,
maxProcessGrowthSample: report.maxProcessGrowthSample,
rootCause: "frontend_browser_process_memory_leak_or_unbounded_render_growth",
rootCauseStatus: "confirmed-from-runner-process-rss-growth",
rootCauseConfidence: "high",
fallbackAllowed: false,
valuesRedacted: true,
});
}
const responsivenessEvents = Array.isArray(report.responsivenessEvents) ? report.responsivenessEvents : [];
const severeLatencyEvents = responsivenessEvents.filter((item) => item.responsivenessTimeout !== true && Number(item.responsivenessLatencyMs ?? 0) >= alertThresholds.playwrightResponsivenessRedMs);
const responsivenessTimeoutBurst = firstBurst(
responsivenessEvents.filter((item) => item.responsivenessTimeout === true),
alertThresholds.playwrightResponsivenessTimeoutRedCount,
alertThresholds.domEvaluateTimeoutRedWindowMs,
);
if (severeLatencyEvents.length > 0 || responsivenessTimeoutBurst) {
const events = severeLatencyEvents.length > 0 ? severeLatencyEvents : responsivenessTimeoutBurst;
findings.push({
id: "frontend-playwright-responsiveness-red",
severity: "red",
summary: "Playwright/CDP responsiveness probe exceeded YAML budget; treat the browser page as frozen instead of refreshing or falling back",
count: events.length,
latencyRedMs: alertThresholds.playwrightResponsivenessRedMs,
timeoutThresholdCount: alertThresholds.playwrightResponsivenessTimeoutRedCount,
windowMs: alertThresholds.domEvaluateTimeoutRedWindowMs,
events: events.slice(0, 20).map(browserProcessEventRef),
rootCause: "frontend_browser_page_unresponsive_to_playwright",
rootCauseStatus: "confirmed-from-cdp-runtime-evaluate",
rootCauseConfidence: "high",
fallbackAllowed: false,
valuesRedacted: true,
});
}
const cdpTimeoutEvents = Array.isArray(report.cdpTimeoutEvents) ? report.cdpTimeoutEvents : [];
const cdpTimeoutBurst = firstBurst(cdpTimeoutEvents, alertThresholds.cdpMetricsTimeoutRedCount, alertThresholds.domEvaluateTimeoutRedWindowMs);
if (cdpTimeoutBurst) {
findings.push({
id: "frontend-cdp-metrics-timeout-red",
severity: "red",
summary: "CDP browser metrics timed out repeatedly; the sentinel has direct browser-side evidence of a hung page/runtime",
count: cdpTimeoutBurst.length,
thresholdCount: alertThresholds.cdpMetricsTimeoutRedCount,
windowMs: alertThresholds.domEvaluateTimeoutRedWindowMs,
events: cdpTimeoutBurst.slice(0, 20).map(browserProcessEventRef),
rootCause: "frontend_browser_cdp_metrics_unresponsive",
rootCauseStatus: "confirmed-from-cdp-metrics-timeouts",
rootCauseConfidence: "high",
fallbackAllowed: false,
valuesRedacted: true,
});
}
return findings;
}
function computeBrowserProcessGrowth(samples, windowMs) {
const budgetMs = Math.max(1000, Number(windowMs || 0));
const sorted = (samples || []).filter((item) => Number.isFinite(item.tsMs)).sort((a, b) => a.tsMs - b.tsMs);
return sorted.map((item, index) => {
const candidates = sorted.slice(0, index + 1).filter((candidate) => item.tsMs - candidate.tsMs <= budgetMs);
const totalBaseline = minByNumber(candidates, (candidate) => candidate.totalRssBytes);
const processBaseline = minByNumber(candidates, (candidate) => candidate.maxProcessRssBytes);
const totalGrowth = Number(item.totalRssBytes || 0) - Number(totalBaseline?.totalRssBytes || 0);
const processGrowth = Number(item.maxProcessRssBytes || 0) - Number(processBaseline?.maxProcessRssBytes || 0);
return {
...item,
windowMs: budgetMs,
totalBaselineAt: totalBaseline?.ts ?? null,
processBaselineAt: processBaseline?.ts ?? null,
totalRssGrowthBytes: totalGrowth,
totalRssGrowthMb: bytesToMb(totalGrowth),
maxProcessRssGrowthBytes: processGrowth,
maxProcessRssGrowthMb: bytesToMb(processGrowth),
valuesRedacted: true,
};
});
}
function browserProcessEventRef(item) {
return {
ts: item?.ts ?? null,
seq: item?.seq ?? null,
sampleSeq: item?.sampleSeq ?? null,
commandId: item?.commandId ?? null,
pageRole: item?.pageRole ?? null,
pageId: item?.pageId ?? null,
pageEpoch: item?.pageEpoch ?? null,
timeoutMs: item?.timeoutMs ?? null,
responsivenessLatencyMs: item?.responsivenessLatencyMs ?? item?.latencyMs ?? null,
responsivenessTimeout: item?.responsivenessTimeout === true,
cdpTimeoutCount: item?.cdpTimeoutCount ?? null,
method: item?.method ?? null,
errorMessage: item?.errorMessage ?? null,
valuesRedacted: true,
};
}
function compactBrowserProcessRow(item) {
if (!item || typeof item !== "object") return null;
return {
pid: item.pid ?? null,
role: item.role ?? null,
name: item.name ?? null,
rssMb: bytesToMb(item.rssBytes),
vmSizeMb: bytesToMb(item.vmSizeBytes),
commandHash: item.commandHash ?? null,
valuesRedacted: true,
};
}
function browserMetricNumber(value) {
const numeric = Number(value);
return Number.isFinite(numeric) ? numeric : null;
}
function bytesToMb(value) {
const numeric = Number(value);
if (!Number.isFinite(numeric)) return null;
return Number((numeric / 1024 / 1024).toFixed(1));
}
function maxByNumber(items, getter) {
let selected = null;
let selectedValue = Number.NEGATIVE_INFINITY;
for (const item of Array.isArray(items) ? items : []) {
const value = Number(getter(item));
if (!Number.isFinite(value)) continue;
if (!selected || value > selectedValue) {
selected = item;
selectedValue = value;
}
}
return selected;
}
function minByNumber(items, getter) {
let selected = null;
let selectedValue = Number.POSITIVE_INFINITY;
for (const item of Array.isArray(items) ? items : []) {
const value = Number(getter(item));
if (!Number.isFinite(value)) continue;
if (!selected || value < selectedValue) {
selected = item;
selectedValue = value;
}
}
return selected;
}
function safeReportUrl(value) {
if (!value) return null;
try {
const url = new URL(String(value));
return url.origin + url.pathname;
} catch {
return limitText(String(value), 200);
}
}
function frontendFreezeErrorEvent(item, promptTimes) {
const details = objectValue(item?.error?.details);
const message = String(item?.error?.message ?? item?.message ?? item?.error ?? "");
@@ -3220,7 +3542,7 @@ function maxPresentNumber(values) {
return numbers.length > 0 ? Math.max(...numbers) : null;
}
function buildRecentAnalysisWindow({ samples, control, network, consoleEvents, errors, manifest }) {
function buildRecentAnalysisWindow({ samples, control, network, consoleEvents, errors, browserProcessRows, manifest }) {
const latestSampleMs = latestTimestampMs(samples);
const windowMs = 5 * 60 * 1000;
const fromMs = Number.isFinite(latestSampleMs) ? latestSampleMs - windowMs : Number.NEGATIVE_INFINITY;
@@ -3234,13 +3556,15 @@ function buildRecentAnalysisWindow({ samples, control, network, consoleEvents, e
const windowNetwork = network.filter(inWindow);
const windowConsole = consoleEvents.filter(inWindow);
const windowErrors = errors.filter(inWindow);
const windowBrowserProcessRows = (browserProcessRows || []).filter(inWindow);
const sampleMetrics = buildSampleMetrics(windowSamples, control);
const pageProvenance = buildPageProvenanceReport(windowSamples, windowControl, manifest);
const pagePerformance = buildPagePerformanceReport(windowSamples, manifest);
const promptNetwork = buildPromptNetworkReport(windowControl, windowNetwork);
const runtimeAlerts = buildRuntimeAlerts(windowSamples, control, windowNetwork, windowConsole, windowErrors);
const apiDomLag = buildApiDomLagReport(windowSamples, windowNetwork);
const findings = buildFindings(windowSamples, control, windowNetwork, windowErrors, sampleMetrics, promptNetwork, runtimeAlerts, pagePerformance, pageProvenance, [], {}, apiDomLag);
const browserProcess = buildBrowserProcessReport(windowBrowserProcessRows);
const findings = buildFindings(windowSamples, control, windowNetwork, windowErrors, sampleMetrics, promptNetwork, runtimeAlerts, pagePerformance, pageProvenance, [], {}, apiDomLag, browserProcess);
return {
summary: {
name: "recent-5m",
@@ -3252,6 +3576,7 @@ function buildRecentAnalysisWindow({ samples, control, network, consoleEvents, e
network: windowNetwork.length,
console: windowConsole.length,
errors: windowErrors.length,
browserProcess: windowBrowserProcessRows.length,
valuesRedacted: true
},
sampleMetrics,
@@ -3260,6 +3585,7 @@ function buildRecentAnalysisWindow({ samples, control, network, consoleEvents, e
promptNetwork,
runtimeAlerts,
apiDomLag,
browserProcess,
findings,
valuesRedacted: true
};