fix(agent-pod): committed progress ledger so resume skips done tasks

Resuming the phase branch alone only recovers the code -- the task loop
still walked from the first task, re-verifying every already-done one
through a full planner call before reaching the first task that actually
needed work. .agent-progress is committed (not gitignored) and appended
per completed task, so a resumed run reads it once and skips straight
past known-done tasks with zero LLM calls. Validated locally against a
throwaway repo: second run skipped both tasks instantly (resumed: true)
instead of re-running planner on them.
This commit is contained in:
Story Crater Bot
2026-08-19 13:16:03 -07:00
parent f6de231999
commit 7c7a171c8d
@@ -469,6 +469,36 @@ data:
}
}
// Committed (never gitignored) so it survives a resumed phase branch --
// one task id per line, appended as each task resolves. This is what lets
// a resumed run skip straight past already-resolved tasks instead of
// re-running planner's judgeOnly decision on every one of them again:
// resuming the git branch alone only recovers the CODE, not "which tasks
// are already settled," and re-deciding that from scratch for every task
// burns a full LLM call per already-done task before ever reaching the
// first one that actually needs work.
function progressLedgerPath(cwd) {
return path.join(cwd, ".agent-progress");
}
function readCompletedTasks(cwd) {
const file = progressLedgerPath(cwd);
if (!fs.existsSync(file)) return new Set();
return new Set(
fs
.readFileSync(file, "utf8")
.split("\n")
.map((line) => line.trim())
.filter(Boolean)
);
}
async function recordTaskComplete(cwd, task) {
fs.appendFileSync(progressLedgerPath(cwd), `${task}\n`);
await runGit(cwd, ["add", path.basename(progressLedgerPath(cwd))]);
await runGit(cwd, ["commit", "-m", `chore: mark ${task} complete in progress ledger`]);
}
// Runs every task in a phase (no declared dependency between them) strictly
// one at a time against the repo's shared role pool -- only one implementer/
// judge/etc. exists per repo, so there is no per-task concurrency to have
@@ -485,9 +515,21 @@ data:
// from a clone that never saw any of that work.
async function runPhase(cwd, baseBranch, phaseBranch, phaseTasks, pool, repoId, pipelineSession) {
const entries = phaseTasks.map((t) => (typeof t === "string" ? { id: t, judgeOnly: false } : t));
const completed = readCompletedTasks(cwd);
for (const entry of entries) {
if (completed.has(entry.id)) {
const result = { task: entry.id, status: "done", resumed: true };
pipelineSession.taskResults.push(result);
logProgress(pipelineSession);
continue;
}
const result = await runTaskOnPool(cwd, baseBranch, entry.id, pool, repoId, pipelineSession, entry.judgeOnly);
pipelineSession.taskResults.push(result);
if (result.status === "done" || result.status === "done-with-concerns") {
await recordTaskComplete(cwd, entry.id);
}
await runGit(cwd, ["push", "-u", "origin", phaseBranch]);
logProgress(pipelineSession);
}