mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-09 16:59:43 +02:00
merge upstream master into COD-358
This commit is contained in:
@@ -1,69 +0,0 @@
|
|||||||
# 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"
|
|
||||||
```
|
|
||||||
-24
@@ -1,24 +0,0 @@
|
|||||||
# Workflow Run Watcher Clock-Independent Test Design
|
|
||||||
|
|
||||||
## Problem
|
|
||||||
|
|
||||||
`getRecentRunSummaries omits agents[] (lightweight snapshot)` uses a workflow fixture whose activity timestamps
|
|
||||||
are fixed in June 2026. The test requests a 100,000-minute recent window, so it began failing once wall-clock time
|
|
||||||
moved beyond that window even though the implementation had not changed.
|
|
||||||
|
|
||||||
## Design
|
|
||||||
|
|
||||||
Keep production code unchanged. Build the synthetic run from one captured `Date.now()` value and express its
|
|
||||||
timestamp, start time, queue times, progress times, and completion times as offsets from that value. Preserve the
|
|
||||||
existing ordering and duration relationships between workflow events, so the fixture remains representative while
|
|
||||||
its completed run always falls within the test's recent window.
|
|
||||||
|
|
||||||
Do not widen the window or replace `getRecentRunSummaries()` with an unfiltered API: either choice would weaken or
|
|
||||||
eventually reintroduce the regression. Do not install fake timers, because the watcher uses asynchronous discovery
|
|
||||||
and timer behavior that this assertion does not need to control.
|
|
||||||
|
|
||||||
## Verification
|
|
||||||
|
|
||||||
- Confirm the existing fixed fixture fails because the run falls outside the recent window.
|
|
||||||
- Run `test/workflow-run-watcher.test.ts` after converting the fixture to relative timestamps.
|
|
||||||
- Run formatting and the CI unit/integration gate before pushing the updated PR.
|
|
||||||
@@ -17,13 +17,22 @@ const PROJECT_HASH = '-home-arkon-default-claudeman';
|
|||||||
const SESSION_UUID = '388113c8-cd01-4e80-93a8-3be66ab1519b';
|
const SESSION_UUID = '388113c8-cd01-4e80-93a8-3be66ab1519b';
|
||||||
const RUN_ID = 'wf_test1234-abc';
|
const RUN_ID = 'wf_test1234-abc';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The fixture's epochs are anchored to "now", never pinned, because the recency
|
||||||
|
* assertions below compare them against `Date.now()`. A frozen epoch plus a fixed
|
||||||
|
* window is a time bomb: the original fixture's newest activity sat at
|
||||||
|
* 2026-06-14T20:06:40Z, and `getRecentRunSummaries(100000)` — that argument is
|
||||||
|
* MINUTES, i.e. 69.4 days — stopped matching it on 2026-08-23T06:46:40Z, turning
|
||||||
|
* CI red on a suite nobody had touched. Offsets from the anchor are preserved
|
||||||
|
* verbatim, so every parsed duration and ordering assertion is unchanged.
|
||||||
|
*/
|
||||||
|
const RUN_ANCHOR = Date.now() - 601_000;
|
||||||
|
|
||||||
/** A run JSON shaped like a real (killed) run: all three agent states + the bloat fields. */
|
/** A run JSON shaped like a real (killed) run: all three agent states + the bloat fields. */
|
||||||
function sampleRunJson() {
|
function sampleRunJson() {
|
||||||
const startTime = Date.now() - 15 * 60_000;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
runId: RUN_ID,
|
runId: RUN_ID,
|
||||||
timestamp: new Date(startTime).toISOString(),
|
timestamp: new Date(RUN_ANCHOR).toISOString(),
|
||||||
taskId: 'task_abc',
|
taskId: 'task_abc',
|
||||||
// --- bloat fields that MUST be stripped ---
|
// --- bloat fields that MUST be stripped ---
|
||||||
script: 'export const meta = {};\n'.repeat(5000), // ~110KB
|
script: 'export const meta = {};\n'.repeat(5000), // ~110KB
|
||||||
@@ -37,7 +46,7 @@ function sampleRunJson() {
|
|||||||
workflowName: 'review-open-prs',
|
workflowName: 'review-open-prs',
|
||||||
status: 'killed',
|
status: 'killed',
|
||||||
error: 'user stopped the task',
|
error: 'user stopped the task',
|
||||||
startTime,
|
startTime: RUN_ANCHOR,
|
||||||
defaultModel: 'claude-opus-4-8[1m]',
|
defaultModel: 'claude-opus-4-8[1m]',
|
||||||
totalTokens: 109703,
|
totalTokens: 109703,
|
||||||
totalToolCalls: 44,
|
totalToolCalls: 44,
|
||||||
@@ -57,13 +66,13 @@ function sampleRunJson() {
|
|||||||
agentId: 'a6c0e282c3f5ac0bf',
|
agentId: 'a6c0e282c3f5ac0bf',
|
||||||
model: 'claude-opus-4-8[1m]',
|
model: 'claude-opus-4-8[1m]',
|
||||||
state: 'done',
|
state: 'done',
|
||||||
startedAt: startTime + 1002,
|
startedAt: RUN_ANCHOR + 1002,
|
||||||
queuedAt: startTime + 962,
|
queuedAt: RUN_ANCHOR + 962,
|
||||||
attempt: 1,
|
attempt: 1,
|
||||||
lastToolName: 'StructuredOutput',
|
lastToolName: 'StructuredOutput',
|
||||||
lastToolSummary: 'Does the profile setting make the allowlist dead config',
|
lastToolSummary: 'Does the profile setting make the allowlist dead config',
|
||||||
promptPreview: 'You are reviewing a pull request...',
|
promptPreview: 'You are reviewing a pull request...',
|
||||||
lastProgressAt: startTime + 525143,
|
lastProgressAt: RUN_ANCHOR + 525_143,
|
||||||
tokens: 104703,
|
tokens: 104703,
|
||||||
toolCalls: 41,
|
toolCalls: 41,
|
||||||
durationMs: 524140,
|
durationMs: 524140,
|
||||||
@@ -78,12 +87,12 @@ function sampleRunJson() {
|
|||||||
agentId: 'a1234567890abcdef',
|
agentId: 'a1234567890abcdef',
|
||||||
model: 'claude-opus-4-8[1m]',
|
model: 'claude-opus-4-8[1m]',
|
||||||
state: 'progress',
|
state: 'progress',
|
||||||
startedAt: startTime + 11000,
|
startedAt: RUN_ANCHOR + 11_000,
|
||||||
queuedAt: startTime + 970,
|
queuedAt: RUN_ANCHOR + 970,
|
||||||
attempt: 1,
|
attempt: 1,
|
||||||
lastToolName: 'Read',
|
lastToolName: 'Read',
|
||||||
promptPreview: 'Review PR 127...',
|
promptPreview: 'Review PR 127...',
|
||||||
lastProgressAt: startTime + 601000,
|
lastProgressAt: RUN_ANCHOR + 601_000,
|
||||||
tokens: 5000,
|
tokens: 5000,
|
||||||
toolCalls: 3,
|
toolCalls: 3,
|
||||||
},
|
},
|
||||||
@@ -95,9 +104,9 @@ function sampleRunJson() {
|
|||||||
phaseTitle: 'Verify',
|
phaseTitle: 'Verify',
|
||||||
model: 'claude-opus-4-8[1m]',
|
model: 'claude-opus-4-8[1m]',
|
||||||
state: 'start',
|
state: 'start',
|
||||||
queuedAt: startTime + 980,
|
queuedAt: RUN_ANCHOR + 980,
|
||||||
promptPreview: 'Verify finding x...',
|
promptPreview: 'Verify finding x...',
|
||||||
lastProgressAt: startTime + 980,
|
lastProgressAt: RUN_ANCHOR + 980,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user