fix(web-probe): avoid loading segment gap overcount (#677)

Co-authored-by: Codex <codex@noreply.local>
This commit is contained in:
Lyon
2026-06-22 19:27:42 +08:00
committed by GitHub
parent 0bb82ee822
commit 702fea6239
2 changed files with 15 additions and 9 deletions
+5 -3
View File
@@ -7819,7 +7819,7 @@ function runNodeWebProbeObserveAnalyze(options: NodeWebProbeObserveOptions, spec
"const slimRunnerError = (item) => { const v = objectOrNull(item) || {}; return { ts: v.ts ?? null, type: clip(v.type, 32), commandId: clip(v.commandId, 80), sampleSeq: v.sampleSeq ?? null, message: clip(v.message, 240), retry: clip(v.retry, 24), retryExhausted: v.retryExhausted === true, lastError: clip(v.lastError, 180) }; };",
"const slimJump = (item) => { const v = objectOrNull(item) || {}; return { columnLabel: v.columnLabel ?? null, promptIndex: v.promptIndex ?? null, fromSeq: v.fromSeq ?? null, toSeq: v.toSeq ?? null, fromValue: v.fromValue ?? null, toValue: v.toValue ?? null, delta: v.delta ?? null, sampleDeltaSeconds: v.sampleDeltaSeconds ?? null, allowedIncreaseSeconds: v.allowedIncreaseSeconds ?? null, traceId: v.traceId ?? null }; };",
"const slimLoadingOwner = (item) => { const v = objectOrNull(item) || {}; return { ownerKey: clip(v.ownerKey, 120), ownerKind: clip(v.ownerKind, 32), ownerLabel: clip(v.ownerLabel, 120), sampleCount: v.sampleCount ?? null, occurrenceCount: v.occurrenceCount ?? null, maxSimultaneousCount: v.maxSimultaneousCount ?? null, longestContinuousSeconds: v.longestContinuousSeconds ?? null, firstSeq: v.firstSeq ?? null, lastSeq: v.lastSeq ?? null, promptIndexes: Array.isArray(v.promptIndexes) ? v.promptIndexes.slice(0, 8) : [] }; };",
"const slimLoadingSegment = (item) => { const v = objectOrNull(item) || {}; return { firstAt: v.firstAt ?? null, lastAt: v.lastAt ?? null, endedAt: v.endedAt ?? null, firstSeq: v.firstSeq ?? null, lastSeq: v.lastSeq ?? null, durationSeconds: v.durationSeconds ?? null, sampleCount: v.sampleCount ?? null, maxCount: v.maxCount ?? null, ownerCount: v.ownerCount ?? null, ongoing: v.ongoing === true, owners: Array.isArray(v.owners) ? v.owners.slice(0, 6).map((owner) => ({ ownerKind: clip(owner?.ownerKind, 32), ownerLabel: clip(owner?.ownerLabel, 120), count: owner?.count ?? null })) : [] }; };",
"const slimLoadingSegment = (item) => { const v = objectOrNull(item) || {}; return { firstAt: v.firstAt ?? null, lastAt: v.lastAt ?? null, endedAt: v.endedAt ?? null, firstSeq: v.firstSeq ?? null, lastSeq: v.lastSeq ?? null, durationSeconds: v.durationSeconds ?? null, upperBoundSeconds: v.upperBoundSeconds ?? null, endedGapSeconds: v.endedGapSeconds ?? null, sampleCount: v.sampleCount ?? null, maxCount: v.maxCount ?? null, ownerCount: v.ownerCount ?? null, ongoing: v.ongoing === true, owners: Array.isArray(v.owners) ? v.owners.slice(0, 6).map((owner) => ({ ownerKind: clip(owner?.ownerKind, 32), ownerLabel: clip(owner?.ownerLabel, 120), count: owner?.count ?? null })) : [] }; };",
"const slimLoadingMetrics = (value) => { const v = objectOrNull(value); if (!v) return null; return { summary: objectOrNull(v.summary), longestSegments: takeHead(v.longestSegments ?? v.segments, 8).map(slimLoadingSegment), owners: takeHead(v.owners, 8).map(slimLoadingOwner), timeline: takeTail(v.timeline, 12).map((item) => { const row = objectOrNull(item) || {}; return { seq: row.seq ?? null, ts: row.ts ?? null, promptIndex: row.promptIndex ?? null, loadingCount: row.loadingCount ?? null, ownerCount: row.ownerCount ?? null, owners: Array.isArray(row.owners) ? row.owners.slice(0, 6).map((owner) => ({ ownerKind: clip(owner?.ownerKind, 32), ownerLabel: clip(owner?.ownerLabel, 120), count: owner?.count ?? null })) : [] }; }), valuesRedacted: true }; };",
"const srcMetrics = objectOrNull(source?.sampleMetrics);",
"const metrics = srcMetrics ? {",
@@ -8260,14 +8260,16 @@ function renderWebObserveAnalyzeTable(value: Record<string, unknown>): string {
]) : [["-", "-", "-", "-", "-", "-"]]),
"",
"Loading segments:",
webObserveTable(["DURATION_S", "MAX", "OWNERS", "SEQ", "LAST", "STATUS"], loadingSegments.length > 0 ? loadingSegments.map((item) => [
webObserveTable(["OBSERVED_S", "UPPER_S", "SAMPLES", "MAX", "OWNERS", "SEQ", "LAST", "STATUS"], loadingSegments.length > 0 ? loadingSegments.map((item) => [
webObserveText(item.durationSeconds),
webObserveText(item.upperBoundSeconds ?? item.durationSeconds),
webObserveText(item.sampleCount),
webObserveText(item.maxCount),
webObserveText(item.ownerCount),
`${webObserveText(item.firstSeq)}..${webObserveText(item.lastSeq)}`,
webObserveShort(webObserveText(item.lastAt), 24),
item.ongoing === true ? "ongoing" : webObserveShort(webObserveText(item.endedAt), 24),
]) : [["-", "-", "-", "-", "-", "-"]]),
]) : [["-", "-", "-", "-", "-", "-", "-", "-"]]),
"",
"Turn columns:",
webObserveTable(["TURN", "PROMPT", "TRACE", "FIRST_SEQ", "LAST_SEQ", "SOURCE"], turnColumns.length > 0 ? turnColumns.map((item) => [
@@ -3140,10 +3140,10 @@ function loadingContinuityThresholdMs(events) {
const delta = events[index].tsMs - events[index - 1].tsMs;
if (Number.isFinite(delta) && delta > 0) deltas.push(delta);
}
if (deltas.length === 0) return 15000;
if (deltas.length === 0) return 5000;
const sorted = deltas.slice().sort((a, b) => a - b);
const median = sorted[Math.floor(sorted.length / 2)];
return Math.max(15000, Math.round(median * 2.5));
return Math.min(15000, Math.max(1500, Math.round(median * 2.5)));
}
function buildLoadingSegments(events, continuityThresholdMs, countForEvent, ownersForEvent) {
@@ -3196,9 +3196,11 @@ function buildLoadingSegments(events, continuityThresholdMs, countForEvent, owne
function finalizeLoadingSegment(segment, absentEvent) {
const startMs = Date.parse(segment.firstAt || "");
const endAnchor = absentEvent?.ts || segment.lastAt;
const endMs = Date.parse(endAnchor || "");
const durationSeconds = Number.isFinite(startMs) && Number.isFinite(endMs) && endMs >= startMs ? Number(((endMs - startMs) / 1000).toFixed(3)) : 0;
const lastMs = Date.parse(segment.lastAt || "");
const absentMs = Date.parse(absentEvent?.ts || "");
const durationSeconds = Number.isFinite(startMs) && Number.isFinite(lastMs) && lastMs >= startMs ? Number(((lastMs - startMs) / 1000).toFixed(3)) : 0;
const upperBoundSeconds = Number.isFinite(startMs) && Number.isFinite(absentMs) && absentMs >= startMs ? Number(((absentMs - startMs) / 1000).toFixed(3)) : durationSeconds;
const endedGapSeconds = Number.isFinite(lastMs) && Number.isFinite(absentMs) && absentMs >= lastMs ? Number(((absentMs - lastMs) / 1000).toFixed(3)) : null;
return {
firstAt: segment.firstAt,
lastAt: segment.lastAt,
@@ -3207,6 +3209,8 @@ function finalizeLoadingSegment(segment, absentEvent) {
lastSeq: segment.lastSeq,
endSeq: absentEvent?.seq ?? null,
durationSeconds,
upperBoundSeconds,
endedGapSeconds,
sampleCount: segment.sampleCount,
maxCount: segment.maxCount,
ownerCount: segment.ownerKeys.size,
@@ -4067,7 +4071,7 @@ function renderMarkdown(report) {
? report.sampleMetrics.rounds.map((item) => "- round " + item.promptIndex + " promptHash=" + (item.promptTextHash || "-") + " samples=" + item.sampleCount + " loadingSamples=" + (item.loadingSamples ?? 0) + " maxLoading=" + (item.maxLoadingCount ?? 0) + " loadingOwners=" + (item.loadingOwnerCount ?? 0) + " totalMax=" + (item.maxTotalElapsedSeconds ?? "-") + " totalLast=" + (item.lastTotalElapsedSeconds ?? "-") + " recentMax=" + (item.maxRecentUpdateSeconds ?? "-") + " recentLast=" + (item.lastRecentUpdateSeconds ?? "-") + " totalDecrease=" + (item.turnTimingTotalElapsedDecreaseCount ?? 0) + " totalForwardJump=" + (item.turnTimingTotalElapsedForwardJumpCount ?? 0) + " totalForwardJumpMax=" + (item.turnTimingTotalElapsedForwardJumpMaxSeconds ?? 0) + " terminalGrowth=" + (item.turnTimingTerminalElapsedGrowthCount ?? 0) + " terminalGrowthMax=" + (item.turnTimingTerminalElapsedGrowthMaxSeconds ?? 0) + " recentJump=" + (item.turnTimingRecentUpdateJumpCount ?? 0) + " recentSawtoothJump=" + (item.turnTimingRecentUpdateSawtoothJumpCount ?? item.turnTimingRecentUpdateJumpCount ?? 0) + " recentStep=" + (item.turnTimingRecentUpdateStepCount ?? 0) + " recentMaxIncrease=" + (item.turnTimingRecentUpdateMaxIncreaseSeconds ?? "-") + " recentMaxExcess=" + (item.turnTimingRecentUpdateMaxExcessSeconds ?? 0) + " recentReset=" + (item.turnTimingRecentUpdateResetCount ?? 0) + " diagnostics=" + item.diagnosticSamples + " terminal=" + item.terminalSamples + " finalText=" + item.finalTextSamples).join("\n")
: "- 无轮次指标。";
const loadingSegmentLines = Array.isArray(loading.segments) && loading.segments.length > 0
? loading.segments.slice(0, 80).map((item) => "- duration=" + (item.durationSeconds ?? 0) + "s countMax=" + (item.maxCount ?? 0) + " owners=" + (item.ownerCount ?? 0) + " seq=" + (item.firstSeq ?? "-") + ".." + (item.lastSeq ?? "-") + " ts=" + (item.firstAt || "-") + ".." + (item.lastAt || "-") + " endedAt=" + (item.endedAt || (item.ongoing ? "ongoing" : "-")) + " ownerLabels=" + ((Array.isArray(item.owners) ? item.owners : []).slice(0, 6).map((owner) => (owner.ownerKind || "-") + ":" + (owner.ownerLabel || "-") + "x" + (owner.count ?? 0)).join(",") || "-")).join("\n")
? loading.segments.slice(0, 80).map((item) => "- observedDuration=" + (item.durationSeconds ?? 0) + "s upperBound=" + (item.upperBoundSeconds ?? item.durationSeconds ?? 0) + "s endedGap=" + (item.endedGapSeconds ?? "-") + "s samples=" + (item.sampleCount ?? 0) + " countMax=" + (item.maxCount ?? 0) + " owners=" + (item.ownerCount ?? 0) + " seq=" + (item.firstSeq ?? "-") + ".." + (item.lastSeq ?? "-") + " ts=" + (item.firstAt || "-") + ".." + (item.lastAt || "-") + " endedAt=" + (item.endedAt || (item.ongoing ? "ongoing" : "-")) + " ownerLabels=" + ((Array.isArray(item.owners) ? item.owners : []).slice(0, 6).map((owner) => (owner.ownerKind || "-") + ":" + (owner.ownerLabel || "-") + "x" + (owner.count ?? 0)).join(",") || "-")).join("\n")
: "- 未观察到“加载中”可见区间。";
const loadingOwnerLines = Array.isArray(loading.owners) && loading.owners.length > 0
? loading.owners.slice(0, 80).map((item) => "- " + (item.ownerKind || "-") + " " + escapeMarkdownCell(item.ownerLabel || item.ownerKey || "-") + " samples=" + (item.sampleCount ?? 0) + " occurrences=" + (item.occurrenceCount ?? 0) + " maxCount=" + (item.maxSimultaneousCount ?? 0) + " longest=" + (item.longestContinuousSeconds ?? 0) + "s seq=" + (item.firstSeq ?? "-") + ".." + (item.lastSeq ?? "-") + " prompts=" + (Array.isArray(item.promptIndexes) ? item.promptIndexes.join(",") : "-")).join("\n")