fix(engine): harden worktree lifecycle and seed frontend UX criteria
Atomic worktree creation: on `git worktree add` failure, remove the partial directory so retries see a clean slate (executor.ts, step-session-executor.ts). Add `reapOrphanWorktrees()` sweep on engine startup to delete `.worktrees/*` dirs that have no `.git` file and are not registered with git. Force readonly workflow steps to run pre-merge so review personas reuse the coding worktree instead of allocating a fresh post-merge one. Inject a Frontend UX Criteria checklist into TRIAGE_SYSTEM_PROMPT when a task touches dashboard UI, so the first coding pass can meet UX reviewer expectations. Motivated by FN-2185 post-mortem: an incomplete `.worktrees/pale-raven` dir blocked retries, and three Step 6 revision cycles over cosmetic UX issues consumed ~13 hours. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -171,10 +171,28 @@ export class InProcessRuntime
|
||||
runtimeLog.log(`PluginRunner initialized`);
|
||||
|
||||
// 3. Initialize WorktreePool
|
||||
|
||||
// Reap half-initialized orphan worktree directories before doing anything
|
||||
// else with the pool. These are directories under .worktrees/ that exist
|
||||
// on disk but were never fully registered with git (e.g. the process was
|
||||
// killed between `mkdir` and `git worktree add`). Removing them here
|
||||
// ensures scanIdleWorktrees / rehydrate never sees broken entries, and
|
||||
// prevents assertValidWorktreeSession from permanently blocking retries.
|
||||
const { reapOrphanWorktrees, scanIdleWorktrees } = await import("../worktree-pool.js");
|
||||
try {
|
||||
const reaped = await reapOrphanWorktrees(this.config.workingDirectory);
|
||||
if (reaped > 0) {
|
||||
runtimeLog.log(`Reaped ${reaped} half-initialized orphan worktree(s) on startup`);
|
||||
}
|
||||
} catch (err: unknown) {
|
||||
// Non-fatal — log and continue; a missed orphan is better than a failed start.
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
runtimeLog.warn(`reapOrphanWorktrees failed (continuing): ${msg}`);
|
||||
}
|
||||
|
||||
this.worktreePool = new WorktreePool();
|
||||
|
||||
// Rehydrate pool from disk state (idle worktrees)
|
||||
const { scanIdleWorktrees } = await import("../worktree-pool.js");
|
||||
const idleWorktrees = await scanIdleWorktrees(
|
||||
this.config.workingDirectory,
|
||||
this.taskStore
|
||||
|
||||
Reference in New Issue
Block a user