436 lines
18 KiB
TypeScript
436 lines
18 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { mkdir, mkdtemp, writeFile } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { test } from "bun:test";
|
|
|
|
import { hwlabRuntimeLaneSpecForNode } from "../hwlab-node-lanes";
|
|
import { nodeWebObserveStatusNodeScript, nodeWebObserveWaitCommandShell, nodeWebProbeScriptRemoteShell } from "./web-observe-scripts";
|
|
|
|
test("web-probe script exports generated runner paths into the guarded child shell", () => {
|
|
const script = nodeWebProbeScriptRemoteShell({
|
|
action: "script",
|
|
node: "NC01",
|
|
lane: "v03",
|
|
url: "https://lab-dev.hwpod.com",
|
|
timeoutMs: 30_000,
|
|
viewport: "1920x1080",
|
|
browserProxyMode: "auto",
|
|
commandTimeoutSeconds: 60,
|
|
scriptText: "export default async () => ({ ok: true });",
|
|
scriptSource: { kind: "generated", path: null, byteCount: 1, sha256: "fixture" },
|
|
originName: "public",
|
|
originMode: "public",
|
|
originConfigPath: "fixture",
|
|
browserProxyModeSource: "yaml-origin",
|
|
}, hwlabRuntimeLaneSpecForNode("v03", "NC01"), {
|
|
username: "fixture-user",
|
|
password: "fixture-password",
|
|
}, {
|
|
loginPath: "/auth/login",
|
|
usernameField: "username",
|
|
passwordField: "password",
|
|
cookieNames: ["hwlab_session"],
|
|
}, {
|
|
envAssignments: [],
|
|
summary: {},
|
|
}, undefined);
|
|
|
|
assert.match(script, /rm -f "[$]user_script_b64" "[$]runner_b64"\nexport run_dir user_script runner\n/u);
|
|
assert.match(script, /UNIDESK_WEB_PROBE_RUN_DIR="[$]run_dir"[\s\S]+node "[$]runner"/u);
|
|
});
|
|
|
|
async function runStatusScript(stateDir: string, commandId: string): Promise<Record<string, any>> {
|
|
const child = Bun.spawn(["bash", "-lc", nodeWebObserveStatusNodeScript(1, "NC01", "v03", commandId)], {
|
|
env: { ...process.env, state_dir: stateDir },
|
|
stdout: "pipe",
|
|
stderr: "pipe",
|
|
});
|
|
const [stdout, stderr, exitCode] = await Promise.all([
|
|
new Response(child.stdout).text(),
|
|
new Response(child.stderr).text(),
|
|
child.exited,
|
|
]);
|
|
assert.equal(exitCode, 0, stderr);
|
|
return JSON.parse(stdout) as Record<string, any>;
|
|
}
|
|
|
|
test("observe status returns one exact completed command without prompt payloads", async () => {
|
|
const stateDir = await mkdtemp(join(tmpdir(), "unidesk-web-observe-exact-status-"));
|
|
const commandId = "cmd-fixture";
|
|
await mkdir(join(stateDir, "commands", "done"), { recursive: true });
|
|
await mkdir(join(stateDir, "commands", "processing"), { recursive: true });
|
|
await writeFile(join(stateDir, "commands", "done", `${commandId}.json`), JSON.stringify({
|
|
ok: true,
|
|
commandId,
|
|
type: "validateRealtimeFanout",
|
|
completedAt: "2026-07-10T12:00:00.000Z",
|
|
result: {
|
|
ok: true,
|
|
status: "passed",
|
|
profile: "pure-kafka-live",
|
|
sessionId: "ses_fixture",
|
|
traceIds: ["trc_first", "trc_second"],
|
|
runIds: ["run_fixture"],
|
|
commandIds: ["cmd_runner_first", "cmd_runner_second"],
|
|
reportPath: "/tmp/report.json",
|
|
reportSha256: "sha256:fixture",
|
|
prompt: "must-not-leak",
|
|
},
|
|
}) + "\n");
|
|
await writeFile(join(stateDir, "commands", "processing", `${commandId}.json`), JSON.stringify({
|
|
ok: null,
|
|
commandId,
|
|
type: "validateRealtimeFanout",
|
|
}) + "\n");
|
|
|
|
const status = await runStatusScript(stateDir, commandId);
|
|
assert.equal(status.exactCommand.phase, "done");
|
|
assert.equal(status.exactCommand.type, "validateRealtimeFanout");
|
|
assert.equal(status.exactCommand.result.reportSha256, "sha256:fixture");
|
|
assert.equal(status.exactCommand.result.prompt, undefined);
|
|
assert.equal(status.exactCommand.valuesRedacted, true);
|
|
});
|
|
|
|
test("observe status summarizes performance capture artifact without embedding CPU profile", async () => {
|
|
const stateDir = await mkdtemp(join(tmpdir(), "unidesk-web-observe-performance-status-"));
|
|
const commandId = "cmd-performance";
|
|
await mkdir(join(stateDir, "commands", "done"), { recursive: true });
|
|
await writeFile(join(stateDir, "commands", "done", `${commandId}.json`), JSON.stringify({
|
|
ok: true,
|
|
commandId,
|
|
type: "performanceCapture",
|
|
completedAt: "2026-07-13T12:00:00.000Z",
|
|
result: {
|
|
ok: true,
|
|
captureId: "cpu-fixture",
|
|
durationMs: 1200,
|
|
profile: { nodes: [{ id: 1, callFrame: { functionName: "large-profile-payload" } }] },
|
|
artifact: {
|
|
path: ".state/web-observe/performance/cpu-fixture/profile.cpuprofile",
|
|
sha256: "sha256:profile",
|
|
summaryPath: ".state/web-observe/performance/cpu-fixture/summary.json",
|
|
summarySha256: "sha256:report",
|
|
},
|
|
},
|
|
}));
|
|
|
|
const status = await runStatusScript(stateDir, commandId);
|
|
assert.equal(status.exactCommand.result.captureId, "cpu-fixture");
|
|
assert.equal(status.exactCommand.result.profileSha256, "sha256:profile");
|
|
assert.equal(status.exactCommand.result.reportSha256, "sha256:report");
|
|
assert.equal(JSON.stringify(status).includes("large-profile-payload"), false);
|
|
});
|
|
|
|
test("observe command wait emits bounded performance capture summary", async () => {
|
|
const stateDir = await mkdtemp(join(tmpdir(), "unidesk-web-observe-performance-wait-"));
|
|
const commandId = "cmd-performance";
|
|
await mkdir(join(stateDir, "commands", "done"), { recursive: true });
|
|
await writeFile(join(stateDir, "commands", "done", `${commandId}.json`), JSON.stringify({
|
|
ok: true,
|
|
commandId,
|
|
type: "performanceCapture",
|
|
completedAt: "2026-07-13T12:00:00.000Z",
|
|
result: {
|
|
ok: true,
|
|
captureId: "cpu-fixture",
|
|
durationMs: 1200,
|
|
profile: { nodes: [{ id: 1, callFrame: { functionName: "large-profile-payload" } }] },
|
|
artifact: {
|
|
path: ".state/web-observe/performance/cpu-fixture/profile.cpuprofile",
|
|
sha256: "sha256:profile",
|
|
summaryPath: ".state/web-observe/performance/cpu-fixture/summary.json",
|
|
summarySha256: "sha256:report",
|
|
},
|
|
},
|
|
}));
|
|
const child = Bun.spawn(["bash", "-lc", nodeWebObserveWaitCommandShell(commandId, 1000)], {
|
|
env: { ...process.env, state_dir: stateDir },
|
|
stdout: "pipe",
|
|
stderr: "pipe",
|
|
});
|
|
const [stdout, stderr, exitCode] = await Promise.all([
|
|
new Response(child.stdout).text(),
|
|
new Response(child.stderr).text(),
|
|
child.exited,
|
|
]);
|
|
assert.equal(exitCode, 0, stderr);
|
|
const summary = JSON.parse(stdout);
|
|
assert.equal(summary.status, "done");
|
|
assert.equal(summary.result.profileSha256, "sha256:profile");
|
|
assert.equal(summary.result.reportSha256, "sha256:report");
|
|
assert.equal(stdout.includes("large-profile-payload"), false);
|
|
assert.ok(Buffer.byteLength(stdout) < 2048);
|
|
});
|
|
|
|
test("observe status preserves bounded existing-session refresh evidence", async () => {
|
|
const stateDir = await mkdtemp(join(tmpdir(), "unidesk-web-observe-existing-refresh-status-"));
|
|
const commandId = "cmd-existing-refresh";
|
|
await mkdir(join(stateDir, "commands", "done"), { recursive: true });
|
|
await writeFile(join(stateDir, "commands", "done", `${commandId}.json`), JSON.stringify({
|
|
ok: true,
|
|
commandId,
|
|
type: "validateExistingSessionRefresh",
|
|
completedAt: "2026-07-11T12:00:00.000Z",
|
|
result: {
|
|
ok: true,
|
|
status: "passed",
|
|
profile: "pure-kafka-live",
|
|
sessionId: "ses_existing",
|
|
traceIds: ["trc_existing"],
|
|
phase: "live",
|
|
code: "refresh_live_handoff_validated",
|
|
before: { messageCount: 2, identities: ["must-not-project"], missingIdentityRows: [], duplicateIdentities: [], traceIds: ["trc_existing"] },
|
|
after: { messageCount: 2, identities: ["must-not-project"], missingIdentityRows: [], duplicateIdentities: [], traceIds: ["trc_existing"] },
|
|
refreshReplay: {
|
|
phase: "live",
|
|
topic: "hwlab.event.v1",
|
|
topicPartitions: [0],
|
|
barrier: [{ partition: 0, endOffset: "18" }],
|
|
counts: { matched: 8, replayed: 8, buffered: 1, bufferedDelivered: 1, liveDelivered: 0, deduplicated: 0 },
|
|
},
|
|
productSse: { requestCount: 1, browserSourceCount: 1, openCount: 1, connectedEventCount: 1, businessEventCount: 9, typedFailureCount: 0, livePhase: true },
|
|
forbiddenRequestCount: 0,
|
|
reportPath: "/tmp/existing-refresh-report.json",
|
|
reportSha256: "sha256:existing-refresh-report",
|
|
screenshot: { path: "/tmp/existing-refresh.png", sha256: "sha256:existing-refresh-image" },
|
|
},
|
|
}) + "\n");
|
|
|
|
const status = await runStatusScript(stateDir, commandId);
|
|
const result = status.exactCommand.result;
|
|
assert.equal(result.phase, "live");
|
|
assert.equal(result.code, "refresh_live_handoff_validated");
|
|
assert.equal(result.before.messageCount, 2);
|
|
assert.equal(result.before.identities, undefined);
|
|
assert.deepEqual(result.refreshReplay.barrier, [{ partition: 0, endOffset: "18" }]);
|
|
assert.equal(result.refreshReplay.counts.replayed, 8);
|
|
assert.equal(result.productSse.typedFailureCount, 0);
|
|
assert.equal(result.reportSha256, "sha256:existing-refresh-report");
|
|
assert.equal(result.screenshot.sha256, "sha256:existing-refresh-image");
|
|
});
|
|
|
|
test("observe status preserves typed existing-session refresh stream failures", async () => {
|
|
const stateDir = await mkdtemp(join(tmpdir(), "unidesk-web-observe-existing-refresh-failure-"));
|
|
const commandId = "cmd-existing-refresh-failed";
|
|
await mkdir(join(stateDir, "commands", "failed"), { recursive: true });
|
|
await writeFile(join(stateDir, "commands", "failed", `${commandId}.json`), JSON.stringify({
|
|
ok: false,
|
|
commandId,
|
|
type: "validateExistingSessionRefresh",
|
|
failedAt: "2026-07-11T12:00:00.000Z",
|
|
error: {
|
|
message: "Kafka retention barrier gap",
|
|
details: {
|
|
sessionId: "ses_existing",
|
|
traceIds: ["trc_existing"],
|
|
phase: "retention-barrier",
|
|
code: "retention_barrier_failed",
|
|
failure: {
|
|
phase: "retention-barrier",
|
|
code: "retention_barrier_failed",
|
|
streamPhase: "flushing",
|
|
streamCode: "workbench_kafka_refresh_barrier_gap",
|
|
streamFailure: { phase: "flushing", code: "workbench_kafka_refresh_barrier_gap", message: "Kafka retention barrier gap" },
|
|
},
|
|
reportSha256: "sha256:failed-existing-refresh-report",
|
|
},
|
|
},
|
|
}) + "\n");
|
|
|
|
const status = await runStatusScript(stateDir, commandId);
|
|
const details = status.exactCommand.error.details;
|
|
assert.equal(details.phase, "retention-barrier");
|
|
assert.equal(details.code, "retention_barrier_failed");
|
|
assert.equal(details.failure.streamPhase, "flushing");
|
|
assert.equal(details.failure.streamCode, "workbench_kafka_refresh_barrier_gap");
|
|
assert.equal(details.failure.message, "Kafka retention barrier gap");
|
|
assert.deepEqual(details.traceIds, ["trc_existing"]);
|
|
});
|
|
|
|
test("observe status keeps exact command not-found structured", async () => {
|
|
const stateDir = await mkdtemp(join(tmpdir(), "unidesk-web-observe-exact-missing-"));
|
|
const status = await runStatusScript(stateDir, "cmd-missing");
|
|
assert.deepEqual(status.exactCommand, {
|
|
commandId: "cmd-missing",
|
|
phase: "not-found",
|
|
ok: false,
|
|
valuesRedacted: true,
|
|
});
|
|
});
|
|
|
|
test("observe status preserves bounded Workbench Kafka debug replay evidence", async () => {
|
|
const stateDir = await mkdtemp(join(tmpdir(), "unidesk-web-observe-debug-replay-status-"));
|
|
const commandId = "cmd-debug-replay";
|
|
await mkdir(join(stateDir, "commands", "done"), { recursive: true });
|
|
await writeFile(join(stateDir, "commands", "done", `${commandId}.json`), JSON.stringify({
|
|
ok: true,
|
|
commandId,
|
|
type: "validateWorkbenchKafkaDebugReplay",
|
|
completedAt: "2026-07-10T12:00:00.000Z",
|
|
result: {
|
|
ok: true,
|
|
status: "passed",
|
|
sessionId: "ses_fixture",
|
|
traceId: "trc_fixture",
|
|
topic: "hwlab.event.debug.v1",
|
|
groupId: "hwlab-v03-workbench-isolated-debug-123-fixture",
|
|
groupPrefix: "hwlab-v03-workbench-isolated-debug",
|
|
phase: "terminal",
|
|
code: "terminal_complete",
|
|
receivedCount: 35,
|
|
appliedCount: 35,
|
|
layerCounts: {
|
|
server: { scanned: 35, matched: 35, delivered: 35 },
|
|
client: { received: 35, decoded: 35, applied: 35 },
|
|
},
|
|
layerDom: {
|
|
matchCount: 1,
|
|
visibleCount: 1,
|
|
connectedCount: 1,
|
|
textPresent: true,
|
|
textBytes: 128,
|
|
textHash: "sha256:layer",
|
|
textPreview: "server scanned=35 client received=35",
|
|
},
|
|
layerDomStabilization: {
|
|
stable: true,
|
|
timedOut: false,
|
|
sampleCount: 4,
|
|
elapsedMs: 400,
|
|
stableQuietMs: 250,
|
|
},
|
|
traceTimeline: {
|
|
contract: "trace-sequence-authority-v1",
|
|
sourceAuthorityRowCount: 35,
|
|
readableSourceRowCount: 35,
|
|
},
|
|
rawHwlabEventWindow: {
|
|
available: true,
|
|
samePage: true,
|
|
unfilteredContractPresent: true,
|
|
productEventSourceRequestCount: 0,
|
|
counts: { received: 35, retained: 30, rejected: 0, evicted: 5, bytes: 8192 },
|
|
},
|
|
terminalStatus: "completed",
|
|
reportPath: "/tmp/report.json",
|
|
reportSha256: "sha256:report",
|
|
screenshot: { path: "/tmp/replay.png", sha256: "sha256:image" },
|
|
},
|
|
}) + "\n");
|
|
|
|
const status = await runStatusScript(stateDir, commandId);
|
|
assert.equal(status.exactCommand.type, "validateWorkbenchKafkaDebugReplay");
|
|
assert.equal(status.exactCommand.result.traceId, "trc_fixture");
|
|
assert.equal(status.exactCommand.result.topic, "hwlab.event.debug.v1");
|
|
assert.equal(status.exactCommand.result.groupPrefix, "hwlab-v03-workbench-isolated-debug");
|
|
assert.equal(status.exactCommand.result.receivedCount, 35);
|
|
assert.equal(status.exactCommand.result.appliedCount, 35);
|
|
assert.equal(status.exactCommand.result.phase, "terminal");
|
|
assert.equal(status.exactCommand.result.code, "terminal_complete");
|
|
assert.equal(status.exactCommand.result.layerCounts.server.scanned, 35);
|
|
assert.equal(status.exactCommand.result.layerDom.visibleCount, 1);
|
|
assert.equal(status.exactCommand.result.layerDom.textHash, "sha256:layer");
|
|
assert.equal(status.exactCommand.result.layerDomStabilization.stable, true);
|
|
assert.equal(status.exactCommand.result.traceTimeline.sourceAuthorityRowCount, 35);
|
|
assert.equal(status.exactCommand.result.rawHwlabEventWindow.counts.retained, 30);
|
|
assert.equal(status.exactCommand.result.screenshot.sha256, "sha256:image");
|
|
});
|
|
|
|
test("observe status preserves failed replay layer DOM and screenshot diagnostics", async () => {
|
|
const stateDir = await mkdtemp(join(tmpdir(), "unidesk-web-observe-debug-replay-failed-status-"));
|
|
const commandId = "cmd-debug-replay-failed";
|
|
await mkdir(join(stateDir, "commands", "failed"), { recursive: true });
|
|
await writeFile(join(stateDir, "commands", "failed", `${commandId}.json`), JSON.stringify({
|
|
ok: false,
|
|
commandId,
|
|
type: "validateWorkbenchKafkaDebugReplay",
|
|
failedAt: "2026-07-10T12:00:00.000Z",
|
|
error: {
|
|
name: "Error",
|
|
message: "layer DOM did not stabilize",
|
|
details: {
|
|
traceId: "trc_fixture",
|
|
layerCounts: null,
|
|
layerDom: { matchCount: 1, visibleCount: 1, connectedCount: 1, textPresent: true, textBytes: 128, textHash: "sha256:failed-layer" },
|
|
layerDomStabilization: { stable: false, timedOut: true, sampleCount: 30, elapsedMs: 3000, stableQuietMs: 500 },
|
|
reportPath: "/tmp/failed-report.json",
|
|
reportSha256: "sha256:failed-report",
|
|
screenshot: { path: "/tmp/failed.png", sha256: "sha256:failed-image" },
|
|
},
|
|
},
|
|
}) + "\n");
|
|
|
|
const status = await runStatusScript(stateDir, commandId);
|
|
assert.equal(status.exactCommand.phase, "failed");
|
|
assert.equal(status.exactCommand.error.details.layerDom.visibleCount, 1);
|
|
assert.equal(status.exactCommand.error.details.layerDom.textHash, "sha256:failed-layer");
|
|
assert.equal(status.exactCommand.error.details.layerDomStabilization.timedOut, true);
|
|
assert.equal(status.exactCommand.error.details.reportSha256, "sha256:failed-report");
|
|
assert.equal(status.exactCommand.error.details.screenshot.sha256, "sha256:failed-image");
|
|
});
|
|
|
|
test("observe status preserves bounded scoped Workbench product Trace evidence", async () => {
|
|
const stateDir = await mkdtemp(join(tmpdir(), "unidesk-web-observe-trace-readability-status-"));
|
|
const commandId = "cmd-trace-readable";
|
|
await mkdir(join(stateDir, "commands", "done"), { recursive: true });
|
|
await writeFile(join(stateDir, "commands", "done", `${commandId}.json`), JSON.stringify({
|
|
ok: true,
|
|
commandId,
|
|
type: "validateWorkbenchTraceReadability",
|
|
completedAt: "2026-07-10T12:00:00.000Z",
|
|
result: {
|
|
ok: true,
|
|
status: "passed",
|
|
sessionId: "ses_fixture",
|
|
traceId: "trc_fixture",
|
|
startedDuringRunning: true,
|
|
forcedExpansion: false,
|
|
scope: {
|
|
selector: "#conversation-list .message-card[data-role=agent][data-trace-id]",
|
|
conversationCount: 1,
|
|
productCardCount: 2,
|
|
debugPanelCountInsideConversation: 0,
|
|
isolatedDebugExcluded: true,
|
|
},
|
|
disclosure: {
|
|
openBefore: true,
|
|
openAfterExpansion: true,
|
|
openAfterTerminal: true,
|
|
autoReadable: true,
|
|
},
|
|
running: {
|
|
observed: true,
|
|
snapshot: { status: "running", traceId: "trc_fixture", rowCount: 2, sourceAuthorityRowCount: 2, projectedAuthorityRowCount: 0, rowSetHash: "sha256:running" },
|
|
},
|
|
terminal: {
|
|
observed: true,
|
|
stable: true,
|
|
snapshot: { status: "completed", traceId: "trc_fixture", disclosure: { open: true }, rowCount: 3, sourceAuthorityRowCount: 3, readableSourceRowCount: 3, projectedAuthorityRowCount: 0, rowSetHash: "sha256:terminal" },
|
|
},
|
|
runningRetention: {
|
|
mode: "identity-overlap",
|
|
passed: true,
|
|
retainedRowCount: 2,
|
|
},
|
|
retainedRunningRowCount: 2,
|
|
reportPath: "/tmp/trace-report.json",
|
|
reportSha256: "sha256:trace-report",
|
|
screenshot: { path: "/tmp/trace.png", sha256: "sha256:trace-image" },
|
|
},
|
|
}) + "\n");
|
|
|
|
const status = await runStatusScript(stateDir, commandId);
|
|
assert.equal(status.exactCommand.type, "validateWorkbenchTraceReadability");
|
|
assert.equal(status.exactCommand.result.scope.debugPanelCountInsideConversation, 0);
|
|
assert.equal(status.exactCommand.result.disclosure.openBefore, true);
|
|
assert.equal(status.exactCommand.result.running.snapshot.sourceAuthorityRowCount, 2);
|
|
assert.equal(status.exactCommand.result.terminal.snapshot.status, "completed");
|
|
assert.equal(status.exactCommand.result.terminal.snapshot.projectedAuthorityRowCount, 0);
|
|
assert.equal(status.exactCommand.result.runningRetention.mode, "identity-overlap");
|
|
assert.equal(status.exactCommand.result.runningRetention.passed, true);
|
|
assert.equal(status.exactCommand.result.retainedRunningRowCount, 2);
|
|
assert.equal(status.exactCommand.result.reportSha256, "sha256:trace-report");
|
|
assert.equal(status.exactCommand.result.screenshot.sha256, "sha256:trace-image");
|
|
});
|