fix: expose full-window web probe timing anomalies (#651)

Co-authored-by: Codex <codex@noreply.local>
This commit is contained in:
Lyon
2026-06-22 13:59:55 +08:00
committed by GitHub
parent 40c593c966
commit 9924212bd9
2 changed files with 200 additions and 14 deletions
+91 -8
View File
@@ -7602,17 +7602,21 @@ function runNodeWebProbeObserveAnalyze(options: NodeWebProbeObserveOptions, spec
"const takeHead = (value, limit) => Array.isArray(value) ? value.slice(0, limit) : [];",
"const takeTail = (value, limit) => Array.isArray(value) ? value.slice(-limit) : [];",
"const firstArray = (...values) => { for (const value of values) if (Array.isArray(value)) return value; return []; };",
"const mergeArrays = (...values) => { const out = []; const seen = new Set(); for (const value of values) { if (!Array.isArray(value)) continue; for (const item of value) { const key = JSON.stringify([item?.id ?? item?.kind ?? item?.code ?? item?.columnLabel ?? item?.traceId ?? null, item?.summary ?? item?.message ?? item?.fromSeq ?? null, item?.toSeq ?? null]); if (seen.has(key)) continue; seen.add(key); out.push(item); } } return out; };",
"const clip = (value, limit = 160) => value === null || value === undefined ? null : String(value).slice(0, limit);",
"const findingRank = (item) => { const id = String(item?.id ?? item?.kind ?? item?.code ?? ''); if (id === 'page-performance-slow-same-origin-api') return 0; if (id.startsWith('turn-timing-total-elapsed')) return 1; if (id.startsWith('turn-timing-recent-update')) return 2; if (id.includes('runtime-execution') || id.includes('prompt-chat-submit-failed')) return 3; return 10; };",
"const severityRank = (item) => { const severity = String(item?.severity ?? item?.level ?? '').toLowerCase(); if (severity === 'red') return 0; if (severity === 'amber' || severity === 'warning') return 1; if (severity === 'info') return 3; return 2; };",
"const sortFindings = (items) => (Array.isArray(items) ? items : []).slice().sort((a, b) => findingRank(a) - findingRank(b) || severityRank(a) - severityRank(b));",
"const stdoutJson = readJson(stdoutPath);",
"const reportJson = readJson(reportJsonPath);",
"const source = (stdoutJson && stdoutJson.ok !== false ? stdoutJson : null) || reportJson || stdoutJson || null;",
"const fullSource = reportJson || source;",
"const objectOrNull = (value) => value && typeof value === 'object' && !Array.isArray(value) ? value : null;",
"const slimRound = (item) => { const v = objectOrNull(item) || {}; return { promptIndex: v.promptIndex ?? null, sampleCount: v.sampleCount ?? null, lastTotalElapsedSeconds: v.lastTotalElapsedSeconds ?? null, lastRecentUpdateSeconds: v.lastRecentUpdateSeconds ?? null, diagnosticSamples: v.diagnosticSamples ?? null, terminalSamples: v.terminalSamples ?? null, promptTextHash: clip(v.promptTextHash, 80) }; };",
"const slimRound = (item) => { const v = objectOrNull(item) || {}; return { promptIndex: v.promptIndex ?? null, sampleCount: v.sampleCount ?? null, lastTotalElapsedSeconds: v.lastTotalElapsedSeconds ?? null, lastRecentUpdateSeconds: v.lastRecentUpdateSeconds ?? null, diagnosticSamples: v.diagnosticSamples ?? null, terminalSamples: v.terminalSamples ?? null, turnTimingTotalElapsedForwardJumpCount: v.turnTimingTotalElapsedForwardJumpCount ?? null, turnTimingTotalElapsedForwardJumpMaxSeconds: v.turnTimingTotalElapsedForwardJumpMaxSeconds ?? null, promptTextHash: clip(v.promptTextHash, 80) }; };",
"const slimTurnColumn = (item) => { const v = objectOrNull(item) || {}; return { label: clip(v.label, 24), promptIndex: v.promptIndex ?? null, lastPromptIndex: v.lastPromptIndex ?? null, traceId: clip(v.traceId, 48), firstSeq: v.firstSeq ?? null, lastSeq: v.lastSeq ?? null, source: clip(v.source, 48) }; };",
"const slimSlowSample = (item) => { const v = objectOrNull(item) || {}; return { ts: v.ts ?? null, seq: v.seq ?? null, path: clip(v.path ?? v.rawPath, 96), initiatorType: clip(v.initiatorType, 24), durationMs: v.durationMs ?? null, requestToResponseStartMs: v.requestToResponseStartMs ?? v.streamOpenMs ?? null, responseTransferMs: v.responseTransferMs ?? null, nextHopProtocol: clip(v.nextHopProtocol, 24) }; };",
"const slimSlowApi = (item) => { const v = objectOrNull(item) || {}; return { path: clip(v.path ?? v.route, 96), route: clip(v.route ?? v.path, 96), sampleCount: v.sampleCount ?? null, p95Ms: v.p95Ms ?? v.p95 ?? null, maxMs: v.maxMs ?? v.max ?? null, overFiveSecondCount: v.overFiveSecondCount ?? null, slowSamples: Array.isArray(v.slowSamples) ? v.slowSamples.slice(0, 3).map(slimSlowSample) : [] }; };",
"const slimFinding = (item) => { const v = objectOrNull(item) || {}; return { kind: clip(v.kind ?? v.code, 48), code: clip(v.code ?? v.kind, 48), severity: clip(v.severity ?? v.level, 24), level: clip(v.level ?? v.severity, 24), count: v.count ?? v.sampleCount ?? null, sampleCount: v.sampleCount ?? v.count ?? null, summary: clip(v.summary ?? v.message, 180), message: clip(v.message ?? v.summary, 180) }; };",
"const slimFinding = (item) => { const v = objectOrNull(item) || {}; return { kind: clip(v.kind ?? v.id ?? v.code, 48), code: clip(v.code ?? v.id ?? v.kind, 48), severity: clip(v.severity ?? v.level, 24), level: clip(v.level ?? v.severity, 24), count: v.count ?? v.sampleCount ?? null, sampleCount: v.sampleCount ?? v.count ?? null, summary: clip(v.summary ?? v.message, 180), message: clip(v.message ?? v.summary, 180) }; };",
"const slimDomGroup = (item) => { const v = objectOrNull(item) || {}; return { count: v.count ?? null, firstAt: v.firstAt ?? null, lastAt: v.lastAt ?? null, text: clip(v.text ?? v.preview, 180) }; };",
"const slimNetworkGroup = (item) => { const v = objectOrNull(item) || {}; return { count: v.count ?? null, method: clip(v.method, 12), status: v.status ?? null, path: clip(v.path, 96), firstAt: v.firstAt ?? null, lastAt: v.lastAt ?? null, promptIndexes: Array.isArray(v.promptIndexes) ? v.promptIndexes.slice(0, 6) : [], failureKinds: Array.isArray(v.failureKinds) ? v.failureKinds.slice(0, 4).map((x) => clip(x, 48)) : [] }; };",
"const slimDomSample = (item) => { const v = objectOrNull(item) || {}; return { seq: v.seq ?? null, ts: v.ts ?? null, source: clip(v.source, 32), diagnosticCode: clip(v.diagnosticCode, 48), traceId: clip(v.traceId, 64), httpStatus: v.httpStatus ?? null, idleSeconds: v.idleSeconds ?? null, waitingFor: clip(v.waitingFor, 48), lastEventLabel: clip(v.lastEventLabel, 80), text: clip(v.text ?? v.preview, 180) }; };",
@@ -7628,6 +7632,8 @@ function runNodeWebProbeObserveAnalyze(options: NodeWebProbeObserveOptions, spec
" turnTimingRows: Array.isArray(srcMetrics.turnTimingRows) ? srcMetrics.turnTimingRows.length : (srcMetrics.turnTimingRows ?? null),",
" turnTimingNonMonotonicCount: srcMetrics.turnTimingNonMonotonicCount ?? null,",
" turnTimingTotalElapsedDecreaseCount: srcMetrics.turnTimingTotalElapsedDecreaseCount ?? null,",
" turnTimingTotalElapsedForwardJumpCount: srcMetrics.turnTimingTotalElapsedForwardJumpCount ?? null,",
" turnTimingTotalElapsedForwardJumpMaxSeconds: srcMetrics.turnTimingTotalElapsedForwardJumpMaxSeconds ?? null,",
" turnTimingTerminalElapsedGrowthCount: srcMetrics.turnTimingTerminalElapsedGrowthCount ?? null,",
" turnTimingRecentUpdateJumpCount: srcMetrics.turnTimingRecentUpdateJumpCount ?? null,",
" turnTimingRecentUpdateSawtoothJumpCount: srcMetrics.turnTimingRecentUpdateSawtoothJumpCount ?? null,",
@@ -7642,6 +7648,7 @@ function runNodeWebProbeObserveAnalyze(options: NodeWebProbeObserveOptions, spec
"const fullRecentWindow = objectOrNull(fullSource?.windows?.recent);",
"const fullPagePerformance = objectOrNull(fullRecentWindow?.pagePerformance) || objectOrNull(fullSource?.pagePerformance);",
"const sourceSlowApi = Array.isArray(source?.pagePerformanceSlowApi) && source.pagePerformanceSlowApi.some((item) => Array.isArray(item?.slowSamples) && item.slowSamples.length > 0) ? source.pagePerformanceSlowApi : (Array.isArray(fullPagePerformance?.sameOriginApiByPath) ? fullPagePerformance.sameOriginApiByPath.filter((item) => Number(item?.overFiveSecondCount ?? 0) > 0) : []);",
"const combinedFindings = sortFindings(mergeArrays(source?.findings, fullSource?.findings));",
"const srcPromptNetwork = objectOrNull(source?.promptNetwork);",
"const promptNetwork = srcPromptNetwork ? { promptSegments: srcPromptNetwork.promptSegments ?? null } : null;",
"const compact = source ? {",
@@ -7654,7 +7661,7 @@ function runNodeWebProbeObserveAnalyze(options: NodeWebProbeObserveOptions, spec
" pagePerformance,",
" promptNetwork,",
" pagePerformanceSlowApi: takeHead(sourceSlowApi, 4).map(slimSlowApi),",
" findings: takeHead(firstArray(source.findings, fullSource?.findings), 6).map(slimFinding),",
" findings: takeHead(combinedFindings, 8).map(slimFinding),",
" httpErrorGroups: takeHead(firstArray(source.httpErrorGroups, fullSource?.httpErrorGroups), 4).map(slimNetworkGroup),",
" requestFailedGroups: takeHead(firstArray(source.requestFailedGroups, fullSource?.requestFailedGroups), 5).map(slimNetworkGroup),",
" domDiagnosticGroups: takeHead(firstArray(source.domDiagnosticGroups, fullSource?.domDiagnosticGroups), 3).map(slimDomGroup),",
@@ -7662,8 +7669,9 @@ function runNodeWebProbeObserveAnalyze(options: NodeWebProbeObserveOptions, spec
" consoleAlertGroups: takeHead(firstArray(source.consoleAlertGroups, fullSource?.consoleAlertGroups), 5).map(slimConsoleGroup),",
" consoleAlertSamples: takeHead(firstArray(source.consoleAlertSamples, fullSource?.consoleAlertSamples), 5).map(slimConsoleSample),",
" runnerErrors: takeTail(firstArray(source.runnerErrors, fullSource?.runnerErrors), 8).map(slimRunnerError),",
" turnTimingRecentUpdateJumps: takeHead(firstArray(source.turnTimingRecentUpdateJumps, srcMetrics?.turnTimingRecentUpdateJumps, fullSource?.turnTimingRecentUpdateJumps), 5).map(slimJump),",
" turnTimingElapsedZeroResets: takeHead(firstArray(source.turnTimingElapsedZeroResets, srcMetrics?.turnTimingElapsedZeroResets, fullSource?.turnTimingElapsedZeroResets), 5).map(slimJump),",
" turnTimingRecentUpdateJumps: takeHead(mergeArrays(source.turnTimingRecentUpdateJumps, srcMetrics?.turnTimingRecentUpdateJumps, fullSource?.sampleMetrics?.turnTimingRecentUpdateSawtoothJumps, fullSource?.turnTimingRecentUpdateJumps), 5).map(slimJump),",
" turnTimingElapsedZeroResets: takeHead(mergeArrays(source.turnTimingElapsedZeroResets, srcMetrics?.turnTimingElapsedZeroResets, fullSource?.sampleMetrics?.turnTimingElapsedZeroResets, fullSource?.turnTimingElapsedZeroResets), 5).map(slimJump),",
" turnTimingTotalElapsedForwardJumps: takeHead(mergeArrays(source.turnTimingTotalElapsedForwardJumps, srcMetrics?.turnTimingTotalElapsedForwardJumps, fullSource?.sampleMetrics?.turnTimingTotalElapsedForwardJumps, fullSource?.turnTimingTotalElapsedForwardJumps), 5).map(slimJump),",
" reportJsonPath: source.reportJsonPath || reportJsonPath,",
" reportJsonSha256: source.reportJsonSha256 || sha256(reportJsonPath),",
" reportMdPath: source.reportMdPath || reportMdPath,",
@@ -7688,7 +7696,47 @@ function runNodeWebProbeObserveAnalyze(options: NodeWebProbeObserveOptions, spec
" stderrTail: tail(readText(stderrPath))",
" }",
"};",
"console.log(JSON.stringify(compact));",
"const compactStdoutLimitBytes = 8000;",
"const compactOutput = (value) => JSON.stringify(value);",
"let output = compactOutput(compact);",
"if (Buffer.byteLength(output, 'utf8') > compactStdoutLimitBytes) {",
" const minimal = {",
" ok: compact.ok,",
" counts: compact.counts ?? null,",
" analysisWindow: compact.analysisWindow ?? null,",
" archiveSummary: compact.archiveSummary ?? null,",
" sampleMetrics: compact.sampleMetrics ? {",
" rounds: Array.isArray(compact.sampleMetrics.rounds) ? compact.sampleMetrics.rounds : compact.sampleMetrics.rounds ?? null,",
" turnTimingRows: compact.sampleMetrics.turnTimingRows ?? null,",
" turnTimingNonMonotonicCount: compact.sampleMetrics.turnTimingNonMonotonicCount ?? null,",
" turnTimingTotalElapsedDecreaseCount: compact.sampleMetrics.turnTimingTotalElapsedDecreaseCount ?? null,",
" turnTimingTotalElapsedForwardJumpCount: compact.sampleMetrics.turnTimingTotalElapsedForwardJumpCount ?? null,",
" turnTimingTotalElapsedForwardJumpMaxSeconds: compact.sampleMetrics.turnTimingTotalElapsedForwardJumpMaxSeconds ?? null,",
" turnTimingTerminalElapsedGrowthCount: compact.sampleMetrics.turnTimingTerminalElapsedGrowthCount ?? null,",
" turnTimingRecentUpdateJumpCount: compact.sampleMetrics.turnTimingRecentUpdateJumpCount ?? null,",
" turnTimingRecentUpdateSawtoothJumpCount: compact.sampleMetrics.turnTimingRecentUpdateSawtoothJumpCount ?? null,",
" turnTimingRecentUpdateMaxIncreaseSeconds: compact.sampleMetrics.turnTimingRecentUpdateMaxIncreaseSeconds ?? null,",
" turnColumns: Array.isArray(compact.sampleMetrics.turnColumns) ? compact.sampleMetrics.turnColumns.slice(-6) : []",
" } : null,",
" runtimeAlerts: compact.runtimeAlerts ?? null,",
" pagePerformance: compact.pagePerformance ?? null,",
" promptNetwork: compact.promptNetwork ?? null,",
" findings: Array.isArray(compact.findings) ? compact.findings.slice(0, 4) : [],",
" pagePerformanceSlowApi: Array.isArray(compact.pagePerformanceSlowApi) ? compact.pagePerformanceSlowApi.slice(0, 3) : [],",
" runnerErrors: Array.isArray(compact.runnerErrors) ? compact.runnerErrors.slice(-4) : [],",
" turnTimingRecentUpdateJumps: Array.isArray(compact.turnTimingRecentUpdateJumps) ? compact.turnTimingRecentUpdateJumps.slice(0, 4) : [],",
" turnTimingElapsedZeroResets: Array.isArray(compact.turnTimingElapsedZeroResets) ? compact.turnTimingElapsedZeroResets.slice(0, 4) : [],",
" turnTimingTotalElapsedForwardJumps: Array.isArray(compact.turnTimingTotalElapsedForwardJumps) ? compact.turnTimingTotalElapsedForwardJumps.slice(0, 4) : [],",
" reportJsonPath: compact.reportJsonPath ?? reportJsonPath,",
" reportJsonSha256: compact.reportJsonSha256 ?? sha256(reportJsonPath),",
" reportMdPath: compact.reportMdPath ?? reportMdPath,",
" reportMdSha256: compact.reportMdSha256 ?? sha256(reportMdPath),",
" analyzer: { ...(compact.analyzer ?? {}), compactStdoutLimited: true, compactStdoutLimitBytes, originalCompactBytes: Buffer.byteLength(output, 'utf8') },",
" valuesRedacted: true",
" };",
" output = compactOutput(minimal);",
"}",
"console.log(output);",
"UNIDESK_WEB_OBSERVE_ANALYZE_COMPACT",
"exit \"$analyzer_exit\"",
].join("\n");
@@ -7725,6 +7773,7 @@ function renderWebObserveAnalyzeTable(value: Record<string, unknown>): string {
const analysisWindow = record(analysis?.analysisWindow);
const archiveSummary = record(analysis?.archiveSummary);
const sampleMetrics = record(analysis?.sampleMetrics);
const archiveMetrics = record(archiveSummary?.sampleMetrics);
const runtimeAlerts = record(analysis?.runtimeAlerts);
const pagePerformance = record(analysis?.pagePerformance);
const promptNetwork = record(analysis?.promptNetwork);
@@ -7743,6 +7792,7 @@ function renderWebObserveAnalyzeTable(value: Record<string, unknown>): string {
const runnerErrors = Array.isArray(analysis?.runnerErrors) ? analysis.runnerErrors.map(record).filter((item): item is Record<string, unknown> => item !== null).slice(-8) : [];
const recentUpdateJumps = Array.isArray(analysis?.turnTimingRecentUpdateJumps) ? analysis.turnTimingRecentUpdateJumps.map(record).filter((item): item is Record<string, unknown> => item !== null).slice(0, 8) : [];
const elapsedZeroResets = Array.isArray(analysis?.turnTimingElapsedZeroResets) ? analysis.turnTimingElapsedZeroResets.map(record).filter((item): item is Record<string, unknown> => item !== null).slice(0, 8) : [];
const elapsedForwardJumps = Array.isArray(analysis?.turnTimingTotalElapsedForwardJumps) ? analysis.turnTimingTotalElapsedForwardJumps.map(record).filter((item): item is Record<string, unknown> => item !== null).slice(0, 8) : [];
const domDiagnosticRows = domDiagnostics.length > 0
? domDiagnostics.map((item) => [
webObserveText(item.count),
@@ -7801,6 +7851,17 @@ function renderWebObserveAnalyzeTable(value: Record<string, unknown>): string {
webObserveText(item.delta),
webObserveShort(webObserveText(item.traceId), 24),
]);
const elapsedForwardJumpRows = elapsedForwardJumps.map((item) => [
webObserveShort(webObserveText(item.columnLabel), 14),
webObserveText(item.promptIndex),
webObserveText(item.fromSeq),
webObserveText(item.toSeq),
`${webObserveText(item.fromValue)}->${webObserveText(item.toValue)}`,
webObserveText(item.delta),
webObserveText(item.sampleDeltaSeconds),
webObserveText(item.allowedIncreaseSeconds),
webObserveShort(webObserveText(item.traceId), 24),
]);
const httpErrorRows = httpErrorGroups.map((item) => [
webObserveText(item.count),
webObserveText(item.method),
@@ -7866,18 +7927,34 @@ function renderWebObserveAnalyzeTable(value: Record<string, unknown>): string {
]),
"",
"Turn timing:",
webObserveTable(["ROUNDS", "TURNS", "ROWS", "NON_MONO", "ELAPSED_DEC", "ZERO_RESET", "TERMINAL_GROWTH", "RECENT_JUMP", "MAX_RECENT_STEP"], [[
webObserveTable(["ROUNDS", "TURNS", "ROWS", "NON_MONO", "ELAPSED_DEC", "ZERO_RESET", "ELAPSED_JUMP", "TERMINAL_GROWTH", "RECENT_JUMP", "MAX_RECENT_STEP"], [[
webObserveText(roundCount),
webObserveText(turnColumnCount),
webObserveText(sampleMetrics?.turnTimingRows),
webObserveText(sampleMetrics?.turnTimingNonMonotonicCount),
webObserveText(sampleMetrics?.turnTimingTotalElapsedDecreaseCount),
webObserveText(sampleMetrics?.turnTimingTotalElapsedZeroResetCount ?? elapsedZeroResets.length),
webObserveText(sampleMetrics?.turnTimingTotalElapsedForwardJumpCount ?? elapsedForwardJumps.length),
webObserveText(sampleMetrics?.turnTimingTerminalElapsedGrowthCount),
webObserveText(sampleMetrics?.turnTimingRecentUpdateJumpCount ?? sampleMetrics?.turnTimingRecentUpdateSawtoothJumpCount),
webObserveText(sampleMetrics?.turnTimingRecentUpdateMaxIncreaseSeconds),
]]),
"",
"Archive turn timing:",
webObserveTable(["SAMPLES", "ROUNDS", "TURNS", "ROWS", "NON_MONO", "ELAPSED_DEC", "ZERO_RESET", "ELAPSED_JUMP", "TERMINAL_GROWTH", "RECENT_JUMP", "MAX_RECENT_STEP"], [[
webObserveText(archiveMetrics?.sampleCount),
webObserveText(archiveMetrics?.rounds),
webObserveText(archiveMetrics?.turnColumns),
webObserveText(archiveMetrics?.turnTimingRows),
webObserveText(archiveMetrics?.turnTimingNonMonotonicCount),
webObserveText(archiveMetrics?.turnTimingTotalElapsedDecreaseCount),
webObserveText(archiveMetrics?.turnTimingTotalElapsedZeroResetCount),
webObserveText(archiveMetrics?.turnTimingTotalElapsedForwardJumpCount),
webObserveText(archiveMetrics?.turnTimingTerminalElapsedGrowthCount),
webObserveText(archiveMetrics?.turnTimingRecentUpdateJumpCount ?? archiveMetrics?.turnTimingRecentUpdateSawtoothJumpCount),
webObserveText(archiveMetrics?.turnTimingRecentUpdateMaxIncreaseSeconds),
]]),
"",
"Rounds:",
webObserveTable(["ROUND", "SAMPLES", "TOTAL_LAST", "RECENT_LAST", "DIAG", "TERMINAL", "PROMPT_HASH"], rounds.length > 0 ? rounds.map((item) => [
webObserveText(item.promptIndex),
@@ -7905,6 +7982,9 @@ function renderWebObserveAnalyzeTable(value: Record<string, unknown>): string {
"Total elapsed zero resets:",
webObserveTable(["TURN", "PROMPT", "FROM_SEQ", "TO_SEQ", "VALUE", "DELTA", "TRACE"], elapsedZeroResetRows.length > 0 ? elapsedZeroResetRows : [["-", "-", "-", "-", "-", "-", "-"]]),
"",
"Total elapsed forward jumps:",
webObserveTable(["TURN", "PROMPT", "FROM_SEQ", "TO_SEQ", "VALUE", "DELTA", "SAMPLE_S", "ALLOWED", "TRACE"], elapsedForwardJumpRows.length > 0 ? elapsedForwardJumpRows : [["-", "-", "-", "-", "-", "-", "-", "-", "-"]]),
"",
"Runtime alerts:",
webObserveTable(["HTTP_ERR", "REQUEST_FAILED", "DOM_DIAG", "CONSOLE_ALERT", "PROMPT_SEGMENTS", "PROMPT_NETWORK"], [[
webObserveText(runtimeAlerts?.httpErrorCount),
@@ -8372,6 +8452,8 @@ function renderWebObserveAnalyzeResult(result: Record<string, unknown>): Record<
[
["nonMonotonic", sampleMetrics.turnTimingNonMonotonicCount],
["elapsedDecrease", sampleMetrics.turnTimingTotalElapsedDecreaseCount],
["elapsedForwardJump", sampleMetrics.turnTimingTotalElapsedForwardJumpCount],
["elapsedForwardJumpMaxSec", sampleMetrics.turnTimingTotalElapsedForwardJumpMaxSeconds],
["recentJump", sampleMetrics.turnTimingRecentUpdateJumpCount],
["maxRecentStepSec", sampleMetrics.turnTimingRecentUpdateMaxIncreaseSeconds],
],
@@ -8380,7 +8462,7 @@ function renderWebObserveAnalyzeResult(result: Record<string, unknown>): Record<
rounds.length === 0
? "ROUNDS\n-"
: webObserveTable(
["ROUND", "COMMAND", "SAMPLES", "TOTAL_MAX", "TOTAL_LAST", "RECENT_MAX", "RECENT_LAST", "DIAG", "TERM", "NONMONO", "JUMP"],
["ROUND", "COMMAND", "SAMPLES", "TOTAL_MAX", "TOTAL_LAST", "RECENT_MAX", "RECENT_LAST", "DIAG", "TERM", "NONMONO", "ELAPSED_JUMP", "JUMP"],
rounds.map((item) => [
item.promptIndex,
item.promptCommandId,
@@ -8392,6 +8474,7 @@ function renderWebObserveAnalyzeResult(result: Record<string, unknown>): Record<
item.diagnosticSamples,
item.terminalSamples,
item.turnTimingNonMonotonicCount,
item.turnTimingTotalElapsedForwardJumpCount,
item.turnTimingRecentUpdateJumpCount,
]),
),