fix: polish hwpod groups and performance probes (#1494)

This commit is contained in:
Lyon
2026-06-18 17:19:03 +08:00
committed by GitHub
parent 1cdf262a80
commit 60d1de1dd7
5 changed files with 361 additions and 16 deletions
@@ -142,13 +142,87 @@ async function handleRequest(request: IncomingMessage, response: ServerResponse)
if (path === "/v1/provider-profiles") return json(response, 200, { profiles: [{ profile: "codex-api", name: "Codex API", configured: true }, { profile: "deepseek", name: "DeepSeek", configured: true }] });
if (path === "/health/live" || path === "/health" || path === "/v1") return json(response, 200, { status: "ok", serviceId: "workbench-e2e", codeAgent: { ready: true, status: "ready" } });
if (path === "/v1/live-builds") return json(response, 200, { status: "ok", builds: [] });
if (path === "/v1/hwpod/specs") return json(response, 200, { specs: [] });
if (path === "/v1/hwpod-node-ops") return json(response, 200, { ok: true, status: "ready", events: [], groups: [] });
if (path === "/v1/hwpod/specs") return json(response, 200, hwpodSpecsPayload());
if (path === "/v1/hwpod-node-ops") return json(response, 200, hwpodNodeOpsPayload());
if (path === "/v1/web-performance/summary") return json(response, 200, webPerformanceSummaryPayload());
if (path.startsWith("/v1/") || path.startsWith("/auth/") || path.startsWith("/health")) return json(response, 500, { ok: false, status: 500, error: { code: "unmocked_request", path } });
return staticFile(response, path);
}
function hwpodSpecsPayload(): JsonRecord {
return {
ok: true,
status: "completed",
count: 1,
availableCount: 0,
nodeOpsContractVersion: "hwpod-node-ops-v1",
specs: [
{
name: "d601-f103-v2",
hwpodId: "d601-f103-v2",
nodeId: "node-d601-f103-v2",
workspacePath: "F:\\Work\\D601-HWLAB",
source: { caseId: "d601-f103-v2-compile" },
availability: {
ok: false,
status: "blocked",
checkedAt: "2026-06-18T04:30:00.000Z",
results: [
{ opId: "op_01_workspace_ls", op: "workspace.ls", ok: false, status: "blocked", blocker: { code: "hwpod_node_unavailable", layer: "hwpod-node", retryable: true, summary: "no outbound WebSocket hwpod-node is connected" } }
]
}
}
]
};
}
function hwpodNodeOpsPayload(): JsonRecord {
return {
ok: true,
status: "ready",
contractVersion: "hwpod-node-ops-v1",
route: "/v1/hwpod-node-ops",
supportedOps: ["node.health", "workspace.ls", "debug.build", "debug.flash"],
websocket: { connectedCount: 0, pendingCount: 1, nodes: [] },
events: [
{ ts: "2026-06-18T04:30:00.000Z", status: "blocked", blocker: { code: "hwpod_node_unavailable", summary: "no outbound WebSocket hwpod-node is connected" } }
]
};
}
function webPerformanceSummaryPayload(): JsonRecord {
const rows = [
performanceRow({ kind: "workbench-journey", metric: "session-switch-full-load", route: "/workbench/sessions/:sessionId", count: 21, p50: 0.18, p75: 0.31, p95: 1.12, tone: "warn", backend: "agentrun", transport: "sse", targetState: "completed" }),
performanceRow({ kind: "workbench-event-phase", metric: "trace-event-projected", route: "/workbench", count: 28, p50: 0.08, p75: 0.14, p95: 0.42, tone: "ok", eventType: "tool_result", phase: "render", source: "rum" }),
performanceRow({ kind: "workbench-backend-event", metric: "backend-event-visible", route: "/v1/workbench/events", count: 15, p50: 0.2, p75: 0.34, p95: 1.38, tone: "warn", eventType: "agentrun.stdout", backend: "agentrun", cache: "miss" }),
performanceRow({ kind: "web-vital", metric: "LCP", route: "/performance", count: 9, p50: 1.2, p75: 1.8, p95: 2.9, tone: "ok" }),
performanceRow({ kind: "api", metric: "fetchJson", route: "/v1/web-performance/summary", method: "GET", statusClass: "2xx", outcome: "ok", count: 17, p50: 0.09, p75: 0.15, p95: 0.33, tone: "ok" }),
performanceRow({ kind: "long-task", metric: "longtask", route: "/workbench", count: 3, p50: 0.08, p75: 0.11, p95: 0.2, tone: "warn", problem: "main-thread busy" })
];
return {
ok: true,
status: "ready",
source: "fake-server",
observedAt: "2026-06-18T04:30:00.000Z",
namespace: "hwlab-v03",
gitopsTarget: "D601/v03",
summary: { status: "ready", sampleCount: 93, sampleSeries: 12, problemCount: 2, lowSampleThreshold: 5, workbenchJourneySeries: 1, workbenchEventPhaseSeries: 1, workbenchBackendEventVisibleSeries: 1 },
rows,
problems: rows.filter((row) => row.tone === "warn"),
webVitals: rows.filter((row) => row.kind === "web-vital"),
apiRoutes: rows.filter((row) => row.kind === "api"),
longTasks: rows.filter((row) => row.kind === "long-task"),
workbenchJourneys: rows.filter((row) => row.kind === "workbench-journey"),
workbenchEventPhases: rows.filter((row) => row.kind === "workbench-event-phase"),
workbenchBackendEvents: rows.filter((row) => row.kind === "workbench-backend-event")
};
}
function performanceRow(row: JsonRecord): JsonRecord {
return { method: "GET", statusClass: "2xx", outcome: "ok", unit: "seconds", sampleState: "ok", ...row };
}
function createScenarioState(scenarioId: string): ScenarioState {
const base = structuredClone(capture.scenario);
const id = scenarioId || "baseline";