From db63931b0418f33f4be83296dc0e79e5001e9fbf Mon Sep 17 00:00:00 2001 From: Tom Owers Date: Sat, 5 Sep 2026 13:57:01 +0200 Subject: [PATCH] fix(warehouse): give the standalone command the same credential ask timeout The seeded warehouse task allows 20 minutes per credential question, on the reasoning that the user is being sent to a database console or an API-key page. `wizard warehouse` asks the same questions through the same skill and was left on the 5-minute default, so the fallback route the outro points declines and browser handoffs at gave a quarter of the time. Hoist the 20-minute allowance into `wizard-ask-bridge` as CREDENTIAL_ASK_TIMEOUT_MS and use it from both paths, so the two cannot drift again. Generated-By: PostHog Desktop Task-Id: 84b5b248-2d87-4c49-a31a-109eab181d07 --- .../orchestrator/orchestrator-runner.ts | 7 +++- .../__tests__/warehouse-ask-timeout.test.ts | 39 +++++++++++++++++++ src/lib/programs/warehouse-source/index.ts | 6 +++ src/lib/wizard-ask-bridge.ts | 16 ++++++++ 4 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 src/lib/programs/__tests__/warehouse-ask-timeout.test.ts diff --git a/src/lib/agent/runner/sequence/orchestrator/orchestrator-runner.ts b/src/lib/agent/runner/sequence/orchestrator/orchestrator-runner.ts index d6a75a59..f7f0f5bc 100644 --- a/src/lib/agent/runner/sequence/orchestrator/orchestrator-runner.ts +++ b/src/lib/agent/runner/sequence/orchestrator/orchestrator-runner.ts @@ -65,7 +65,10 @@ import { drainQueue, type RunTask } from './executor'; import { RunMetrics } from './run-metrics'; import { dependencyClosure, uncoveredBySink } from './queue-tools'; import { deferSeededTasks } from './seeded-deps'; -import { createWizardAskBridge } from '@lib/wizard-ask-bridge'; +import { + createWizardAskBridge, + CREDENTIAL_ASK_TIMEOUT_MS, +} from '@lib/wizard-ask-bridge'; import { shouldDisableAsk } from '../../shared/bootstrap'; import { agentRunTools, @@ -196,7 +199,7 @@ function resolveReferenceSkillId( * open a database console or mint a restricted API key. The drain waits it out * — the executor holds the task's promise — so the only real limit is this one. */ -const TASK_ASK_TIMEOUT_MS = 20 * 60 * 1000; +const TASK_ASK_TIMEOUT_MS = CREDENTIAL_ASK_TIMEOUT_MS; /** * How long an optional step's notice waits for an answer. diff --git a/src/lib/programs/__tests__/warehouse-ask-timeout.test.ts b/src/lib/programs/__tests__/warehouse-ask-timeout.test.ts new file mode 100644 index 00000000..5a875ad9 --- /dev/null +++ b/src/lib/programs/__tests__/warehouse-ask-timeout.test.ts @@ -0,0 +1,39 @@ +/** + * How long the standalone `wizard warehouse` command waits for a credential. + * + * The same source credentials are collected two ways: as the orchestrator's + * seeded warehouse task, and as this command — the one the outro points at + * when the user declines the offer or a source falls back to browser setup. + * The command was on the 5-minute default, so the fallback route gave the + * user a quarter of the time the in-run prompt does for identical questions. + */ +import type { WizardSession } from '@lib/wizard-session'; + +vi.mock('@utils/analytics', () => ({ + analytics: { + wizardCapture: vi.fn(), + setTag: vi.fn(), + capture: vi.fn(), + captureException: vi.fn(), + }, +})); + +import { warehouseSourceConfig } from '@lib/programs/warehouse-source/index'; +import { + CREDENTIAL_ASK_TIMEOUT_MS, + DEFAULT_ASK_TIMEOUT_MS, +} from '@lib/wizard-ask-bridge'; + +function session(): WizardSession { + return { installDir: '/tmp/app', frameworkContext: {} } as WizardSession; +} + +describe('warehouse command ask timeout', () => { + it('gives credential questions the shared allowance, not the default', async () => { + const { run } = warehouseSourceConfig; + const resolved = typeof run === 'function' ? await run(session()) : run; + + expect(resolved?.askTimeoutMs).toBe(CREDENTIAL_ASK_TIMEOUT_MS); + expect(resolved?.askTimeoutMs).toBeGreaterThan(DEFAULT_ASK_TIMEOUT_MS); + }); +}); diff --git a/src/lib/programs/warehouse-source/index.ts b/src/lib/programs/warehouse-source/index.ts index 8667a6b7..9701cd0b 100644 --- a/src/lib/programs/warehouse-source/index.ts +++ b/src/lib/programs/warehouse-source/index.ts @@ -1,6 +1,7 @@ import type { ProgramConfig } from '@lib/programs/program-step'; import type { ProgramRun } from '@lib/agent/agent-runner'; import type { WizardSession } from '@lib/wizard-session'; +import { CREDENTIAL_ASK_TIMEOUT_MS } from '@lib/wizard-ask-bridge'; import { WAREHOUSE_SOURCE_PROGRAM } from './steps.js'; import { WAREHOUSE_ABORT_CASES, @@ -60,6 +61,11 @@ export const warehouseSourceConfig: ProgramConfig = { docsUrl: 'https://posthog.com/docs/data-warehouse', spinnerMessage: 'Connecting your data source...', estimatedDurationMinutes: 5, + // Same questions the orchestrator's seeded warehouse task asks, so the + // same allowance. On the 5-minute default a user who went to fetch a + // database password came back to a cancelled prompt and the browser + // fallback — in the command the outro sends declines to. + askTimeoutMs: CREDENTIAL_ASK_TIMEOUT_MS, abortCases: WAREHOUSE_ABORT_CASES, }), requires: ['posthog-integration'], diff --git a/src/lib/wizard-ask-bridge.ts b/src/lib/wizard-ask-bridge.ts index b0d4c4a0..35595223 100644 --- a/src/lib/wizard-ask-bridge.ts +++ b/src/lib/wizard-ask-bridge.ts @@ -76,6 +76,22 @@ export const CANCELLED_SENTINEL = '__cancelled__'; /** Default per-question timeout (5 minutes). */ export const DEFAULT_ASK_TIMEOUT_MS = 5 * 60 * 1000; +/** + * Per-question timeout for a flow that collects source credentials. + * + * These questions wait on a person, not on a model: opening a database + * console, finding a host and port, minting a restricted API key. The default + * above is sized for a question the user can answer from memory and expires + * long before that errand is done. + * + * Shared rather than inlined because the same credential prompts are reached + * two ways — as the orchestrator's seeded warehouse task and as the standalone + * `wizard warehouse` command the outro points declines at — and the two giving + * the user different allowances for identical questions is the bug, not a + * setting. + */ +export const CREDENTIAL_ASK_TIMEOUT_MS = 20 * 60 * 1000; + function buildCancelledAnswers(questions: AskQuestion[]): AskAnswers { const out: AskAnswers = {}; for (const q of questions) {