fix: surface OTel and sentinel visibility gaps
This commit is contained in:
@@ -2743,7 +2743,7 @@ function buildFindings(samples, control, network, errors, sampleMetrics, promptN
|
||||
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(...buildBrowserProcessFindings(browserProcess, runtimeAlerts));
|
||||
findings.push(...buildControlledNavigationRootCauseFindings(control, manifest));
|
||||
findings.push(...buildSessionInvariantFindings(control, manifest));
|
||||
const commandTimes = control
|
||||
@@ -3220,10 +3220,11 @@ function buildBrowserProcessReport(rows) {
|
||||
};
|
||||
}
|
||||
|
||||
function buildBrowserProcessFindings(report) {
|
||||
function buildBrowserProcessFindings(report, runtimeAlerts = null) {
|
||||
const summary = report?.summary || {};
|
||||
if (!summary || Number(summary.sampleCount ?? 0) <= 0) return [];
|
||||
const findings = [];
|
||||
const rootCauseSignals = browserRootCauseSignals(report, runtimeAlerts);
|
||||
const maxTotalRssMb = Number(summary.maxTotalRssMb ?? 0);
|
||||
const maxProcessRssMb = Number(summary.maxProcessRssMb ?? 0);
|
||||
if (maxTotalRssMb >= alertThresholds.browserTotalRssRedMb || maxProcessRssMb >= alertThresholds.browserProcessRssRedMb) {
|
||||
@@ -3240,6 +3241,7 @@ function buildBrowserProcessFindings(report) {
|
||||
rootCause: "frontend_browser_process_memory_pressure",
|
||||
rootCauseStatus: "confirmed-from-runner-process-rss",
|
||||
rootCauseConfidence: "high",
|
||||
rootCauseSignals,
|
||||
fallbackAllowed: false,
|
||||
valuesRedacted: true,
|
||||
});
|
||||
@@ -3260,6 +3262,7 @@ function buildBrowserProcessFindings(report) {
|
||||
rootCause: "frontend_browser_process_memory_leak_or_unbounded_render_growth",
|
||||
rootCauseStatus: "confirmed-from-runner-process-rss-growth",
|
||||
rootCauseConfidence: "high",
|
||||
rootCauseSignals,
|
||||
fallbackAllowed: false,
|
||||
valuesRedacted: true,
|
||||
});
|
||||
@@ -3285,6 +3288,7 @@ function buildBrowserProcessFindings(report) {
|
||||
rootCause: "frontend_browser_page_unresponsive_to_playwright",
|
||||
rootCauseStatus: "confirmed-from-cdp-runtime-evaluate",
|
||||
rootCauseConfidence: "high",
|
||||
rootCauseSignals,
|
||||
fallbackAllowed: false,
|
||||
valuesRedacted: true,
|
||||
});
|
||||
@@ -3303,6 +3307,7 @@ function buildBrowserProcessFindings(report) {
|
||||
rootCause: "frontend_browser_cdp_metrics_unresponsive",
|
||||
rootCauseStatus: "confirmed-from-cdp-metrics-timeouts",
|
||||
rootCauseConfidence: "high",
|
||||
rootCauseSignals,
|
||||
fallbackAllowed: false,
|
||||
valuesRedacted: true,
|
||||
});
|
||||
@@ -3310,6 +3315,32 @@ function buildBrowserProcessFindings(report) {
|
||||
return findings;
|
||||
}
|
||||
|
||||
function browserRootCauseSignals(report, runtimeAlerts) {
|
||||
const browserSummary = report?.summary || {};
|
||||
const runtimeSummary = runtimeAlerts?.summary || {};
|
||||
const sampleCount = Number(browserSummary.sampleCount ?? 0);
|
||||
const sessionListReadCount = Number(runtimeSummary.workbenchSessionListReadCount ?? 0);
|
||||
const traceEventsReadCount = Number(runtimeSummary.workbenchTraceEventsReadCount ?? 0);
|
||||
const webPerformanceBeaconFailureCount = Number(runtimeSummary.webPerformanceBeaconFailureCount ?? 0);
|
||||
const eventSourceFailureCount = Number(runtimeSummary.workbenchEventSourceFailureCount ?? 0);
|
||||
const suspectedFrontendRefreshStorm = sessionListReadCount >= Math.max(20, sampleCount * 2);
|
||||
return {
|
||||
suspectedFrontendRefreshStorm,
|
||||
sessionListReadCount,
|
||||
traceEventsReadCount,
|
||||
webPerformanceBeaconFailureCount,
|
||||
eventSourceFailureCount,
|
||||
requestFailedCount: runtimeSummary.significantRequestFailedCount ?? runtimeSummary.requestFailedCount ?? 0,
|
||||
httpErrorCount: runtimeSummary.httpErrorCount ?? 0,
|
||||
topRequestFailedPaths: (runtimeAlerts?.networkSignificantRequestFailedByPath ?? runtimeAlerts?.networkRequestFailedByPath ?? []).slice(0, 5),
|
||||
topHttpErrorPaths: (runtimeAlerts?.networkHttpErrorsByPath ?? []).slice(0, 5),
|
||||
note: suspectedFrontendRefreshStorm
|
||||
? "suspected frontend refresh storm: session list reads exceed the sample-derived budget during a browser red finding"
|
||||
: "root-cause signals are included so memory/responsiveness/CDP red findings can be correlated without manual grep",
|
||||
valuesRedacted: true,
|
||||
};
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -4154,6 +4185,18 @@ function buildRuntimeAlerts(samples, control, network, consoleEvents, errors) {
|
||||
const requestFailed = naturalNetwork
|
||||
.filter((item) => item?.type === "requestfailed")
|
||||
.map((item) => networkAlertEvent(item, promptTimes));
|
||||
const workbenchSessionListReadCount = naturalNetwork
|
||||
.filter((item) => urlPath(item?.url) === "/v1/workbench/sessions")
|
||||
.length;
|
||||
const workbenchTraceEventsReadCount = naturalNetwork
|
||||
.filter((item) => /^\/v1\/workbench\/traces\/[^/]+\/events$/u.test(urlPath(item?.url)))
|
||||
.length;
|
||||
const webPerformanceBeaconFailureCount = naturalNetwork
|
||||
.filter((item) => urlPath(item?.url) === "/v1/web-performance" && (item?.type === "requestfailed" || Number(item?.status) >= 400))
|
||||
.length;
|
||||
const workbenchEventSourceFailureCount = naturalNetwork
|
||||
.filter((item) => urlPath(item?.url) === "/v1/workbench/events" && (item?.type === "requestfailed" || Number(item?.status) >= 400))
|
||||
.length;
|
||||
const significantRequestFailed = requestFailed.filter(
|
||||
(item) => !isBenignLongLivedStreamClosureAlert(item) && !isObserverRefreshClosureAlert(item, observerRefreshTimes),
|
||||
);
|
||||
@@ -4284,6 +4327,10 @@ function buildRuntimeAlerts(samples, control, network, consoleEvents, errors) {
|
||||
httpErrorCount: httpErrors.length,
|
||||
requestFailedCount: requestFailed.length,
|
||||
significantRequestFailedCount: significantRequestFailed.length,
|
||||
workbenchSessionListReadCount,
|
||||
workbenchTraceEventsReadCount,
|
||||
webPerformanceBeaconFailureCount,
|
||||
workbenchEventSourceFailureCount,
|
||||
benignLongLivedStreamClosureCount: requestFailed.length - significantRequestFailed.length,
|
||||
domDiagnosticSampleCount: domDiagnostics.length,
|
||||
domDiagnosticGroupCount: groupDomDiagnostics(domDiagnostics).length,
|
||||
|
||||
Reference in New Issue
Block a user