From 3eb06e305e69ba0cfd47c7f1f949d0832b3683de Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 25 May 2026 18:35:50 +0200 Subject: [PATCH] fix(qa): harden restart inflight Windows scenario --- CHANGELOG.md | 1 + extensions/qa-lab/src/scenario-catalog.test.ts | 4 ++++ .../runtime/gateway-restart-inflight-run.md | 18 +++++++++--------- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cadd4fb140e5..454ce5f70bf6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,6 +61,7 @@ Docs: https://docs.openclaw.ai - Docker E2E: avoid rebuilding the Control UI twice while preparing the shared OpenClaw package tarball for package-backed scenario runs. - Tests: avoid rebuilding the Control UI twice during the installer Docker smoke now that `pnpm build` includes `ui:build`. - Tests: give QA config mutation RPCs enough native Windows budget to finish gateway config writes and restart settle after hot scenario runs. +- Tests: keep the gateway restart-inflight QA scenario focused on restart recovery on native Windows by allowing expected embedded prompt handoff errors and using the Windows-safe timeout budget. - Crabbox: sync clean sparse worktrees through a temporary full checkout even when reusing an existing lease so tracked build-time files are not omitted. - Build: route `scripts/ui.js` through the shared pnpm runner and keep Control UI chunking helpers in sparse-included source so native Windows Corepack builds can produce `dist/control-ui`. - Tests: give the memory fallback QA scenario enough turn budget to exercise native Windows gateway runs instead of failing on the client timeout while the mock agent is still dispatching. diff --git a/extensions/qa-lab/src/scenario-catalog.test.ts b/extensions/qa-lab/src/scenario-catalog.test.ts index d038a521e2ad..7b9e1d3b905f 100644 --- a/extensions/qa-lab/src/scenario-catalog.test.ts +++ b/extensions/qa-lab/src/scenario-catalog.test.ts @@ -197,6 +197,10 @@ describe("qa scenario catalog", () => { expect(readQaScenarioById("long-context-progress-watchdog").sourcePath).toBe( "qa/scenarios/runtime/long-context-progress-watchdog.md", ); + expect(JSON.stringify(readQaScenarioById("gateway-restart-inflight-run").execution.flow)) + .toContain("EmbeddedAttemptSessionTakeoverError"); + expect(JSON.stringify(readQaScenarioById("gateway-restart-inflight-run").execution.flow)) + .toContain("liveTurnTimeoutMs(env, 180000)"); expect(readQaScenarioExecutionConfig("long-context-progress-watchdog")).toMatchObject({ requiredProviderMode: "live-frontier", harnessRuntime: "codex", diff --git a/qa/scenarios/runtime/gateway-restart-inflight-run.md b/qa/scenarios/runtime/gateway-restart-inflight-run.md index 1f71cac8794c..6bcc499885a2 100644 --- a/qa/scenarios/runtime/gateway-restart-inflight-run.md +++ b/qa/scenarios/runtime/gateway-restart-inflight-run.md @@ -41,11 +41,11 @@ steps: - call: waitForGatewayHealthy args: - ref: env - - 60000 + - 180000 - call: waitForQaChannelReady args: - ref: env - - 60000 + - 180000 - call: reset - set: startIndex value: @@ -62,7 +62,7 @@ steps: message: expr: config.prompt timeoutMs: - expr: liveTurnTimeoutMs(env, 30000) + expr: liveTurnTimeoutMs(env, 180000) - call: readConfigSnapshot saveAs: current args: @@ -86,19 +86,19 @@ steps: - call: waitForGatewayHealthy args: - ref: env - - 60000 + - 180000 - call: waitForQaChannelReady args: - ref: env - - 60000 + - 180000 - call: waitForAgentRun saveAs: waited args: - ref: env - expr: started.runId - - expr: liveTurnTimeoutMs(env, 20000) + - expr: liveTurnTimeoutMs(env, 180000) - assert: - expr: "waited.status === 'ok' || waited.status === 'timeout'" + expr: "waited.status === 'ok' || waited.status === 'timeout' || (waited.status === 'error' && String(waited.error ?? '').includes('EmbeddedAttemptSessionTakeoverError'))" message: expr: "`interrupted agent run ended with unexpected status: ${JSON.stringify(waited)}`" - set: interruptedMatches @@ -116,7 +116,7 @@ steps: message: expr: config.recoveryPrompt timeoutMs: - expr: liveTurnTimeoutMs(env, 45000) + expr: liveTurnTimeoutMs(env, 180000) - call: waitForOutboundMessage saveAs: outbound args: @@ -124,7 +124,7 @@ steps: - lambda: params: [candidate] expr: "candidate.conversation.id === 'qa-operator' && candidate.text.includes(config.recoveryMarker)" - - expr: liveTurnTimeoutMs(env, 30000) + - expr: liveTurnTimeoutMs(env, 180000) - sinceIndex: ref: startIndex - set: matchingOutbounds