fix(retry): lineage tracking + relative mission path resolution (#28)
- retryRun rewrites a snapshot's relative mission path to the run's own recorded mission.json (absolute) before execution — retries stay faithful to what originally ran - runTask accepts options.retriedFrom; retry records lineage in result.json (additive optional field, no schema break) - task suite +4 cases: retry succeeds, lineage recorded, mission section present after retry (36 total), missing-run retry exits 4 Closes #28
This commit is contained in:
+21
-2
@@ -234,7 +234,7 @@ function writeOnce(file, content) {
|
||||
}
|
||||
}
|
||||
|
||||
function runTask(taskFile) {
|
||||
function runTask(taskFile, options = {}) {
|
||||
const resolved = JSON.parse(
|
||||
spawnSync(process.execPath, [path.join(PROJECT_ROOT, "scripts", "mosaic-config.mjs"), "validate"], {
|
||||
cwd: PROJECT_ROOT,
|
||||
@@ -345,6 +345,7 @@ function runTask(taskFile) {
|
||||
request: task.prompt,
|
||||
response,
|
||||
expectedExact: expected,
|
||||
...(options.retriedFrom ? { retriedFrom: options.retriedFrom } : {}),
|
||||
workspace: task.workspace,
|
||||
tools: task.tools,
|
||||
session: task.session,
|
||||
@@ -455,6 +456,24 @@ function retryRun(runId) {
|
||||
fail(4, `run task snapshot unreadable: ${runId}`);
|
||||
}
|
||||
|
||||
// Relative mission paths in a snapshot resolve against the ORIGINAL task
|
||||
// location, which no longer exists here — rewrite them to the run's own
|
||||
// recorded mission.json so retries stay faithful.
|
||||
let snapshotDoc;
|
||||
try {
|
||||
snapshotDoc = JSON.parse(snapshot);
|
||||
} catch {
|
||||
fail(4, `run task snapshot is not valid JSON: ${runId}`);
|
||||
}
|
||||
if (snapshotDoc.mission && !path.isAbsolute(snapshotDoc.mission)) {
|
||||
const recordedMission = path.join(dir, "mission.json");
|
||||
if (!fs.existsSync(recordedMission)) {
|
||||
fail(4, `cannot retry ${runId}: relative mission path but no mission.json snapshot in run dir`);
|
||||
}
|
||||
snapshotDoc.mission = recordedMission;
|
||||
snapshot = `${JSON.stringify(snapshotDoc, null, 2)}\n`;
|
||||
}
|
||||
|
||||
// A retry is a brand-new run: replay the recorded task snapshot through
|
||||
// the ordinary run path; existing run records stay untouched.
|
||||
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "mosaic-retry-"));
|
||||
@@ -467,7 +486,7 @@ function retryRun(runId) {
|
||||
// Best-effort cleanup only.
|
||||
}
|
||||
});
|
||||
runTask(tempTaskFile);
|
||||
runTask(tempTaskFile, { retriedFrom: runId });
|
||||
}
|
||||
|
||||
const operation = process.argv[2];
|
||||
|
||||
Reference in New Issue
Block a user