fix: bound web-probe observe analyze output

This commit is contained in:
Codex
2026-07-02 09:13:41 +00:00
parent ff8f13f243
commit 87351278b5
2 changed files with 239 additions and 17 deletions
+99 -17
View File
@@ -2453,6 +2453,30 @@ export function runNodeWebProbeObserveAnalyze(options: NodeWebProbeObserveOption
" }",
" }",
"}",
"if (Buffer.byteLength(output, 'utf8') > 7500) {",
" const frontend = objectOrNull(compact.frontendPerformance) || {};",
" const frontendHotspots = objectOrNull(compact.frontendPerformanceHotspots) || {};",
" output = compactOutput({",
" ok: compact.ok,",
" counts: compact.counts ? { samples: compact.counts.samples ?? null, control: compact.counts.control ?? null, network: compact.counts.network ?? null, console: compact.counts.console ?? null, artifacts: compact.counts.artifacts ?? null } : null,",
" jsonlScope: compact.jsonlScope ? { mode: compact.jsonlScope.mode ?? null, focus: objectOrNull(compact.jsonlScope.focus)?.mode ?? null, archivePrefix: compact.jsonlScope.archivePrefix ?? null } : null,",
" analysisWindow: compact.analysisWindow ? { name: compact.analysisWindow.name ?? null, fromAt: compact.analysisWindow.fromAt ?? null, toAt: compact.analysisWindow.toAt ?? null, samples: compact.analysisWindow.samples ?? null, network: compact.analysisWindow.network ?? null, console: compact.analysisWindow.console ?? null } : null,",
" archiveSummary: compact.archiveSummary ? { redFindingCount: compact.archiveSummary.redFindingCount ?? null, findingCount: compact.archiveSummary.findingCount ?? null, sampleCount: compact.archiveSummary.sampleMetrics?.sampleCount ?? null, slowPathCount: compact.archiveSummary.pagePerformance?.slowPathCount ?? null } : null,",
" sampleMetrics: compact.sampleMetrics ? { sampleCount: compact.sampleMetrics.sampleCount ?? null, roundCount: Array.isArray(compact.sampleMetrics.rounds) ? compact.sampleMetrics.rounds.length : null, turnColumnCount: Array.isArray(compact.sampleMetrics.turnColumns) ? compact.sampleMetrics.turnColumns.length : null, turnTimingRows: compact.sampleMetrics.turnTimingRows ?? null, turnTimingTotalElapsedForwardJumpCount: compact.sampleMetrics.turnTimingTotalElapsedForwardJumpCount ?? null, turnTimingRecentUpdateJumpCount: compact.sampleMetrics.turnTimingRecentUpdateJumpCount ?? compact.sampleMetrics.turnTimingRecentUpdateSawtoothJumpCount ?? null, loadingSampleCount: compact.sampleMetrics.loadingSampleCount ?? null, loadingMaxCount: compact.sampleMetrics.loadingMaxCount ?? null, loadingOverFiveSecondSegmentCount: compact.sampleMetrics.loadingOverFiveSecondSegmentCount ?? null } : null,",
" requestRate: compact.requestRate ? { requestCount: compact.requestRate.requestCount ?? null, totalPeakPerMinute: compact.requestRate.totalPeakPerMinute ?? null, pagePeakPerMinute: compact.requestRate.pagePeakPerMinute ?? null, apiPathPeakPerMinute: compact.requestRate.apiPathPeakPerMinute ?? null, overThresholdPeakCount: compact.requestRate.overThresholdPeakCount ?? null } : null,",
" frontendPerformance: frontend ? { eventCount: frontend.eventCount ?? null, longTaskCount: frontend.longTaskCount ?? null, longAnimationFrameCount: frontend.longAnimationFrameCount ?? null, eventLoopGapCount: frontend.eventLoopGapCount ?? null, captureCount: frontend.captureCount ?? null, maxLongTaskMs: frontend.maxLongTaskMs ?? null, maxLongAnimationFrameMs: frontend.maxLongAnimationFrameMs ?? null, maxEventLoopGapMs: frontend.maxEventLoopGapMs ?? null, profileHotspotCount: frontend.profileHotspotCount ?? null, scriptHotspotCount: frontend.scriptHotspotCount ?? null, profileFunctions: takeHead(frontendHotspots.profileFunctions, 3).map((item) => ({ functionName: clip(item?.functionName ?? item?.name, 64), url: clip(item?.url ?? item?.sourceURL, 96), selfTimeMs: item?.selfTimeMs ?? null, totalTimeMs: item?.totalTimeMs ?? null, hitCount: item?.hitCount ?? null })), profileStacks: takeHead(frontendHotspots.profileStacks, 2).map((item) => ({ functionName: clip(item?.functionName ?? item?.name, 64), selfTimeMs: item?.selfTimeMs ?? null, frameCount: item?.frameCount ?? (Array.isArray(item?.frames) ? item.frames.length : null) })), scripts: takeHead(frontendHotspots.scripts, 3).map((item) => ({ functionName: clip(item?.sourceFunctionName ?? item?.functionName ?? item?.invoker, 64), url: clip(item?.sourceURL ?? item?.url, 96), totalDurationMs: item?.totalDurationMs ?? null, count: item?.count ?? null })) } : null,",
" commandState: compact.commandState ? { pendingCount: compact.commandState.pendingCount ?? null, processingCount: compact.commandState.processingCount ?? null, abandonedCount: compact.commandState.abandonedCount ?? null, failedCount: compact.commandState.failedCount ?? null } : null,",
" findings: Array.isArray(compact.findings) ? compact.findings.slice(0, 4).map((item) => ({ kind: item.kind ?? item.code ?? null, severity: item.severity ?? item.level ?? null, count: item.count ?? item.sampleCount ?? null, summary: clip(item.summary ?? item.message, 100) })) : [],",
" archiveRedFindings: Array.isArray(compact.archiveRedFindings) ? compact.archiveRedFindings.slice(0, 3).map((item) => ({ kind: item.kind ?? item.code ?? null, severity: item.severity ?? item.level ?? null, count: item.count ?? item.sampleCount ?? null, summary: clip(item.summary ?? item.message, 100) })) : [],",
" pagePerformanceSlowApi: Array.isArray(compact.pagePerformanceSlowApi) ? compact.pagePerformanceSlowApi.slice(0, 2).map((item) => ({ path: item.path ?? item.route ?? null, sampleCount: item.sampleCount ?? null, p95Ms: item.p95Ms ?? null, maxMs: item.maxMs ?? null, overBudgetCount: item.overBudgetCount ?? null })) : [],",
" reportJsonPath: compact.reportJsonPath ?? reportJsonPath,",
" reportJsonSha256: compact.reportJsonSha256 ?? sha256(reportJsonPath),",
" reportMdPath: compact.reportMdPath ?? reportMdPath,",
" reportMdSha256: compact.reportMdSha256 ?? sha256(reportMdPath),",
" analyzer: { exitCode: compact.analyzer?.exitCode ?? null, recoveredFrom: compact.analyzer?.recoveredFrom ?? null, stdoutBytes: compact.analyzer?.stdoutBytes ?? null, stderrBytes: compact.analyzer?.stderrBytes ?? null, compactStdoutLimited: true, hardFallback: true, byteClamp: 7500 },",
" valuesRedacted: true",
" });",
"}",
"console.log(output);",
"UNIDESK_WEB_OBSERVE_ANALYZE_COMPACT",
"exit \"$analyzer_exit\"",
@@ -2528,6 +2552,7 @@ export function runNodeWebProbeObserveAnalyze(options: NodeWebProbeObserveOption
browserFreezePolicy,
wrapper: buildWebObserveWrapperForObserveOptions("analyze", options, spec.workspace),
result: analysis === null ? compactCommandResultWithStdoutTail(result) : compactCommandResult(result),
full: options.full,
valuesRedacted: true,
};
return options.raw ? compactWebObserveAnalyzePayloadForRaw(payload, options.compactRaw) : withWebObserveAnalyzeRendered(payload);
@@ -2558,8 +2583,10 @@ function compactWebObserveAnalyzeAnalysisForRaw(analysis: Record<string, unknown
const archiveSummary = recordValue(analysis.archiveSummary);
const requestRate = recordValue(analysis.requestRate);
const requestRateCurve = recordValue(analysis.requestRateCurve);
const findings = arrayRecordsValue(analysis.findings).slice(0, 16).map(compactWebObserveAnalyzeFindingForRaw);
const archiveRedFindings = arrayRecordsValue(analysis.archiveRedFindings ?? archiveSummary.redFindings).slice(0, 16).map(compactWebObserveAnalyzeFindingForRaw);
const findings = arrayRecordsValue(analysis.findings).slice(0, 4).map(compactWebObserveAnalyzeFindingForRaw);
const archiveRedFindings = arrayRecordsValue(analysis.archiveRedFindings ?? archiveSummary.redFindings).slice(0, 3).map(compactWebObserveAnalyzeFindingForRaw);
const frontendPerformance = recordValue(analysis.frontendPerformance);
const frontendHotspots = recordValue(analysis.frontendPerformanceHotspots);
return {
ok: analysis.ok === true ? true : analysis.ok === false ? false : null,
command: stringOrNullValue(analysis.command),
@@ -2577,8 +2604,9 @@ function compactWebObserveAnalyzeAnalysisForRaw(analysis: Record<string, unknown
runtimeAlerts: compactWebObserveAnalyzeAlertSummaryForRaw(analysis.runtimeAlerts),
requestRate: Object.keys(requestRate).length > 0 ? requestRate : recordValue(requestRateCurve.summary),
requestRateCurve: compactWebObserveAnalyzeRequestRateCurveForRaw(requestRateCurve),
requestRatePeaks: arrayRecordsValue(analysis.requestRatePeaks ?? requestRateCurve.peaks ?? requestRate.peaks).slice(0, 8),
pagePerformanceSlowApi: arrayRecordsValue(analysis.pagePerformanceSlowApi ?? analysis.archivePagePerformanceSlowApi).slice(0, 8).map((item) => ({
requestRatePeaks: arrayRecordsValue(analysis.requestRatePeaks ?? requestRateCurve.peaks ?? requestRate.peaks).slice(0, 4),
frontendPerformance: compactWebObserveAnalyzeFrontendPerformanceForRaw(frontendPerformance, frontendHotspots),
pagePerformanceSlowApi: arrayRecordsValue(analysis.pagePerformanceSlowApi ?? analysis.archivePagePerformanceSlowApi).slice(0, 4).map((item) => ({
path: stringOrNullValue(item.path ?? item.route),
route: stringOrNullValue(item.route ?? item.path),
sampleCount: numberOrNullValue(item.sampleCount),
@@ -2611,13 +2639,74 @@ function compactWebObserveAnalyzeRequestRateCurveForRaw(value: Record<string, un
return {
summary,
buckets: arrayRecordsValue(value.buckets).slice(-4).map(compactWebObserveAnalyzeRequestRateBucketForRaw),
pageCurves: arrayRecordsValue(value.pageCurves).slice(0, 8).map(compactWebObserveAnalyzeRequestRateSeriesForRaw),
apiPathCurves: arrayRecordsValue(value.apiPathCurves).slice(0, 12).map(compactWebObserveAnalyzeRequestRateSeriesForRaw),
peaks: arrayRecordsValue(value.peaks).slice(0, 8),
pageCurves: arrayRecordsValue(value.pageCurves).slice(0, 3).map(compactWebObserveAnalyzeRequestRateSeriesForRaw),
apiPathCurves: arrayRecordsValue(value.apiPathCurves).slice(0, 4).map(compactWebObserveAnalyzeRequestRateSeriesForRaw),
peaks: arrayRecordsValue(value.peaks).slice(0, 4),
valuesRedacted: true,
};
}
function compactWebObserveAnalyzeFrontendPerformanceForRaw(performance: Record<string, unknown>, hotspots: Record<string, unknown>): Record<string, unknown> | null {
const summary = recordValue(performance.summary);
const hasPerformance = Object.keys(summary).length > 0
|| arrayRecordsValue(performance.profileHotspots).length > 0
|| arrayRecordsValue(performance.profileStacks).length > 0
|| arrayRecordsValue(performance.scriptHotspots).length > 0
|| arrayRecordsValue(hotspots.profileFunctions).length > 0
|| arrayRecordsValue(hotspots.profileStacks).length > 0
|| arrayRecordsValue(hotspots.scripts).length > 0;
if (!hasPerformance) return null;
const performanceSummary = Object.keys(summary).length > 0 ? summary : performance;
return {
summary: {
eventCount: numberOrNullValue(performanceSummary.eventCount),
longTaskCount: numberOrNullValue(performanceSummary.longTaskCount),
longAnimationFrameCount: numberOrNullValue(performanceSummary.longAnimationFrameCount),
eventLoopGapCount: numberOrNullValue(performanceSummary.eventLoopGapCount),
captureCount: numberOrNullValue(performanceSummary.captureCount),
maxLongTaskMs: numberOrNullValue(performanceSummary.maxLongTaskMs),
maxLongAnimationFrameMs: numberOrNullValue(performanceSummary.maxLongAnimationFrameMs),
maxEventLoopGapMs: numberOrNullValue(performanceSummary.maxEventLoopGapMs),
profileHotspotCount: numberOrNullValue(performanceSummary.profileHotspotCount),
scriptHotspotCount: numberOrNullValue(performanceSummary.scriptHotspotCount),
valuesRedacted: true,
},
profileFunctions: arrayRecordsValue(hotspots.profileFunctions ?? performance.profileHotspots).slice(0, 4).map(compactWebObserveAnalyzeFrontendHotspotForRaw),
profileStacks: arrayRecordsValue(hotspots.profileStacks ?? performance.profileStacks).slice(0, 3).map(compactWebObserveAnalyzeFrontendStackForRaw),
scriptHotspots: arrayRecordsValue(hotspots.scripts ?? performance.scriptHotspots).slice(0, 4).map(compactWebObserveAnalyzeFrontendHotspotForRaw),
valuesRedacted: true,
};
}
function compactWebObserveAnalyzeFrontendHotspotForRaw(value: Record<string, unknown>): Record<string, unknown> {
return {
functionName: stringOrNullValue(value.functionName ?? value.name ?? value.sourceFunctionName ?? value.invoker)?.slice(0, 80) ?? null,
url: stringOrNullValue(value.url ?? value.sourceURL ?? value.scriptUrl)?.slice(0, 120) ?? null,
lineNumber: numberOrNullValue(value.lineNumber ?? value.line),
columnNumber: numberOrNullValue(value.columnNumber ?? value.column),
selfTimeMs: numberOrNullValue(value.selfTimeMs ?? value.selfMs),
totalTimeMs: numberOrNullValue(value.totalTimeMs ?? value.totalMs),
totalDurationMs: numberOrNullValue(value.totalDurationMs ?? value.durationMs),
hitCount: numberOrNullValue(value.hitCount ?? value.sampleCount ?? value.count),
captureCount: numberOrNullValue(value.captureCount),
valuesRedacted: true,
};
}
function compactWebObserveAnalyzeFrontendStackForRaw(value: Record<string, unknown>): Record<string, unknown> {
return {
...compactWebObserveAnalyzeFrontendHotspotForRaw(value),
frameCount: numberOrNullValue(value.frameCount),
frames: arrayRecordsValue(value.frames).slice(0, 2).map((frame) => ({
functionName: stringOrNullValue(frame.functionName ?? frame.name)?.slice(0, 64) ?? null,
url: stringOrNullValue(frame.url ?? frame.sourceURL ?? frame.scriptUrl)?.slice(0, 96) ?? null,
lineNumber: numberOrNullValue(frame.lineNumber ?? frame.line),
columnNumber: numberOrNullValue(frame.columnNumber ?? frame.column),
valuesRedacted: true,
})),
};
}
function compactWebObserveAnalyzeRequestRateBucketForRaw(value: Record<string, unknown>): Record<string, unknown> {
return {
t: stringOrNullValue(value.startAt ?? value.t),
@@ -2633,7 +2722,7 @@ function compactWebObserveAnalyzeRequestRateSeriesForRaw(value: Record<string, u
bucketCount: numberOrNullValue(value.bucketCount),
peakRequestPerMinute: numberOrNullValue(value.peakRequestPerMinute),
peakBucket: compactWebObserveAnalyzeRequestRateBucketForRaw(recordValue(value.peakBucket)),
buckets: arrayRecordsValue(value.buckets).slice(-20).map(compactWebObserveAnalyzeRequestRateBucketForRaw),
buckets: arrayRecordsValue(value.buckets).slice(-6).map(compactWebObserveAnalyzeRequestRateBucketForRaw),
valuesRedacted: true,
};
const pageKey = stringOrNullValue(value.pageKey);
@@ -2711,22 +2800,15 @@ function compactWebObserveAnalyzeAlertSummaryForRaw(value: unknown): Record<stri
function compactWebObserveAnalyzeFindingForRaw(value: Record<string, unknown>): Record<string, unknown> {
return {
kind: stringOrNullValue(value.kind ?? value.id ?? value.code),
id: stringOrNullValue(value.id ?? value.kind ?? value.code),
code: stringOrNullValue(value.code ?? value.id ?? value.kind),
severity: stringOrNullValue(value.severity ?? value.level),
level: stringOrNullValue(value.level ?? value.severity),
count: numberOrNullValue(value.count ?? value.sampleCount),
sampleCount: numberOrNullValue(value.sampleCount ?? value.count),
timingSourceOfTruth: stringOrNullValue(value.timingSourceOfTruth ?? value.expectedElapsedSource ?? value.evidenceKind),
timingStatus: stringOrNullValue(value.timingStatus),
timingAlert: value.timingAlert === true,
summary: stringOrNullValue(value.summary ?? value.message)?.slice(0, 220) ?? null,
message: stringOrNullValue(value.message ?? value.summary)?.slice(0, 220) ?? null,
rootCause: stringOrNullValue(value.rootCause)?.slice(0, 140) ?? null,
summary: stringOrNullValue(value.summary ?? value.message)?.slice(0, 140) ?? null,
rootCause: stringOrNullValue(value.rootCause)?.slice(0, 90) ?? null,
rootCauseStatus: stringOrNullValue(value.rootCauseStatus)?.slice(0, 90) ?? null,
rootCauseConfidence: stringOrNullValue(value.rootCauseConfidence)?.slice(0, 40) ?? null,
nextAction: stringOrNullValue(value.nextAction)?.slice(0, 240) ?? null,
evidenceSummary: stringOrNullValue(value.evidenceSummary)?.slice(0, 220) ?? null,
valuesRedacted: true,
};
}