fix(gsd): update test files for removed completedUnits, writeLock signature, and type changes
- Remove completedUnits from WorkerInfo/SessionLockData test object literals - Remove verifyExpectedArtifact/writeUnitRuntimeRecord from LoopDeps mocks - Fix writeLock call signatures (remove numeric completedUnits arg) - Fix idle-recovery imports (moved to auto-recovery.ts) - Add full_plan_md to TaskRow test objects - Fix WorkflowEvent type in test (exclude session_id from Omit) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
63dea156c3
commit
8119e12ce9
14 changed files with 34 additions and 61 deletions
|
|
@ -367,9 +367,6 @@ function makeMockDeps(
|
|||
getPriorSliceCompletionBlocker: () => null,
|
||||
getMainBranch: () => "main",
|
||||
closeoutUnit: async () => {},
|
||||
verifyExpectedArtifact: () => true,
|
||||
clearUnitRuntimeRecord: () => {},
|
||||
writeUnitRuntimeRecord: () => {},
|
||||
recordOutcome: () => {},
|
||||
writeLock: () => {},
|
||||
captureAvailableSkills: () => {},
|
||||
|
|
@ -1990,7 +1987,6 @@ test("autoLoop does NOT reject non-execute-task units with 0 tool calls (#1833)"
|
|||
});
|
||||
},
|
||||
getLedger: () => mockLedger,
|
||||
verifyExpectedArtifact: () => true,
|
||||
postUnitPostVerification: async () => {
|
||||
deps.callLog.push("postUnitPostVerification");
|
||||
s.active = false;
|
||||
|
|
|
|||
|
|
@ -195,9 +195,6 @@ function makeMockDeps(overrides?: Partial<LoopDeps>): LoopDeps & { callLog: stri
|
|||
getPriorSliceCompletionBlocker: () => null,
|
||||
getMainBranch: () => "main",
|
||||
closeoutUnit: async () => {},
|
||||
verifyExpectedArtifact: () => true,
|
||||
clearUnitRuntimeRecord: () => {},
|
||||
writeUnitRuntimeRecord: () => {},
|
||||
recordOutcome: () => {},
|
||||
writeLock: () => {},
|
||||
captureAvailableSkills: () => {},
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
writeBlockerPlaceholder,
|
||||
verifyExpectedArtifact,
|
||||
buildLoopRemediationSteps,
|
||||
} from "../auto.ts";
|
||||
} from "../auto-recovery.ts";
|
||||
import { describe, test, beforeEach, afterEach } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
|
||||
|
|
|
|||
|
|
@ -92,9 +92,6 @@ function makeMockDeps(
|
|||
getPriorSliceCompletionBlocker: () => null,
|
||||
getMainBranch: () => "main",
|
||||
closeoutUnit: async () => {},
|
||||
verifyExpectedArtifact: () => true,
|
||||
clearUnitRuntimeRecord: () => {},
|
||||
writeUnitRuntimeRecord: () => {},
|
||||
recordOutcome: () => {},
|
||||
writeLock: () => {},
|
||||
captureAvailableSkills: () => {},
|
||||
|
|
|
|||
|
|
@ -322,7 +322,6 @@ test("budget — refreshWorkerStatuses updates worker state from disk", async ()
|
|||
const workers = getWorkerStatuses();
|
||||
assert.equal(workers.length, 1);
|
||||
assert.equal(workers[0]!.state, "paused", "worker state should be updated from disk");
|
||||
assert.equal(workers[0]!.completedUnits, 5, "completedUnits should be updated from disk");
|
||||
assert.equal(workers[0]!.cost, 2.5, "cost should be updated from disk");
|
||||
} finally {
|
||||
resetOrchestrator();
|
||||
|
|
|
|||
|
|
@ -71,7 +71,6 @@ test('Test 1: persistState writes valid JSON', () => {
|
|||
worktreePath: "/tmp/wt-M001",
|
||||
startedAt: Date.now(),
|
||||
state: "running",
|
||||
completedUnits: 3,
|
||||
cost: 0.15,
|
||||
},
|
||||
],
|
||||
|
|
@ -114,7 +113,6 @@ test('Test 3: restoreState filters dead PIDs', () => {
|
|||
worktreePath: "/tmp/wt-M001",
|
||||
startedAt: Date.now(),
|
||||
state: "running",
|
||||
completedUnits: 0,
|
||||
cost: 0,
|
||||
},
|
||||
{
|
||||
|
|
@ -124,7 +122,6 @@ test('Test 3: restoreState filters dead PIDs', () => {
|
|||
worktreePath: "/tmp/wt-M002",
|
||||
startedAt: Date.now(),
|
||||
state: "running",
|
||||
completedUnits: 0,
|
||||
cost: 0,
|
||||
},
|
||||
],
|
||||
|
|
@ -153,7 +150,6 @@ test('Test 4: restoreState keeps alive PIDs', () => {
|
|||
worktreePath: "/tmp/wt-M001",
|
||||
startedAt: Date.now(),
|
||||
state: "running",
|
||||
completedUnits: 5,
|
||||
cost: 0.25,
|
||||
},
|
||||
{
|
||||
|
|
@ -163,7 +159,6 @@ test('Test 4: restoreState keeps alive PIDs', () => {
|
|||
worktreePath: "/tmp/wt-M002",
|
||||
startedAt: Date.now(),
|
||||
state: "running",
|
||||
completedUnits: 0,
|
||||
cost: 0,
|
||||
},
|
||||
],
|
||||
|
|
@ -176,7 +171,6 @@ test('Test 4: restoreState keeps alive PIDs', () => {
|
|||
assert.deepStrictEqual(result!.workers.length, 1, "restoreState: filters out dead PID");
|
||||
assert.deepStrictEqual(result!.workers[0].milestoneId, "M001", "restoreState: keeps alive worker");
|
||||
assert.deepStrictEqual(result!.workers[0].pid, process.pid, "restoreState: preserves PID");
|
||||
assert.deepStrictEqual(result!.workers[0].completedUnits, 5, "restoreState: preserves progress");
|
||||
} finally {
|
||||
rmSync(basePath, { recursive: true, force: true });
|
||||
}
|
||||
|
|
@ -194,7 +188,6 @@ test('Test 5: restoreState skips stopped/error workers even with alive PIDs', ()
|
|||
worktreePath: "/tmp/wt-M001",
|
||||
startedAt: Date.now(),
|
||||
state: "stopped",
|
||||
completedUnits: 10,
|
||||
cost: 0.50,
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -70,7 +70,6 @@ function makeWorker(overrides: Partial<WorkerInfo> = {}): WorkerInfo {
|
|||
worktreePath: "/tmp/test",
|
||||
startedAt: Date.now(),
|
||||
state: "stopped",
|
||||
completedUnits: 3,
|
||||
cost: 1.5,
|
||||
...overrides,
|
||||
};
|
||||
|
|
@ -132,16 +131,16 @@ test("determineMergeOrder — by-completion sorts by startedAt (earliest first)"
|
|||
assert.deepEqual(order, ["M003", "M002", "M001"]);
|
||||
});
|
||||
|
||||
test("determineMergeOrder — only includes stopped workers with completedUnits > 0", () => {
|
||||
test("determineMergeOrder — only includes stopped workers", () => {
|
||||
const workers = [
|
||||
makeWorker({ milestoneId: "M001", state: "stopped", completedUnits: 3 }),
|
||||
makeWorker({ milestoneId: "M002", state: "running", completedUnits: 2 }),
|
||||
makeWorker({ milestoneId: "M003", state: "stopped", completedUnits: 0 }),
|
||||
makeWorker({ milestoneId: "M004", state: "error", completedUnits: 5 }),
|
||||
makeWorker({ milestoneId: "M005", state: "paused", completedUnits: 1 }),
|
||||
makeWorker({ milestoneId: "M001", state: "stopped" }),
|
||||
makeWorker({ milestoneId: "M002", state: "running" }),
|
||||
makeWorker({ milestoneId: "M003", state: "stopped" }),
|
||||
makeWorker({ milestoneId: "M004", state: "error" }),
|
||||
makeWorker({ milestoneId: "M005", state: "paused" }),
|
||||
];
|
||||
const order = determineMergeOrder(workers, "sequential");
|
||||
assert.deepEqual(order, ["M001"]);
|
||||
assert.deepEqual(order, ["M001", "M003"]);
|
||||
});
|
||||
|
||||
test("determineMergeOrder — empty workers returns empty array", () => {
|
||||
|
|
|
|||
|
|
@ -297,7 +297,6 @@ describe("parallel-orchestrator: lifecycle", () => {
|
|||
worktreePath: "/tmp/wt-M001",
|
||||
startedAt: Date.now(),
|
||||
state: "running",
|
||||
completedUnits: 2,
|
||||
cost: 0.25,
|
||||
},
|
||||
],
|
||||
|
|
@ -309,7 +308,6 @@ describe("parallel-orchestrator: lifecycle", () => {
|
|||
const workers = getWorkerStatuses(base);
|
||||
assert.equal(workers.length, 1);
|
||||
assert.equal(workers[0].milestoneId, "M001");
|
||||
assert.equal(workers[0].completedUnits, 2);
|
||||
assert.equal(isParallelActive(), true);
|
||||
} finally {
|
||||
resetOrchestrator();
|
||||
|
|
@ -416,7 +414,6 @@ describe("parallel-orchestrator: lifecycle", () => {
|
|||
const workers = getWorkerStatuses();
|
||||
assert.equal(workers.length, 1);
|
||||
assert.equal(workers[0].state, "running");
|
||||
assert.equal(workers[0].completedUnits, 4);
|
||||
} finally {
|
||||
resetOrchestrator();
|
||||
rmSync(base, { recursive: true, force: true });
|
||||
|
|
@ -552,7 +549,6 @@ function makeWorker(overrides: Partial<WorkerInfo> = {}): WorkerInfo {
|
|||
worktreePath: "/tmp/test-worktree",
|
||||
startedAt: Date.now() - 60_000,
|
||||
state: "stopped",
|
||||
completedUnits: 5,
|
||||
cost: 2.50,
|
||||
...overrides,
|
||||
};
|
||||
|
|
@ -563,9 +559,9 @@ function makeWorker(overrides: Partial<WorkerInfo> = {}): WorkerInfo {
|
|||
describe("parallel-merge: determineMergeOrder sequential", () => {
|
||||
it("returns milestone IDs sorted alphabetically by default", () => {
|
||||
const workers = [
|
||||
makeWorker({ milestoneId: "M003", state: "stopped", completedUnits: 1 }),
|
||||
makeWorker({ milestoneId: "M001", state: "stopped", completedUnits: 2 }),
|
||||
makeWorker({ milestoneId: "M002", state: "stopped", completedUnits: 3 }),
|
||||
makeWorker({ milestoneId: "M003", state: "stopped" }),
|
||||
makeWorker({ milestoneId: "M001", state: "stopped" }),
|
||||
makeWorker({ milestoneId: "M002", state: "stopped" }),
|
||||
];
|
||||
const order = determineMergeOrder(workers, "sequential");
|
||||
assert.deepEqual(order, ["M001", "M002", "M003"]);
|
||||
|
|
@ -573,27 +569,27 @@ describe("parallel-merge: determineMergeOrder sequential", () => {
|
|||
|
||||
it("excludes workers that are still running", () => {
|
||||
const workers = [
|
||||
makeWorker({ milestoneId: "M001", state: "stopped", completedUnits: 5 }),
|
||||
makeWorker({ milestoneId: "M002", state: "running", completedUnits: 0 }),
|
||||
makeWorker({ milestoneId: "M003", state: "stopped", completedUnits: 2 }),
|
||||
makeWorker({ milestoneId: "M001", state: "stopped" }),
|
||||
makeWorker({ milestoneId: "M002", state: "running" }),
|
||||
makeWorker({ milestoneId: "M003", state: "stopped" }),
|
||||
];
|
||||
const order = determineMergeOrder(workers, "sequential");
|
||||
assert.deepEqual(order, ["M001", "M003"]);
|
||||
});
|
||||
|
||||
it("excludes workers with zero completedUnits even if stopped", () => {
|
||||
it("includes all stopped workers", () => {
|
||||
const workers = [
|
||||
makeWorker({ milestoneId: "M001", state: "stopped", completedUnits: 0 }),
|
||||
makeWorker({ milestoneId: "M002", state: "stopped", completedUnits: 3 }),
|
||||
makeWorker({ milestoneId: "M001", state: "stopped" }),
|
||||
makeWorker({ milestoneId: "M002", state: "stopped" }),
|
||||
];
|
||||
const order = determineMergeOrder(workers, "sequential");
|
||||
assert.deepEqual(order, ["M002"]);
|
||||
assert.deepEqual(order, ["M001", "M002"]);
|
||||
});
|
||||
|
||||
it("returns empty array when no workers are completed", () => {
|
||||
const workers = [
|
||||
makeWorker({ milestoneId: "M001", state: "running", completedUnits: 0 }),
|
||||
makeWorker({ milestoneId: "M002", state: "paused", completedUnits: 0 }),
|
||||
makeWorker({ milestoneId: "M001", state: "running" }),
|
||||
makeWorker({ milestoneId: "M002", state: "paused" }),
|
||||
];
|
||||
const order = determineMergeOrder(workers);
|
||||
assert.deepEqual(order, []);
|
||||
|
|
@ -601,8 +597,8 @@ describe("parallel-merge: determineMergeOrder sequential", () => {
|
|||
|
||||
it("uses sequential order as the default when no order arg provided", () => {
|
||||
const workers = [
|
||||
makeWorker({ milestoneId: "M002", state: "stopped", completedUnits: 1 }),
|
||||
makeWorker({ milestoneId: "M001", state: "stopped", completedUnits: 1 }),
|
||||
makeWorker({ milestoneId: "M002", state: "stopped" }),
|
||||
makeWorker({ milestoneId: "M001", state: "stopped" }),
|
||||
];
|
||||
// Call with no second argument — should default to "sequential"
|
||||
const order = determineMergeOrder(workers);
|
||||
|
|
@ -614,9 +610,9 @@ describe("parallel-merge: determineMergeOrder by-completion", () => {
|
|||
it("returns milestones sorted by startedAt (earliest first)", () => {
|
||||
const now = Date.now();
|
||||
const workers = [
|
||||
makeWorker({ milestoneId: "M003", state: "stopped", completedUnits: 1, startedAt: now - 30_000 }),
|
||||
makeWorker({ milestoneId: "M001", state: "stopped", completedUnits: 1, startedAt: now - 90_000 }),
|
||||
makeWorker({ milestoneId: "M002", state: "stopped", completedUnits: 1, startedAt: now - 60_000 }),
|
||||
makeWorker({ milestoneId: "M003", state: "stopped", startedAt: now - 30_000 }),
|
||||
makeWorker({ milestoneId: "M001", state: "stopped", startedAt: now - 90_000 }),
|
||||
makeWorker({ milestoneId: "M002", state: "stopped", startedAt: now - 60_000 }),
|
||||
];
|
||||
const order = determineMergeOrder(workers, "by-completion");
|
||||
assert.deepEqual(order, ["M001", "M002", "M003"]);
|
||||
|
|
@ -625,9 +621,9 @@ describe("parallel-merge: determineMergeOrder by-completion", () => {
|
|||
it("excludes paused workers from by-completion order", () => {
|
||||
const now = Date.now();
|
||||
const workers = [
|
||||
makeWorker({ milestoneId: "M001", state: "stopped", completedUnits: 2, startedAt: now - 90_000 }),
|
||||
makeWorker({ milestoneId: "M002", state: "paused", completedUnits: 1, startedAt: now - 60_000 }),
|
||||
makeWorker({ milestoneId: "M003", state: "stopped", completedUnits: 3, startedAt: now - 30_000 }),
|
||||
makeWorker({ milestoneId: "M001", state: "stopped", startedAt: now - 90_000 }),
|
||||
makeWorker({ milestoneId: "M002", state: "paused", startedAt: now - 60_000 }),
|
||||
makeWorker({ milestoneId: "M003", state: "stopped", startedAt: now - 30_000 }),
|
||||
];
|
||||
const order = determineMergeOrder(workers, "by-completion");
|
||||
assert.deepEqual(order, ["M001", "M003"]);
|
||||
|
|
|
|||
|
|
@ -155,7 +155,6 @@ describe("parallel-worker-monitoring", () => {
|
|||
worktreePath: "/tmp/wt-M001",
|
||||
startedAt: Date.now(),
|
||||
state: "running",
|
||||
completedUnits: 1,
|
||||
cost: 0.1,
|
||||
},
|
||||
],
|
||||
|
|
@ -191,7 +190,6 @@ describe("parallel-worker-monitoring", () => {
|
|||
refreshWorkerStatuses(base, { restoreIfNeeded: true });
|
||||
const workers = getWorkerStatuses();
|
||||
assert.deepStrictEqual(workers[0].state, "running", "live session status restored");
|
||||
assert.deepStrictEqual(workers[0].completedUnits, 3, "completed units restored from status file");
|
||||
} finally {
|
||||
resetOrchestrator();
|
||||
rmSync(base, { recursive: true, force: true });
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ function makeTaskRow(overrides?: Partial<TaskRow>): TaskRow {
|
|||
key_files: [],
|
||||
key_decisions: [],
|
||||
full_summary_md: '',
|
||||
full_plan_md: '',
|
||||
description: 'Test description',
|
||||
estimate: '30m',
|
||||
files: ['src/test.ts'],
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ describe('session-lock-regression', async () => {
|
|||
try {
|
||||
acquireSessionLock(base);
|
||||
|
||||
updateSessionLock(base, 'execute-task', 'M001/S01/T01', 5, '/tmp/session.json');
|
||||
updateSessionLock(base, 'execute-task', 'M001/S01/T01', '/tmp/session.json');
|
||||
|
||||
const data = readSessionLockData(base);
|
||||
assert.ok(data !== null, 'lock data readable after update');
|
||||
|
|
@ -111,7 +111,6 @@ describe('session-lock-regression', async () => {
|
|||
assert.deepStrictEqual(data.pid, process.pid, 'lock data has correct PID');
|
||||
assert.deepStrictEqual(data.unitType, 'execute-task', 'lock data has correct unit type');
|
||||
assert.deepStrictEqual(data.unitId, 'M001/S01/T01', 'lock data has correct unit ID');
|
||||
assert.deepStrictEqual(data.completedUnits, 5, 'lock data has correct completed count');
|
||||
assert.deepStrictEqual(data.sessionFile, '/tmp/session.json', 'lock data has session file');
|
||||
}
|
||||
|
||||
|
|
@ -136,7 +135,6 @@ describe('session-lock-regression', async () => {
|
|||
unitType: 'execute-task',
|
||||
unitId: 'M001/S01/T01',
|
||||
unitStartedAt: new Date(Date.now() - 3600000).toISOString(),
|
||||
completedUnits: 3,
|
||||
};
|
||||
writeFileSync(lockFile, JSON.stringify(staleLock, null, 2));
|
||||
|
||||
|
|
@ -233,7 +231,6 @@ describe('session-lock-regression', async () => {
|
|||
unitType: 'execute-task',
|
||||
unitId: 'M001/S01/T01',
|
||||
unitStartedAt: new Date().toISOString(),
|
||||
completedUnits: 0,
|
||||
}, null, 2));
|
||||
|
||||
const status = getSessionLockStatus(base);
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ test("stopAutoRemote cleans up stale lock (dead PID) and returns found:false", (
|
|||
const base = makeTmpBase();
|
||||
try {
|
||||
// Write a lock with a PID that doesn't exist
|
||||
writeLock(base, "execute-task", "M001/S01/T01", 3);
|
||||
writeLock(base, "execute-task", "M001/S01/T01");
|
||||
// Overwrite PID to a dead one
|
||||
const lock = readCrashLock(base)!;
|
||||
const staleData = { ...lock, pid: 999999999 };
|
||||
|
|
@ -111,7 +111,6 @@ test("stopAutoRemote sends SIGTERM to a live process and returns found:true", {
|
|||
unitType: "execute-task",
|
||||
unitId: "M001/S01/T01",
|
||||
unitStartedAt: new Date().toISOString(),
|
||||
completedUnits: 0,
|
||||
};
|
||||
writeFileSync(join(base, ".gsd", "auto.lock"), JSON.stringify(lockData, null, 2), "utf-8");
|
||||
|
||||
|
|
@ -143,7 +142,7 @@ test("lock file should be discoverable at project root, not worktree path", () =
|
|||
|
||||
try {
|
||||
// Simulate: auto-mode writes lock to project root (the fix)
|
||||
writeLock(projectRoot, "execute-task", "M001/S01/T01", 0);
|
||||
writeLock(projectRoot, "execute-task", "M001/S01/T01");
|
||||
|
||||
// Second terminal checks project root — should find the lock
|
||||
const lock = readCrashLock(projectRoot);
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ function cleanupDir(dirPath: string): void {
|
|||
try { fs.rmSync(dirPath, { recursive: true, force: true }); } catch { /* best effort */ }
|
||||
}
|
||||
|
||||
function makeEvent(cmd: string, params: Record<string, unknown> = {}): Omit<WorkflowEvent, 'hash'> {
|
||||
function makeEvent(cmd: string, params: Record<string, unknown> = {}): Omit<WorkflowEvent, 'hash' | 'session_id'> {
|
||||
return { cmd, params, ts: new Date().toISOString(), actor: 'agent' };
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ function makeTask(overrides: Partial<TaskRow> = {}): TaskRow {
|
|||
key_files: [],
|
||||
key_decisions: [],
|
||||
full_summary_md: '',
|
||||
full_plan_md: '',
|
||||
inputs: [],
|
||||
expected_output: [],
|
||||
observability_impact: '',
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue