fix(web-probe): keep sampling through startup degradation (#709)

Co-authored-by: Codex <codex@noreply.local>
This commit is contained in:
Lyon
2026-06-23 01:04:27 +08:00
committed by GitHub
parent 30d64d762f
commit 7a72e396ba
2 changed files with 75 additions and 43 deletions
+64 -36
View File
@@ -8135,12 +8135,12 @@ function runNodeWebProbeObserveAnalyze(options: NodeWebProbeObserveOptions, spec
" loadingLongestContinuousSeconds: compact.sampleMetrics.loadingLongestContinuousSeconds ?? null,",
" loadingCurrentContinuousSeconds: compact.sampleMetrics.loadingCurrentContinuousSeconds ?? null,",
" loadingOverFiveSecondSegmentCount: compact.sampleMetrics.loadingOverFiveSecondSegmentCount ?? null,",
" sessionRailSampleCount: compact.sampleMetrics.sessionRailSampleCount ?? null,",
" sessionRailVisibleSampleCount: compact.sampleMetrics.sessionRailVisibleSampleCount ?? null,",
" sessionRailFallbackMajoritySampleCount: compact.sampleMetrics.sessionRailFallbackMajoritySampleCount ?? null,",
" sessionRailFallbackMaxRatio: compact.sampleMetrics.sessionRailFallbackMaxRatio ?? null,",
" sessionRailFallbackMaxVisibleCount: compact.sampleMetrics.sessionRailFallbackMaxVisibleCount ?? null,",
" sessionRailFallbackMaxCount: compact.sampleMetrics.sessionRailFallbackMaxCount ?? null,",
" sessionRailSampleCount: compact.sampleMetrics.sessionRailSampleCount ?? compact.sampleMetrics.sessionRailTitles?.summary?.sampleCount ?? null,",
" sessionRailVisibleSampleCount: compact.sampleMetrics.sessionRailVisibleSampleCount ?? compact.sampleMetrics.sessionRailTitles?.summary?.visibleSampleCount ?? null,",
" sessionRailFallbackMajoritySampleCount: compact.sampleMetrics.sessionRailFallbackMajoritySampleCount ?? compact.sampleMetrics.sessionRailTitles?.summary?.majorityFallbackSampleCount ?? null,",
" sessionRailFallbackMaxRatio: compact.sampleMetrics.sessionRailFallbackMaxRatio ?? compact.sampleMetrics.sessionRailTitles?.summary?.maxFallbackRatio ?? null,",
" sessionRailFallbackMaxVisibleCount: compact.sampleMetrics.sessionRailFallbackMaxVisibleCount ?? compact.sampleMetrics.sessionRailTitles?.summary?.maxVisibleCount ?? null,",
" sessionRailFallbackMaxCount: compact.sampleMetrics.sessionRailFallbackMaxCount ?? compact.sampleMetrics.sessionRailTitles?.summary?.maxFallbackTitleCount ?? null,",
" loading: compact.sampleMetrics.loading ?? null,",
" sessionRailTitles: compact.sampleMetrics.sessionRailTitles ? { summary: compact.sampleMetrics.sessionRailTitles.summary ?? null, samples: Array.isArray(compact.sampleMetrics.sessionRailTitles.samples) ? compact.sampleMetrics.sessionRailTitles.samples.slice(0, 4) : [], examples: Array.isArray(compact.sampleMetrics.sessionRailTitles.examples) ? compact.sampleMetrics.sessionRailTitles.examples.slice(0, 4) : [] } : null,",
" turnTimingRows: compact.sampleMetrics.turnTimingRows ?? null,",
@@ -8193,9 +8193,12 @@ function runNodeWebProbeObserveAnalyze(options: NodeWebProbeObserveOptions, spec
" loadingCurrentContinuousSeconds: compact.sampleMetrics.loadingCurrentContinuousSeconds ?? null,",
" loadingOverFiveSecondSegmentCount: compact.sampleMetrics.loadingOverFiveSecondSegmentCount ?? null,",
" loading: compact.sampleMetrics.loading ? { summary: compact.sampleMetrics.loading.summary ?? null, longestSegments: Array.isArray(compact.sampleMetrics.loading.longestSegments) ? compact.sampleMetrics.loading.longestSegments.slice(0, 4) : [], owners: Array.isArray(compact.sampleMetrics.loading.owners) ? compact.sampleMetrics.loading.owners.slice(0, 4) : [] } : null,",
" sessionRailFallbackMajoritySampleCount: compact.sampleMetrics.sessionRailFallbackMajoritySampleCount ?? null,",
" sessionRailFallbackMaxRatio: compact.sampleMetrics.sessionRailFallbackMaxRatio ?? null,",
" sessionRailFallbackMaxCount: compact.sampleMetrics.sessionRailFallbackMaxCount ?? null,",
" sessionRailSampleCount: compact.sampleMetrics.sessionRailSampleCount ?? compact.sampleMetrics.sessionRailTitles?.summary?.sampleCount ?? null,",
" sessionRailVisibleSampleCount: compact.sampleMetrics.sessionRailVisibleSampleCount ?? compact.sampleMetrics.sessionRailTitles?.summary?.visibleSampleCount ?? null,",
" sessionRailFallbackMajoritySampleCount: compact.sampleMetrics.sessionRailFallbackMajoritySampleCount ?? compact.sampleMetrics.sessionRailTitles?.summary?.majorityFallbackSampleCount ?? null,",
" sessionRailFallbackMaxRatio: compact.sampleMetrics.sessionRailFallbackMaxRatio ?? compact.sampleMetrics.sessionRailTitles?.summary?.maxFallbackRatio ?? null,",
" sessionRailFallbackMaxVisibleCount: compact.sampleMetrics.sessionRailFallbackMaxVisibleCount ?? compact.sampleMetrics.sessionRailTitles?.summary?.maxVisibleCount ?? null,",
" sessionRailFallbackMaxCount: compact.sampleMetrics.sessionRailFallbackMaxCount ?? compact.sampleMetrics.sessionRailTitles?.summary?.maxFallbackTitleCount ?? null,",
" sessionRailTitles: compact.sampleMetrics.sessionRailTitles ? { summary: compact.sampleMetrics.sessionRailTitles.summary ?? null, samples: Array.isArray(compact.sampleMetrics.sessionRailTitles.samples) ? compact.sampleMetrics.sessionRailTitles.samples.slice(0, 4) : [], examples: Array.isArray(compact.sampleMetrics.sessionRailTitles.examples) ? compact.sampleMetrics.sessionRailTitles.examples.slice(0, 4) : [] } : null,",
" turnTimingRows: compact.sampleMetrics.turnTimingRows ?? null,",
" turnTimingNonMonotonicCount: compact.sampleMetrics.turnTimingNonMonotonicCount ?? null,",
@@ -8478,15 +8481,15 @@ function renderWebObserveAnalyzeTable(value: Record<string, unknown>): string {
webObserveText(loadingSummary?.overFiveSecondSegmentCount ?? sampleMetrics?.loadingOverFiveSecondSegmentCount),
]]),
"",
"Session rail titles:",
webObserveTable(["SAMPLES", "VISIBLE", "MAJORITY", "MAX_RATIO", "MAX_VISIBLE", "MAX_FALLBACK"], [[
webObserveText(sessionRailTitleSummary?.sampleCount ?? sampleMetrics?.sessionRailSampleCount),
webObserveText(sessionRailTitleSummary?.visibleSampleCount ?? sampleMetrics?.sessionRailVisibleSampleCount),
webObserveText(sessionRailTitleSummary?.majorityFallbackSampleCount ?? sampleMetrics?.sessionRailFallbackMajoritySampleCount),
webObserveText(sessionRailTitleSummary?.maxFallbackRatio ?? sampleMetrics?.sessionRailFallbackMaxRatio),
webObserveText(sessionRailTitleSummary?.maxVisibleCount ?? sampleMetrics?.sessionRailFallbackMaxVisibleCount),
webObserveText(sessionRailTitleSummary?.maxFallbackTitleCount ?? sampleMetrics?.sessionRailFallbackMaxCount),
]]),
"Session rail titles:",
webObserveTable(["SAMPLES", "VISIBLE", "MAJORITY", "MAX_RATIO", "MAX_VISIBLE", "MAX_FALLBACK"], [[
webObserveText(sessionRailTitleSummary?.sampleCount ?? sampleMetrics?.sessionRailSampleCount ?? archiveMetrics?.sessionRailSampleCount),
webObserveText(sessionRailTitleSummary?.visibleSampleCount ?? sampleMetrics?.sessionRailVisibleSampleCount ?? archiveMetrics?.sessionRailVisibleSampleCount),
webObserveText(sessionRailTitleSummary?.majorityFallbackSampleCount ?? sampleMetrics?.sessionRailFallbackMajoritySampleCount ?? archiveMetrics?.sessionRailFallbackMajoritySampleCount),
webObserveText(sessionRailTitleSummary?.maxFallbackRatio ?? sampleMetrics?.sessionRailFallbackMaxRatio ?? archiveMetrics?.sessionRailFallbackMaxRatio),
webObserveText(sessionRailTitleSummary?.maxVisibleCount ?? sampleMetrics?.sessionRailFallbackMaxVisibleCount ?? archiveMetrics?.sessionRailFallbackMaxVisibleCount),
webObserveText(sessionRailTitleSummary?.maxFallbackTitleCount ?? sampleMetrics?.sessionRailFallbackMaxCount ?? archiveMetrics?.sessionRailFallbackMaxCount),
]]),
sessionRailTitleSamples.length === 0 ? "Session rail fallback samples:\n-" : webObserveTable(["SEQ", "ROLE", "VISIBLE", "FALLBACK", "RATIO", "EXAMPLE"], sessionRailTitleSamples.map((item) => [
webObserveText(item.seq),
webObserveText(item.pageRole),
@@ -9638,24 +9641,49 @@ function readNodeWebProbeScriptReport(
"const reportPath = process.argv[2];",
"const report = JSON.parse(fs.readFileSync(reportPath, 'utf8'));",
"function rec(value) { return value && typeof value === 'object' && !Array.isArray(value) ? value : {}; }",
"function compact(value, depth = 0) {",
" if (value === null || value === undefined) return value ?? null;",
" if (typeof value === 'string') return value.replace(/\\s+/gu, ' ').trim().slice(0, 240);",
" if (typeof value === 'number' || typeof value === 'boolean') return value;",
" if (depth >= 4) return '[max-depth]';",
" if (Array.isArray(value)) return value.slice(0, 6).map((item) => compact(item, depth + 1));",
" if (typeof value === 'object') {",
" const out = {};",
" for (const [key, nested] of Object.entries(value).slice(0, 12)) out[key] = compact(nested, depth + 1);",
" return out;",
" }",
" return String(value).slice(0, 240);",
"}",
"const scriptBlock = rec(report.script);",
"const compactReport = {",
" ok: report.ok === true,",
" status: typeof report.status === 'string' ? report.status : null,",
" summary: compact(report.summary),",
"function compact(value, depth = 0) {",
" if (value === null || value === undefined) return value ?? null;",
" if (typeof value === 'string') return value.replace(/\\s+/gu, ' ').trim().slice(0, 120);",
" if (typeof value === 'number' || typeof value === 'boolean') return value;",
" if (depth >= 3) return '[max-depth]';",
" if (Array.isArray(value)) return value.slice(0, 4).map((item) => compact(item, depth + 1));",
" if (typeof value === 'object') {",
" const out = {};",
" for (const [key, nested] of Object.entries(value).slice(0, 8)) out[key] = compact(nested, depth + 1);",
" return out;",
" }",
" return String(value).slice(0, 240);",
"}",
"function compactSummary(value) {",
" const summary = rec(value);",
" return {",
" ok: summary.ok === true,",
" status: typeof summary.status === 'string' ? summary.status : null,",
" degradedReason: typeof summary.degradedReason === 'string' ? summary.degradedReason : null,",
" failureKind: typeof summary.failureKind === 'string' ? summary.failureKind : null,",
" failedCondition: typeof summary.failedCondition === 'string' ? compact(summary.failedCondition) : null,",
" nextAction: typeof summary.nextAction === 'string' ? compact(summary.nextAction) : null,",
" baseUrl: typeof summary.baseUrl === 'string' ? summary.baseUrl : null,",
" finalUrl: typeof summary.finalUrl === 'string' ? summary.finalUrl : null,",
" lastUrl: typeof summary.lastUrl === 'string' ? summary.lastUrl : null,",
" scriptSha256: typeof summary.scriptSha256 === 'string' ? summary.scriptSha256 : null,",
" runDir: typeof summary.runDir === 'string' ? summary.runDir : null,",
" reportPath: typeof summary.reportPath === 'string' ? summary.reportPath : null,",
" reportSha256: typeof summary.reportSha256 === 'string' ? summary.reportSha256 : null,",
" lastScreenshot: compact(summary.lastScreenshot),",
" screenshots: compact(summary.screenshots),",
" apiMatrix: compact(summary.apiMatrix),",
" stepCount: typeof summary.stepCount === 'number' ? summary.stepCount : null,",
" lastStep: compact(summary.lastStep),",
" issueEvidence: compact(summary.issueEvidence),",
" valuesRedacted: true,",
" };",
"}",
"const scriptBlock = rec(report.script);",
"const compactReport = {",
" ok: report.ok === true,",
" status: typeof report.status === 'string' ? report.status : null,",
" summary: compactSummary(report.summary),",
" issueEvidence: compact(report.issueEvidence ?? rec(report.summary).issueEvidence),",
" baseUrl: typeof report.baseUrl === 'string' ? report.baseUrl : null,",
" finalUrl: typeof report.finalUrl === 'string' ? report.finalUrl : null,",
@@ -80,13 +80,17 @@ try {
await runControlCommand({ id: "startup-goto", type: "goto", path: targetPath, createdAt: new Date().toISOString(), source: "startup" }, async () => gotoTarget(targetPath));
observerPage = await context.newPage();
attachPassiveListeners(observerPage, "observer", observerPageId);
await runControlCommand({ id: "startup-observer-goto", type: "observerGoto", path: targetPath, createdAt: new Date().toISOString(), source: "startup" }, async () => {
const result = await syncObserverPageToControlSession("startup");
if (!result?.ok) {
throw Object.assign(new Error("observer startup did not reach the target workbench route: " + (result?.failureKind || result?.reason || "observer-not-ready")), { details: result });
}
return result;
});
await runControlCommand({ id: "startup-observer-goto", type: "observerGoto", path: targetPath, createdAt: new Date().toISOString(), source: "startup" }, async () => {
const result = await syncObserverPageToControlSession("startup");
if (!result?.ok) {
await appendJsonl(files.control, eventRecord("observer-startup-degraded", {
reason: result?.failureKind || result?.reason || "observer-not-ready",
result: sanitize(result),
valuesRedacted: true,
}));
}
return result ?? { ok: false, reason: "observer-not-ready", pageRole: "observer", pageId: observerPageId, valuesRedacted: true };
});
terminalStatus = "running";
await writeManifest({ status: "running", auth: publicAuth(auth) });
await writeHeartbeat({ status: "running" });