fix(gsd): address QA round 1

- Re-derive state from project root after stale/recoverable cleanup in
  guided flow; the assessment may have derived state from a worktree
  path that was cleaned up, leading to stale state being used downstream.
- Add test for the "none" classification path (clean startup with no
  lock and no paused session) to close coverage gap.
This commit is contained in:
Derek Pearson 2026-03-21 20:57:21 -04:00
parent d3db0cb411
commit 9e357f8a85
2 changed files with 22 additions and 2 deletions

View file

@ -909,8 +909,9 @@ export async function showSmartEntry(
}
}
const state = interrupted.state ?? await deriveState(basePath);
// Always derive from the project root — the assessment may have derived
// state from a worktree path that was cleaned up in the stale branch above.
const state = await deriveState(basePath);
if (!state.activeMilestone) {
// Guard: if a discuss session is already in flight, don't re-inject the prompt.

View file

@ -168,6 +168,25 @@ test("readPausedSessionMetadata reads paused-session metadata when present", ()
}
});
test("assessInterruptedSession returns none when no lock and no paused session exist", async () => {
const base = makeTmpBase();
try {
const assessment = await assessInterruptedSession(base);
assert.equal(assessment.classification, "none");
assert.equal(assessment.lock, null);
assert.equal(assessment.pausedSession, null);
assert.equal(assessment.state, null);
assert.equal(assessment.recovery, null);
assert.equal(assessment.recoveryPrompt, null);
assert.equal(assessment.recoveryToolCallCount, 0);
assert.equal(assessment.artifactSatisfied, false);
assert.equal(assessment.hasResumableDiskState, false);
assert.equal(assessment.isBootstrapCrash, false);
} finally {
cleanup(base);
}
});
test("assessInterruptedSession classifies stale complete repo as stale and suppresses recovery", async () => {
const base = makeTmpBase();
try {