coordinator: make gitignore/PLAN.md setup idempotent, run every phase

Old i===0 && !resuming gate meant this only ran on a fresh start -- every
run this session was a resume, so poiman's branch never got the harness
gitignore rules, and portfolio's PLAN.md stayed tracked from before the
rule existed (gitignore doesn't affect already-tracked files). Now checks
and fixes both on every phase instead of once at genesis.
This commit is contained in:
Story Crater Bot
2026-08-19 21:12:33 -07:00
parent 1b38297cbf
commit 081bbf97fc
+38 -22
View File
@@ -752,31 +752,47 @@ data:
return finish("branch-crashed"); return finish("branch-crashed");
} }
if (i === 0 && !resuming) { // Idempotent and run every phase, NOT gated on a fresh (non-resumed)
const gitignoreAdditions = [ // start -- every run this session was a resume, so the old i===0 &&
"", // !resuming gate meant this setup permanently never ran on poiman's
"# agent-harness: build artifacts and vendored archives never belong in source control", // branch, and portfolio's PLAN.md stayed tracked from before this rule
"*.tar.gz", // ever existed (gitignore has no effect on an already-tracked file --
"*.tgz", // observed live: it kept getting swept back in by every `git add -A`
"*.crate", // regardless of the ignore rule). Check-and-fix on every phase instead
"*.zip", // of once-at-genesis so a repo that's missing either self-heals on its
"*.bin", // very next run rather than carrying the gap forever.
"*.whl", const gitignorePath = path.join(cwd, ".gitignore");
"vendor/", const currentGitignore = fs.existsSync(gitignorePath) ? fs.readFileSync(gitignorePath, "utf8").split("\n") : [];
"node_modules/", const requiredGitignoreLines = [
"", "*.tar.gz",
"# agent-harness: task/phase completion sentinel files, harness bookkeeping only", "*.tgz",
".task-result-*", "*.crate",
".phase-result-*", "*.zip",
".stage-done-*", "*.bin",
"", "*.whl",
"# agent-harness: PLAN.md is per-task planner scratch state, never a deliverable", "vendor/",
"PLAN.md", "node_modules/",
].join("\n"); ".task-result-*",
fs.appendFileSync(path.join(cwd, ".gitignore"), gitignoreAdditions + "\n"); ".phase-result-*",
".stage-done-*",
"PLAN.md",
];
const missingGitignoreLines = requiredGitignoreLines.filter((line) => !currentGitignore.includes(line));
if (missingGitignoreLines.length > 0) {
fs.appendFileSync(
gitignorePath,
"\n# agent-harness: build artifacts, vendored archives, and harness bookkeeping never belong in source control\n" +
missingGitignoreLines.join("\n") +
"\n"
);
await runGit(cwd, ["add", ".gitignore"]); await runGit(cwd, ["add", ".gitignore"]);
await runGit(cwd, ["commit", "-m", "chore: broaden .gitignore for agent-run artifacts"]); await runGit(cwd, ["commit", "-m", "chore: broaden .gitignore for agent-run artifacts"]);
} }
const trackedFiles = await runGit(cwd, ["ls-tree", "-r", "HEAD", "--name-only"]);
if (trackedFiles.out.split("\n").includes("PLAN.md")) {
await runGit(cwd, ["rm", "--cached", "PLAN.md"]);
await runGit(cwd, ["commit", "-m", "chore: untrack PLAN.md (already gitignored, was committed pre-rule)"]);
}
await runPhase(cwd, baseBranch, phaseBranch, phaseTasks, pool, repoId, pipelineSession); await runPhase(cwd, baseBranch, phaseBranch, phaseTasks, pool, repoId, pipelineSession);