diff --git a/docs/superpowers/plans/2026-08-23-workflow-run-watcher-clock-independent-test.md b/docs/superpowers/plans/2026-08-23-workflow-run-watcher-clock-independent-test.md new file mode 100644 index 00000000..894aa6fb --- /dev/null +++ b/docs/superpowers/plans/2026-08-23-workflow-run-watcher-clock-independent-test.md @@ -0,0 +1,69 @@ +# Workflow Run Watcher Clock-Independent Test Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Prevent `workflow-run-watcher.test.ts` from expiring as wall-clock time advances. + +**Architecture:** Keep production code unchanged. Anchor every synthetic workflow timestamp to one captured current +time while preserving the fixture's existing event offsets, then verify the recent-summary assertion against the +real watcher. + +**Tech Stack:** TypeScript, Vitest, Node.js + +--- + +### Task 1: Make the completed-run fixture relative to test time + +**Files:** + +- Modify: `test/workflow-run-watcher.test.ts:17-100` + +- [x] **Step 1: Confirm the fixed fixture fails after its recent window expires** + +Run: + +```bash +npm test -- test/workflow-run-watcher.test.ts +``` + +Expected: FAIL in `getRecentRunSummaries omits agents[] (lightweight snapshot)` because `summaries` is empty. + +- [x] **Step 2: Anchor the fixture to the current test time** + +At the start of `sampleRunJson()`, capture a start time fifteen minutes before the call: + +```typescript +const startTime = Date.now() - 15 * 60_000; +``` + +Replace the fixed ISO timestamp with `new Date(startTime).toISOString()`, replace the fixed `startTime` property +with the variable, and express each workflow agent's `startedAt`, `queuedAt`, and `lastProgressAt` as its existing +millisecond offset from `startTime`. + +- [x] **Step 3: Verify the focused test passes** + +Run: + +```bash +npm test -- test/workflow-run-watcher.test.ts +``` + +Expected: 19 tests pass with no failures. + +- [x] **Step 4: Verify formatting and the CI gate** + +Run: + +```bash +npx prettier --check test/workflow-run-watcher.test.ts +npm run test:ci +``` + +Expected: formatting passes and the CI unit/integration suite has no failures. + +- [x] **Step 5: Commit the correction** + +```bash +git add test/workflow-run-watcher.test.ts docs/superpowers/plans/2026-08-23-workflow-run-watcher-clock-independent-test.md +git commit -m "test(workflows): keep recent-run fixture clock-independent" +``` diff --git a/test/workflow-run-watcher.test.ts b/test/workflow-run-watcher.test.ts index 73fa042b..965a418e 100644 --- a/test/workflow-run-watcher.test.ts +++ b/test/workflow-run-watcher.test.ts @@ -19,9 +19,11 @@ const RUN_ID = 'wf_test1234-abc'; /** A run JSON shaped like a real (killed) run: all three agent states + the bloat fields. */ function sampleRunJson() { + const startTime = Date.now() - 15 * 60_000; + return { runId: RUN_ID, - timestamp: '2026-06-15T00:00:00.000Z', + timestamp: new Date(startTime).toISOString(), taskId: 'task_abc', // --- bloat fields that MUST be stripped --- script: 'export const meta = {};\n'.repeat(5000), // ~110KB @@ -35,7 +37,7 @@ function sampleRunJson() { workflowName: 'review-open-prs', status: 'killed', error: 'user stopped the task', - startTime: 1781466999000, + startTime, defaultModel: 'claude-opus-4-8[1m]', totalTokens: 109703, totalToolCalls: 44, @@ -55,13 +57,13 @@ function sampleRunJson() { agentId: 'a6c0e282c3f5ac0bf', model: 'claude-opus-4-8[1m]', state: 'done', - startedAt: 1781467000002, - queuedAt: 1781466999962, + startedAt: startTime + 1002, + queuedAt: startTime + 962, attempt: 1, lastToolName: 'StructuredOutput', lastToolSummary: 'Does the profile setting make the allowlist dead config', promptPreview: 'You are reviewing a pull request...', - lastProgressAt: 1781467524143, + lastProgressAt: startTime + 525143, tokens: 104703, toolCalls: 41, durationMs: 524140, @@ -76,12 +78,12 @@ function sampleRunJson() { agentId: 'a1234567890abcdef', model: 'claude-opus-4-8[1m]', state: 'progress', - startedAt: 1781467010000, - queuedAt: 1781466999970, + startedAt: startTime + 11000, + queuedAt: startTime + 970, attempt: 1, lastToolName: 'Read', promptPreview: 'Review PR 127...', - lastProgressAt: 1781467600000, + lastProgressAt: startTime + 601000, tokens: 5000, toolCalls: 3, }, @@ -93,9 +95,9 @@ function sampleRunJson() { phaseTitle: 'Verify', model: 'claude-opus-4-8[1m]', state: 'start', - queuedAt: 1781466999980, + queuedAt: startTime + 980, promptPreview: 'Verify finding x...', - lastProgressAt: 1781466999980, + lastProgressAt: startTime + 980, }, ], };