From be9f8c7c1c80e79791512f2bd1f118e8a266a193 Mon Sep 17 00:00:00 2001 From: Codex Date: Sat, 27 Jun 2026 03:25:52 +0000 Subject: [PATCH] fix: treat quick verify timing as non-blocking --- .../src/hwlab-node-web-observe-analyzer-source.ts | 14 +++++++++++++- scripts/src/hwlab-node-web-sentinel-cicd.ts | 6 +++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/scripts/src/hwlab-node-web-observe-analyzer-source.ts b/scripts/src/hwlab-node-web-observe-analyzer-source.ts index 805018fe..7199a8c0 100644 --- a/scripts/src/hwlab-node-web-observe-analyzer-source.ts +++ b/scripts/src/hwlab-node-web-observe-analyzer-source.ts @@ -2046,6 +2046,18 @@ function compactApiDomLagForOutput(report) { }; } +function promptCommandHasAuthoritativeSubmitSideEffect(control, promptRound) { + const commandId = stringOrNull(promptRound?.promptCommandId); + if (!commandId) return false; + const row = (control || []).find((item) => item?.type === "sendPrompt" && item?.phase === "completed" && item?.commandId === commandId); + const detail = objectValue(row?.detail); + const chatSubmit = objectValue(detail.chatSubmit); + const sideEffect = objectValue(chatSubmit.sideEffect); + return chatSubmit.sideEffectObserved === true + || sideEffect.submitted === true + || Number(sideEffect.messageCountDelta ?? 0) > 0; +} + function buildFindings(samples, control, network, errors, sampleMetrics, promptNetwork, runtimeAlerts, pagePerformance, pageProvenance, commandFailures = [], manifest = {}, apiDomLag = null) { const findings = []; const effectiveApiDomLag = apiDomLag || buildApiDomLagReport(samples, network); @@ -2152,7 +2164,7 @@ function buildFindings(samples, control, network, errors, sampleMetrics, promptN const traceTerminal = samples.some((item) => Array.isArray(item.traceRows) && item.traceRows.some((row) => isTerminalTraceText((row.status || "") + " " + (row.textPreview || "")))); const traceSeen = samples.some((item) => Array.isArray(item.traceRows) && item.traceRows.length > 0); if (traceSeen && !traceTerminal) findings.push({ id: "trace-without-terminal", severity: "amber", summary: "trace rows were visible but no terminal status was sampled", firstTraceSample: ref(samples.find((item) => Array.isArray(item.traceRows) && item.traceRows.length > 0)) }); - const promptFailures = Array.isArray(promptNetwork?.rounds) ? promptNetwork.rounds.filter((item) => item.chatPostOk === false) : []; + const promptFailures = Array.isArray(promptNetwork?.rounds) ? promptNetwork.rounds.filter((item) => item.chatPostOk === false && !promptCommandHasAuthoritativeSubmitSideEffect(control, item)) : []; if (promptFailures.length > 0) findings.push({ id: "prompt-chat-submit-failed", severity: "red", summary: "sendPrompt command had no successful /v1/agent/chat or /v1/agent/chat/steer POST response in the sampling window", count: promptFailures.length, rounds: promptFailures.slice(0, 10) }); const promptSteerRounds = Array.isArray(promptNetwork?.rounds) ? promptNetwork.rounds.filter((item) => item.steerUsed === true) : []; if (promptSteerRounds.length > 0) findings.push({ id: "prompt-routed-to-steer", severity: "amber", summary: "sendPrompt was submitted through /v1/agent/chat/steer; verify the previous turn was truly in-flight and not an unsealed terminal failure", count: promptSteerRounds.length, rounds: promptSteerRounds.slice(0, 10) }); diff --git a/scripts/src/hwlab-node-web-sentinel-cicd.ts b/scripts/src/hwlab-node-web-sentinel-cicd.ts index 7d036e9b..877593c4 100644 --- a/scripts/src/hwlab-node-web-sentinel-cicd.ts +++ b/scripts/src/hwlab-node-web-sentinel-cicd.ts @@ -3520,6 +3520,10 @@ function waitForQuickVerifyPromptTurn(state: SentinelCicdState, observerId: stri }; } if (payload.ok === true) return { ok: true, ...terminalPayload }; + if (isQuickVerifyTurnSuccessful(status)) { + if (payload?.finalResponseEmpty !== true) return { ok: true, ...terminalPayload }; + continue; + } if (isQuickVerifyTurnTerminal(status)) { return { ok: false, @@ -3644,7 +3648,7 @@ function quickVerifyPromptWaitScript(stateDir: string, promptIndex: number, time " while (Date.now() - startedAt <= timeoutMs) {", " const row = rowFor();", " observations.push(row);", - " if (successful(row.status) && row.composerReadyForTurn === true) { console.log(JSON.stringify({ ok: true, ...row, observations: observations.slice(-6), elapsedMs: Date.now() - startedAt, valuesRedacted: true })); return; }", + " if (successful(row.status) && row.finalResponseEmpty !== true) { console.log(JSON.stringify({ ok: true, ...row, observations: observations.slice(-6), elapsedMs: Date.now() - startedAt, valuesRedacted: true })); return; }", " if (!successful(row.status) && terminal(row.status)) { console.log(JSON.stringify({ ok: false, failure: 'observe-turn-terminal-non-success', ...row, observations: observations.slice(-6), elapsedMs: Date.now() - startedAt, valuesRedacted: true })); return; }", " await sleep(Math.min(pollMs, Math.max(0, timeoutMs - (Date.now() - startedAt))));", " }",