fix(gsd): address QA round 2
- Initialize autoStartTime, originalModelId, originalModelProvider, and autoModeStartModel on file-based paused-session resume path so dashboard elapsed time, model restore on stop, and error-recovery model fallback all work correctly. - Validate worktreePath existence before using it as assessment base; fall back to project root when the worktree has been torn down. - Add tests for paused-session-only (no lock) with resumable disk state and for worktreePath fallback when the directory no longer exists.
This commit is contained in:
parent
9e357f8a85
commit
364cc7dcbc
3 changed files with 43 additions and 1 deletions
|
|
@ -1023,6 +1023,12 @@ export async function startAuto(
|
|||
s.stepMode = s.stepMode || requestedStepMode;
|
||||
s.cmdCtx = ctx;
|
||||
s.basePath = base;
|
||||
s.autoStartTime = Date.now();
|
||||
s.originalModelId = ctx.model?.id ?? null;
|
||||
s.originalModelProvider = ctx.model?.provider ?? null;
|
||||
if (ctx.model) {
|
||||
s.autoModeStartModel = { provider: ctx.model.provider, id: ctx.model.id };
|
||||
}
|
||||
s.unitDispatchCount.clear();
|
||||
s.unitLifetimeDispatches.clear();
|
||||
if (!getLedger()) initMetrics(base);
|
||||
|
|
|
|||
|
|
@ -74,7 +74,10 @@ export async function assessInterruptedSession(
|
|||
basePath: string,
|
||||
): Promise<InterruptedSessionAssessment> {
|
||||
const pausedSession = readPausedSessionMetadata(basePath);
|
||||
const assessmentBasePath = pausedSession?.worktreePath || basePath;
|
||||
const worktreeExists = pausedSession?.worktreePath
|
||||
? existsSync(pausedSession.worktreePath)
|
||||
: false;
|
||||
const assessmentBasePath = worktreeExists ? pausedSession!.worktreePath! : basePath;
|
||||
const rawLock = readCrashLock(basePath);
|
||||
const lock = rawLock && rawLock.pid !== process.pid ? rawLock : null;
|
||||
|
||||
|
|
|
|||
|
|
@ -251,6 +251,39 @@ test("assessInterruptedSession marks stale paused-session metadata as stale when
|
|||
}
|
||||
});
|
||||
|
||||
test("assessInterruptedSession classifies paused session without lock as recoverable when disk state is resumable", async () => {
|
||||
const base = makeTmpBase();
|
||||
try {
|
||||
writeRoadmap(base, false);
|
||||
writePausedSession(base, "M001", true);
|
||||
|
||||
const assessment = await assessInterruptedSession(base);
|
||||
assert.equal(assessment.classification, "recoverable");
|
||||
assert.equal(assessment.lock, null);
|
||||
assert.equal(assessment.pausedSession?.milestoneId, "M001");
|
||||
assert.equal(assessment.hasResumableDiskState, true);
|
||||
assert.equal(assessment.isBootstrapCrash, false);
|
||||
} finally {
|
||||
cleanup(base);
|
||||
}
|
||||
});
|
||||
|
||||
test("assessInterruptedSession falls back to basePath when worktreePath no longer exists", async () => {
|
||||
const base = makeTmpBase();
|
||||
try {
|
||||
writeRoadmap(base, false);
|
||||
// Reference a worktree that doesn't exist on disk
|
||||
writePausedSession(base, "M001", false, "/nonexistent/worktree");
|
||||
|
||||
const assessment = await assessInterruptedSession(base);
|
||||
// Should use basePath (which has an unfinished roadmap) instead of the missing worktree
|
||||
assert.equal(assessment.classification, "recoverable");
|
||||
assert.equal(assessment.hasResumableDiskState, true);
|
||||
} finally {
|
||||
cleanup(base);
|
||||
}
|
||||
});
|
||||
|
||||
test("assessInterruptedSession prefers paused worktree state when worktreePath is recorded", async () => {
|
||||
const base = makeTmpBase();
|
||||
const worktree = join(base, "worktree-copy");
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue