fix(web-probe): recover run reports with compact summaries (#751)
Co-authored-by: Codex <codex@noreply.local>
This commit is contained in:
@@ -7446,7 +7446,7 @@ function runNodeWebProbe(options: NodeWebProbeOptions): Record<string, unknown>
|
||||
: typeof probe?.degradedReason === "string"
|
||||
? probe.degradedReason
|
||||
: null;
|
||||
return {
|
||||
return renderWebProbeRunResult({
|
||||
ok: passed,
|
||||
status: passed ? "pass" : "blocked",
|
||||
command: `hwlab nodes web-probe run --node ${options.node} --lane ${options.lane}`,
|
||||
@@ -7468,7 +7468,7 @@ function runNodeWebProbe(options: NodeWebProbeOptions): Record<string, unknown>
|
||||
probe,
|
||||
result: compactCommandResult(result),
|
||||
valuesRedacted: true,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function nodeWebProbeRunArgs(options: NodeWebProbeRunOptions, command: "run" | "start"): string[] {
|
||||
@@ -7507,7 +7507,7 @@ function runNodeWebProbeAsync(
|
||||
const start = parseJsonObject(startResult.stdout);
|
||||
const jobId = typeof start?.jobId === "string" ? start.jobId : null;
|
||||
if (startResult.exitCode !== 0 || jobId === null) {
|
||||
return {
|
||||
return renderWebProbeRunResult({
|
||||
ok: false,
|
||||
status: "blocked",
|
||||
command: `hwlab nodes web-probe run --node ${options.node} --lane ${options.lane}`,
|
||||
@@ -7523,7 +7523,7 @@ function runNodeWebProbeAsync(
|
||||
start: start ?? null,
|
||||
result: compactCommandResultRedacted(startResult, [material.password ?? ""]),
|
||||
valuesRedacted: true,
|
||||
};
|
||||
});
|
||||
}
|
||||
const poll = pollNodeWebProbeJob(options, spec, jobId);
|
||||
const statusReport = record(record(poll.status).report);
|
||||
@@ -7532,6 +7532,7 @@ function runNodeWebProbeAsync(
|
||||
? { source: "status", report: statusReport, result: null as CommandResult | null, degradedReason: null as string | null, path: null as string | null }
|
||||
: readNodeWebProbeReport(options, spec, reportPath);
|
||||
const report = reportLoad.report ?? {};
|
||||
const reportRecovered = Object.keys(report).length > 0;
|
||||
const probe = compactWebProbeResult(Object.keys(report).length > 0 ? report : null);
|
||||
const passed = probe?.status === "pass";
|
||||
const summary = nullableRecord(probe?.summary);
|
||||
@@ -7540,9 +7541,11 @@ function runNodeWebProbeAsync(
|
||||
: typeof probe?.degradedReason === "string"
|
||||
? probe.degradedReason
|
||||
: poll.status === null
|
||||
? reportLoad.degradedReason ?? "web-probe-async-status-failed"
|
||||
? reportRecovered
|
||||
? reportLoad.degradedReason
|
||||
: reportLoad.degradedReason ?? "web-probe-async-status-failed"
|
||||
: reportLoad.degradedReason;
|
||||
return {
|
||||
return renderWebProbeRunResult({
|
||||
ok: passed,
|
||||
status: passed ? "pass" : "blocked",
|
||||
command: `hwlab nodes web-probe run --node ${options.node} --lane ${options.lane}`,
|
||||
@@ -7581,7 +7584,7 @@ function runNodeWebProbeAsync(
|
||||
degradedReason: reportLoad.degradedReason,
|
||||
},
|
||||
valuesRedacted: true,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function readNodeWebProbeReport(
|
||||
@@ -7591,7 +7594,52 @@ function readNodeWebProbeReport(
|
||||
): { source: string; report: Record<string, unknown> | null; result: CommandResult | null; degradedReason: string | null; path: string | null } {
|
||||
if (!reportPath) return { source: "missing", report: null, result: null, degradedReason: "web-probe-report-path-missing", path: null };
|
||||
if (!isSafeWebProbeReportPath(reportPath)) return { source: "unsafe-path", report: null, result: null, degradedReason: "web-probe-report-path-invalid", path: reportPath };
|
||||
const result = runTransWorkspaceStdinScript(options.node, spec.workspace, `cat ${shellQuote(reportPath)}`, 55);
|
||||
const script = [
|
||||
"set -eu",
|
||||
`test -f ${shellQuote(reportPath)}`,
|
||||
`node - ${shellQuote(reportPath)} <<'NODE'`,
|
||||
"const fs = require('fs');",
|
||||
"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, 600);",
|
||||
" if (typeof value === 'number' || typeof value === 'boolean') return value;",
|
||||
" if (depth >= 6) return '[max-depth]';",
|
||||
" if (Array.isArray(value)) return value.slice(0, 16).map((item) => compact(item, depth + 1));",
|
||||
" if (typeof value === 'object') {",
|
||||
" const out = {};",
|
||||
" for (const [key, nested] of Object.entries(value).slice(0, 32)) out[key] = compact(nested, depth + 1);",
|
||||
" return out;",
|
||||
" }",
|
||||
" return String(value).slice(0, 600);",
|
||||
"}",
|
||||
"const artifacts = rec(report.artifacts);",
|
||||
"const compactReport = {",
|
||||
" ok: report.ok === true,",
|
||||
" status: typeof report.status === 'string' ? report.status : null,",
|
||||
" finalUrl: typeof report.finalUrl === 'string' ? report.finalUrl : null,",
|
||||
" error: typeof report.error === 'string' ? report.error : null,",
|
||||
" degradedReason: typeof report.degradedReason === 'string' ? report.degradedReason : null,",
|
||||
" actions: compact(report.actions),",
|
||||
" session: compact(report.session),",
|
||||
" trace: compact(report.trace),",
|
||||
" promptValidation: compact(report.promptValidation),",
|
||||
" performance: compact(report.performance),",
|
||||
" traceSamples: compact(report.traceSamples),",
|
||||
" dom: compact(report.dom),",
|
||||
" failureDom: compact(report.failureDom),",
|
||||
" artifacts: {",
|
||||
" ...compact(artifacts),",
|
||||
" reportPath: typeof artifacts.reportPath === 'string' ? artifacts.reportPath : reportPath,",
|
||||
" },",
|
||||
" safety: compact(report.safety),",
|
||||
"};",
|
||||
"console.log(JSON.stringify(compactReport));",
|
||||
"NODE",
|
||||
].join("\n");
|
||||
const result = runTransWorkspaceStdinScript(options.node, spec.workspace, script, 55);
|
||||
if (result.exitCode !== 0 || result.timedOut) return { source: "report-file", report: null, result, degradedReason: result.timedOut ? "web-probe-command-timeout" : "web-probe-report-read-failed", path: reportPath };
|
||||
const report = parseJsonObject(result.stdout);
|
||||
return {
|
||||
@@ -9563,6 +9611,64 @@ function withWebObserveRendered(result: Record<string, unknown>, renderedText: s
|
||||
};
|
||||
}
|
||||
|
||||
function renderWebProbeRunResult(result: Record<string, unknown>): Record<string, unknown> {
|
||||
const summary = record(result.summary);
|
||||
const probe = record(result.probe);
|
||||
const trace = record(probe.trace);
|
||||
const session = record(probe.session);
|
||||
const artifacts = record(probe.artifacts);
|
||||
const reportLoad = record(result.reportLoad);
|
||||
const commandTimeout = record(result.commandTimeout);
|
||||
const job = record(result.job);
|
||||
const start = record(result.start);
|
||||
const commandResult = record(result.result ?? result.statusResult);
|
||||
const reportPath = reportLoad.path ?? summary.reportPath ?? artifacts.reportPath ?? start.reportPath ?? "-";
|
||||
const reportSource = reportLoad.source ?? (result.mode === "async" ? "-" : "stdout");
|
||||
const blockedRows = result.ok === true ? [] : [
|
||||
"",
|
||||
webObserveTable(
|
||||
["BLOCKED_FIELD", "VALUE"],
|
||||
[
|
||||
["failureKind", result.failureKind ?? summary.failureKind ?? "-"],
|
||||
["failedCondition", summary.failedCondition ?? result.degradedReason ?? "-"],
|
||||
["nextAction", summary.nextAction ?? "-"],
|
||||
["exitCode", commandResult.exitCode ?? "-"],
|
||||
["timedOut", commandResult.timedOut ?? commandTimeout.timedOut ?? "-"],
|
||||
],
|
||||
),
|
||||
];
|
||||
const renderedText = [
|
||||
webObserveTable(
|
||||
["WEB_PROBE_RUN", "NODE", "LANE", "STATUS", "OK", "DEGRADED", "URL"],
|
||||
[[result.command ?? "web-probe run", result.node, result.lane, result.status, result.ok, result.degradedReason ?? "-", result.url]],
|
||||
),
|
||||
"",
|
||||
webObserveTable(
|
||||
["FIELD", "VALUE"],
|
||||
[
|
||||
["mode", result.mode ?? (result.reportLoad ? "async" : "direct")],
|
||||
["traceId", summary.traceId ?? trace.traceId ?? "-"],
|
||||
["sessionId", summary.sessionId ?? session.sessionId ?? "-"],
|
||||
["conversationId", summary.conversationId ?? session.conversationId ?? "-"],
|
||||
["agentStatus", summary.agentStatus ?? trace.finalAgentStatus ?? "-"],
|
||||
["traceStatus", summary.traceStatus ?? trace.finalTraceStatus ?? "-"],
|
||||
["messageCount", summary.messageCount ?? session.messageCount ?? "-"],
|
||||
["reportSource", reportSource],
|
||||
["reportPath", reportPath],
|
||||
["reportSha256", summary.reportSha256 ?? artifacts.reportSha256 ?? "-"],
|
||||
["timeout", `${commandTimeout.seconds ?? "-"}s timedOut=${commandTimeout.timedOut ?? "-"}`],
|
||||
["job", job.jobId ?? "-"],
|
||||
],
|
||||
),
|
||||
...blockedRows,
|
||||
"",
|
||||
"NEXT",
|
||||
` report: ${reportPath}`,
|
||||
` rerun: ${result.command ?? `hwlab nodes web-probe run --node ${result.node ?? "-"} --lane ${result.lane ?? "-"}`}`,
|
||||
].join("\n");
|
||||
return withWebObserveRendered(result, renderedText);
|
||||
}
|
||||
|
||||
function renderWebObserveStartResult(result: Record<string, unknown>): Record<string, unknown> {
|
||||
const observer = record(result.observer);
|
||||
const heartbeat = record(observer.heartbeat);
|
||||
|
||||
Reference in New Issue
Block a user