fix: render web observe analyze as table

This commit is contained in:
Codex
2026-06-21 15:57:09 +00:00
parent 83fd2ce3b0
commit 9e94909e06
+102 -2
View File
@@ -7264,7 +7264,7 @@ function runNodeWebProbeObserveCollect(options: NodeWebProbeObserveOptions, spec
};
}
function runNodeWebProbeObserveAnalyze(options: NodeWebProbeObserveOptions, spec: HwlabRuntimeLaneSpec): Record<string, unknown> {
function runNodeWebProbeObserveAnalyze(options: NodeWebProbeObserveOptions, spec: HwlabRuntimeLaneSpec): Record<string, unknown> | RenderedCliResult {
const analyzerB64 = Buffer.from(nodeWebObserveAnalyzerSource(), "utf8").toString("base64");
const script = [
"set -eu",
@@ -7276,7 +7276,7 @@ function runNodeWebProbeObserveAnalyze(options: NodeWebProbeObserveOptions, spec
].join("\n");
const result = runTransWorkspaceStdinScript(options.node, spec.workspace, script, options.commandTimeoutSeconds);
const analysis = parseJsonObject(result.stdout);
return {
return withWebObserveAnalyzeRendered({
ok: result.exitCode === 0 && analysis?.ok === true,
status: result.exitCode === 0 && analysis?.ok === true ? "analyzed" : "blocked",
command: webObserveCommandLabel("analyze", options),
@@ -7287,9 +7287,109 @@ function runNodeWebProbeObserveAnalyze(options: NodeWebProbeObserveOptions, spec
analysis,
result: compactCommandResult(result),
valuesRedacted: true,
});
}
function withWebObserveAnalyzeRendered(value: Record<string, unknown>): RenderedCliResult {
return {
ok: value.ok !== false,
command: typeof value.command === "string" ? value.command : "hwlab nodes web-probe observe analyze",
contentType: "text/plain",
renderedText: renderWebObserveAnalyzeTable(value),
};
}
function renderWebObserveAnalyzeTable(value: Record<string, unknown>): string {
const analysis = record(value.analysis);
const counts = record(analysis?.counts);
const sampleMetrics = record(analysis?.sampleMetrics);
const runtimeAlerts = record(analysis?.runtimeAlerts);
const pagePerformance = record(analysis?.pagePerformance);
const promptNetwork = record(analysis?.promptNetwork);
const slowApis = Array.isArray(analysis?.pagePerformanceSlowApi) ? analysis.pagePerformanceSlowApi.map(record).filter((item): item is Record<string, unknown> => item !== null).slice(0, 8) : [];
const findings = Array.isArray(analysis?.findings) ? analysis.findings.map(record).filter((item): item is Record<string, unknown> => item !== null).slice(0, 8) : [];
const domDiagnostics = Array.isArray(analysis?.domDiagnosticGroups) ? analysis.domDiagnosticGroups.map(record).filter((item): item is Record<string, unknown> => item !== null).slice(0, 5) : [];
const lines = [
`hwlab nodes web-probe observe analyze (${webObserveText(value.status)})`,
"",
webObserveTable(["ID", "NODE", "LANE", "SAMPLES", "CONTROL", "NETWORK", "CONSOLE", "ARTIFACTS"], [[
webObserveText(value.id),
webObserveText(value.node),
webObserveText(value.lane),
webObserveText(counts?.samples),
webObserveText(counts?.control),
webObserveText(counts?.network),
webObserveText(counts?.console),
webObserveText(counts?.artifacts),
]]),
"",
"Reports:",
webObserveTable(["KIND", "PATH", "SHA256"], [
["json", webObserveShort(webObserveText(analysis?.reportJsonPath), 96), webObserveShort(webObserveText(analysis?.reportJsonSha256), 24)],
["md", webObserveShort(webObserveText(analysis?.reportMdPath), 96), webObserveShort(webObserveText(analysis?.reportMdSha256), 24)],
]),
"",
"Turn timing:",
webObserveTable(["ROUNDS", "TURNS", "ROWS", "NON_MONO", "ELAPSED_DEC", "RECENT_JUMP", "MAX_RECENT_STEP"], [[
webObserveText(sampleMetrics?.rounds),
webObserveText(sampleMetrics?.turnColumns),
webObserveText(sampleMetrics?.turnTimingRows),
webObserveText(sampleMetrics?.turnTimingNonMonotonicCount),
webObserveText(sampleMetrics?.turnTimingTotalElapsedDecreaseCount),
webObserveText(sampleMetrics?.turnTimingRecentUpdateJumpCount ?? sampleMetrics?.turnTimingRecentUpdateSawtoothJumpCount),
webObserveText(sampleMetrics?.turnTimingRecentUpdateMaxIncreaseSeconds),
]]),
"",
"Runtime alerts:",
webObserveTable(["HTTP_ERR", "REQUEST_FAILED", "DOM_DIAG", "CONSOLE_ALERT", "PROMPT_SEGMENTS", "PROMPT_NETWORK"], [[
webObserveText(runtimeAlerts?.httpErrorCount),
webObserveText(runtimeAlerts?.requestFailedCount),
webObserveText(runtimeAlerts?.domDiagnosticSampleCount),
webObserveText(runtimeAlerts?.consoleAlertCount),
webObserveText(sampleMetrics?.promptSegments),
webObserveText(promptNetwork?.promptSegments),
]]),
"",
"Slow API (>5s):",
webObserveTable(["PATH", "SAMPLES", "P95", "MAX", "OVER5S"], slowApis.length > 0 ? slowApis.map((item) => [
webObserveShort(webObserveText(item.path ?? item.route), 52),
webObserveText(item.sampleCount),
webObserveText(item.p95Ms ?? item.p95),
webObserveText(item.maxMs ?? item.max),
webObserveText(item.overFiveSecondCount),
]) : [["-", "-", "-", "-", "-"]]),
"",
"DOM diagnostics:",
webObserveTable(["COUNT", "FIRST", "LAST", "TEXT"], domDiagnostics.length > 0 ? domDiagnostics.map((item) => [
webObserveText(item.count),
webObserveShort(webObserveText(item.firstAt), 24),
webObserveShort(webObserveText(item.lastAt), 24),
webObserveShort(webObserveText(item.text), 96),
]) : [["-", "-", "-", "-"]]),
"",
"Findings:",
webObserveTable(["KIND", "SEVERITY", "COUNT", "SUMMARY"], findings.length > 0 ? findings.map((item) => [
webObserveShort(webObserveText(item.kind ?? item.code), 32),
webObserveText(item.severity ?? item.level),
webObserveText(item.count ?? item.sampleCount),
webObserveShort(webObserveText(item.summary ?? item.message), 96),
]) : [["-", "-", "-", "-"]]),
];
if (pagePerformance !== null && Object.keys(pagePerformance).length > 0) {
lines.push("", "Page performance:", ` ${webObserveShort(JSON.stringify(pagePerformance), 180)}`);
}
lines.push(
"",
"Next:",
` cat ${webObserveText(analysis?.reportMdPath)}`,
` cat ${webObserveText(analysis?.reportJsonPath)}`,
"",
"Disclosure:",
" default view is a bounded report summary; use report.md/report.json paths for full offline analysis.",
);
return lines.join("\n");
}
function nodeWebObserveResolveStateDirShell(options: Pick<NodeWebProbeObserveOptions, "stateDir" | "jobId" | "node" | "lane">): string {
if (options.stateDir !== null) {
return [