fix: recover missing Reasonix sessions
This commit is contained in:
@@ -267,6 +267,69 @@ echo '{"session_id":"fake-session-123","conversation_id":"fake-conv-456"}'
|
||||
.toBe("initial_continuation");
|
||||
});
|
||||
|
||||
it("recovers a missing Reasonix handle for a blocked fix cycle", async () => {
|
||||
const { retryExecuteWorkflow } = await import("./workflow-engine.js");
|
||||
const { gitHead, initWorkflowState, readState, writeState } = await import("./workflow-state.js");
|
||||
const runId = "reasonix-missing-handle";
|
||||
const dir = runDir(repoRoot, runId);
|
||||
const projectKey = path.resolve(repoRoot).replaceAll(path.sep, "-");
|
||||
const sessionsDir = path.join(process.env.HOME!, ".reasonix", "projects", projectKey, "sessions");
|
||||
const sessionFile = path.join(sessionsDir, "matching-session.jsonl");
|
||||
fs.mkdirSync(sessionsDir, { recursive: true });
|
||||
fs.writeFileSync(sessionFile, [
|
||||
JSON.stringify({ role: "system", content: `Current workspace: "${path.dirname(repoRoot)}"` }),
|
||||
JSON.stringify({ role: "user", content: "# Implementation Task: Test" }),
|
||||
].join("\n"));
|
||||
fs.writeFileSync(`${sessionFile}.meta`, "{}");
|
||||
|
||||
const fakeReasonix = path.join(tmpDir, "fake-reasonix-resume");
|
||||
fs.writeFileSync(fakeReasonix, "#!/bin/bash\nexit 0\n", { mode: 0o755 });
|
||||
const startedAt = new Date(Date.now() - 5000).toISOString();
|
||||
const state = initWorkflowState({
|
||||
runId,
|
||||
repoRoot,
|
||||
baselineHead: gitHead(repoRoot),
|
||||
plan: plan(),
|
||||
executor: "reasonix",
|
||||
maxCycles: 3,
|
||||
});
|
||||
state.status = "blocked";
|
||||
state.stopDescription = "No session handle available for resume.";
|
||||
state.currentCycle = 2;
|
||||
state.cycles = [
|
||||
{
|
||||
cycleIndex: 1,
|
||||
startedAt,
|
||||
completedAt: new Date().toISOString(),
|
||||
decisionFile: "cycle-1-decision.json",
|
||||
decisionOutcome: "fix",
|
||||
},
|
||||
{ cycleIndex: 2, startedAt: new Date().toISOString() },
|
||||
];
|
||||
state.executorConfig = { binary: fakeReasonix };
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
fs.writeFileSync(path.join(dir, "cycle-1-decision.json"), JSON.stringify({
|
||||
version: "1",
|
||||
outcome: "fix",
|
||||
findingDecisions: [],
|
||||
verificationEvidence: [],
|
||||
decidedAt: new Date().toISOString(),
|
||||
}));
|
||||
writeState(dir, state);
|
||||
|
||||
await retryExecuteWorkflow({ runId });
|
||||
|
||||
const recovered = readState(dir)!;
|
||||
expect(recovered.status).toBe("awaiting_review");
|
||||
expect(recovered.sessionHandle).toEqual({ kind: "reasonix", sessionFilePath: sessionFile });
|
||||
const events = fs.readFileSync(path.join(dir, "events.jsonl"), "utf8")
|
||||
.trim().split("\n").map((line) => JSON.parse(line));
|
||||
expect(events.find((event) => event.kind === "executor_session_rebound")?.data).toEqual({
|
||||
sessionFilePath: sessionFile,
|
||||
recovery: "reasonix_project_session",
|
||||
});
|
||||
});
|
||||
|
||||
it("rebinds a validated Claude session before retrying the failed cycle", async () => {
|
||||
const { retryExecuteWorkflow } = await import("./workflow-engine.js");
|
||||
const { gitHead, initWorkflowState, readState, writeState } = await import("./workflow-state.js");
|
||||
|
||||
Reference in New Issue
Block a user