fix(web-probe): focus analysis after latest new session (#833)
Co-authored-by: Codex <codex@noreply.local>
This commit is contained in:
@@ -8678,6 +8678,7 @@ function runNodeWebProbeObserveAnalyze(options: NodeWebProbeObserveOptions, spec
|
||||
" const minimal = {",
|
||||
" ok: compact.ok,",
|
||||
" counts: compact.counts ?? null,",
|
||||
" jsonlScope: compact.jsonlScope ?? null,",
|
||||
" analysisWindow: compact.analysisWindow ?? null,",
|
||||
" archiveSummary: compact.archiveSummary ?? null,",
|
||||
" sampleMetrics: compact.sampleMetrics ? {",
|
||||
@@ -8745,6 +8746,7 @@ function runNodeWebProbeObserveAnalyze(options: NodeWebProbeObserveOptions, spec
|
||||
" const tiny = {",
|
||||
" ok: compact.ok,",
|
||||
" counts: compact.counts ?? null,",
|
||||
" jsonlScope: compact.jsonlScope ?? null,",
|
||||
" analysisWindow: compact.analysisWindow ?? null,",
|
||||
" archiveSummary: compact.archiveSummary ?? null,",
|
||||
" sampleMetrics: compact.sampleMetrics ? {",
|
||||
@@ -8832,7 +8834,7 @@ function runNodeWebProbeObserveAnalyze(options: NodeWebProbeObserveOptions, spec
|
||||
" output = compactOutput(ultratiny);",
|
||||
" }",
|
||||
" if (Buffer.byteLength(output, 'utf8') > compactStdoutLimitBytes) {",
|
||||
" output = compactOutput({ ok: compact.ok, counts: compact.counts ?? null, analysisWindow: compact.analysisWindow ?? null, archiveSummary: compact.archiveSummary ?? 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, 120) })) : [], archiveRedFindings: Array.isArray(compact.archiveRedFindings) ? compact.archiveRedFindings.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, 120) })) : [], commandFailures: Array.isArray(compact.commandFailures) ? compact.commandFailures.slice(-3).map((item) => ({ ts: item.ts ?? null, type: item.type ?? null, commandId: item.commandId ?? null, durationMs: item.durationMs ?? null, sampleSeq: item.sampleSeq ?? null, beforePath: item.beforePath ?? null, afterPath: item.afterPath ?? null, message: clip(item.message ?? item.failureKind ?? item.name, 120) })) : [], archivePagePerformanceSlowApi: Array.isArray(compact.archivePagePerformanceSlowApi) ? compact.archivePagePerformanceSlowApi.slice(0, 4).map((item) => ({ path: item.path ?? item.route ?? null, sampleCount: item.sampleCount ?? null, p95Ms: item.p95Ms ?? null, maxMs: item.maxMs ?? null, overFiveSecondCount: item.overFiveSecondCount ?? null })) : [], reportJsonPath: compact.reportJsonPath ?? reportJsonPath, reportJsonSha256: compact.reportJsonSha256 ?? sha256(reportJsonPath), reportMdPath: compact.reportMdPath ?? reportMdPath, reportMdSha256: compact.reportMdSha256 ?? sha256(reportMdPath), analyzer: { ...(compact.analyzer ?? {}), compactStdoutLimited: true, ultratiny: true, hardFallback: true, compactStdoutLimitBytes }, valuesRedacted: true });",
|
||||
" output = compactOutput({ ok: compact.ok, counts: compact.counts ?? null, jsonlScope: compact.jsonlScope ?? null, analysisWindow: compact.analysisWindow ?? null, archiveSummary: compact.archiveSummary ?? 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, 120) })) : [], archiveRedFindings: Array.isArray(compact.archiveRedFindings) ? compact.archiveRedFindings.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, 120) })) : [], commandFailures: Array.isArray(compact.commandFailures) ? compact.commandFailures.slice(-3).map((item) => ({ ts: item.ts ?? null, type: item.type ?? null, commandId: item.commandId ?? null, durationMs: item.durationMs ?? null, sampleSeq: item.sampleSeq ?? null, beforePath: item.beforePath ?? null, afterPath: item.afterPath ?? null, message: clip(item.message ?? item.failureKind ?? item.name, 120) })) : [], archivePagePerformanceSlowApi: Array.isArray(compact.archivePagePerformanceSlowApi) ? compact.archivePagePerformanceSlowApi.slice(0, 4).map((item) => ({ path: item.path ?? item.route ?? null, sampleCount: item.sampleCount ?? null, p95Ms: item.p95Ms ?? null, maxMs: item.maxMs ?? null, overFiveSecondCount: item.overFiveSecondCount ?? null })) : [], reportJsonPath: compact.reportJsonPath ?? reportJsonPath, reportJsonSha256: compact.reportJsonSha256 ?? sha256(reportJsonPath), reportMdPath: compact.reportMdPath ?? reportMdPath, reportMdSha256: compact.reportMdSha256 ?? sha256(reportMdPath), analyzer: { ...(compact.analyzer ?? {}), compactStdoutLimited: true, ultratiny: true, hardFallback: true, compactStdoutLimitBytes }, valuesRedacted: true });",
|
||||
" }",
|
||||
" }",
|
||||
"}",
|
||||
@@ -9166,7 +9168,7 @@ function renderWebObserveAnalyzeTable(value: Record<string, unknown>): string {
|
||||
webObserveText(value.id),
|
||||
webObserveText(value.node),
|
||||
webObserveText(value.lane),
|
||||
webObserveShort([webObserveText(jsonlScope?.mode ?? "current"), jsonlScope?.archivePrefix ? webObserveText(jsonlScope.archivePrefix) : ""].filter((part) => part && part !== "-").join(":"), 36),
|
||||
webObserveShort([webObserveText(jsonlScope?.mode ?? "current"), webObserveText(record(jsonlScope?.focus)?.mode), jsonlScope?.archivePrefix ? webObserveText(jsonlScope.archivePrefix) : ""].filter((part) => part && part !== "-").join(":"), 36),
|
||||
webObserveText(counts?.samples),
|
||||
webObserveText(counts?.control),
|
||||
webObserveText(counts?.network),
|
||||
|
||||
@@ -2116,15 +2116,18 @@ const reportJsonPath = path.join(analysisDir, "report.json");
|
||||
const reportMdPath = path.join(analysisDir, "report.md");
|
||||
const jsonlReadIssues = [];
|
||||
const sourceSamples = await readJsonl(dataFile("samples.jsonl"), { compact: compactSampleForAnalysis, tail: analyzeTailSamples });
|
||||
const samples = sourceSamples;
|
||||
const sampleWindow = sampleTimeWindow(samples, 60_000);
|
||||
const relatedJsonlTailLimit = analyzeTailSamples > 0 ? Math.max(1200, analyzeTailSamples * 50) : 0;
|
||||
const smallJsonlTailLimit = analyzeTailSamples > 0 ? Math.max(500, analyzeTailSamples * 8) : 0;
|
||||
const control = filterRowsByTimeWindow(await readJsonl(dataFile("control.jsonl"), { tail: relatedJsonlTailLimit }), sampleWindow);
|
||||
const network = filterRowsByTimeWindow(await readJsonl(dataFile("network.jsonl"), { tail: relatedJsonlTailLimit }), sampleWindow);
|
||||
const consoleEvents = filterRowsByTimeWindow(await readJsonl(dataFile("console.jsonl"), { tail: smallJsonlTailLimit }), sampleWindow);
|
||||
const errors = filterRowsByTimeWindow(await readJsonl(dataFile("errors.jsonl"), { tail: smallJsonlTailLimit }), sampleWindow);
|
||||
const artifacts = filterRowsByTimeWindow(await readJsonl(dataFile("artifacts.jsonl"), { tail: smallJsonlTailLimit }), sampleWindow);
|
||||
const sourceSampleWindow = sampleTimeWindow(sourceSamples, 60_000);
|
||||
const sourceControl = filterRowsByTimeWindow(await readJsonl(dataFile("control.jsonl"), { tail: relatedJsonlTailLimit }), sourceSampleWindow);
|
||||
const analysisFocus = analysisFocusFromControl(sourceControl);
|
||||
const samples = applyAnalysisFocus(sourceSamples, analysisFocus);
|
||||
const sampleWindow = sampleTimeWindow(samples, 60_000);
|
||||
const control = applyAnalysisFocus(filterRowsByTimeWindow(sourceControl, sampleWindow), analysisFocus, 1000);
|
||||
const network = applyAnalysisFocus(filterRowsByTimeWindow(await readJsonl(dataFile("network.jsonl"), { tail: relatedJsonlTailLimit }), sampleWindow), analysisFocus);
|
||||
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 manifest = await readJson(path.join(stateDir, "manifest.json"));
|
||||
const heartbeat = await readJson(path.join(stateDir, "heartbeat.json"));
|
||||
|
||||
@@ -2185,7 +2188,7 @@ const report = {
|
||||
command: "web-probe-observe analyze",
|
||||
generatedAt: new Date().toISOString(),
|
||||
stateDir,
|
||||
jsonlScope: { mode: archivePrefix ? "archive" : "current", archivePrefix: archivePrefix || null, dataDir, analyzeTailSamples, sourceSampleCount: sourceSamples.length, effectiveSampleCount: samples.length, sampleWindow, valuesRedacted: true },
|
||||
jsonlScope: { mode: archivePrefix ? "archive" : "current", archivePrefix: archivePrefix || null, dataDir, analyzeTailSamples, sourceSampleCount: sourceSamples.length, effectiveSampleCount: samples.length, sampleWindow, focus: analysisFocus, valuesRedacted: true },
|
||||
alertThresholds,
|
||||
manifest: compactManifest(manifest),
|
||||
heartbeat: compactHeartbeat(heartbeat),
|
||||
@@ -2601,6 +2604,33 @@ function filterRowsByTimeWindow(rows, window) {
|
||||
});
|
||||
}
|
||||
|
||||
function analysisFocusFromControl(control) {
|
||||
const completedNewSessions = (Array.isArray(control) ? control : [])
|
||||
.filter((item) => item?.type === "newSession" && item?.phase === "completed" && Number.isFinite(Date.parse(String(item.ts || ""))))
|
||||
.sort((a, b) => Date.parse(String(a.ts || "")) - Date.parse(String(b.ts || "")));
|
||||
const latest = completedNewSessions.at(-1) ?? null;
|
||||
if (!latest) return { mode: "all", reason: "no-new-session-command", startAt: null, startMs: null, commandId: null, valuesRedacted: true };
|
||||
const startMs = Date.parse(String(latest.ts));
|
||||
return {
|
||||
mode: "after-new-session",
|
||||
reason: "latest-completed-new-session",
|
||||
startAt: new Date(startMs).toISOString(),
|
||||
startMs,
|
||||
commandId: latest.commandId ?? null,
|
||||
valuesRedacted: true
|
||||
};
|
||||
}
|
||||
|
||||
function applyAnalysisFocus(rows, focus, graceMs = 0) {
|
||||
if (!focus || !Number.isFinite(focus.startMs)) return rows;
|
||||
const minMs = focus.startMs - Math.max(0, Number(graceMs) || 0);
|
||||
return (Array.isArray(rows) ? rows : []).filter((item) => {
|
||||
const value = item && (item.ts || item.observedAt || item.startedAt || item.finishedAt || item.createdAt || item.updatedAt);
|
||||
const ms = Date.parse(String(value || ""));
|
||||
return Number.isFinite(ms) ? ms >= minMs : true;
|
||||
});
|
||||
}
|
||||
|
||||
function compactSampleForAnalysis(sample) {
|
||||
if (!sample || typeof sample !== "object") return sample;
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user