@@ -373,32 +373,10 @@ function findWorktreeForBranch(
373373 return null ;
374374}
375375
376- /** Find any existing symphony loop worktree for a repo (reuse across loops). */
377- function findExistingLoopWorktree (
378- expandedRepoPath : string
379- ) : string | null {
380- try {
381- const output = execSync ( "git worktree list --porcelain" , {
382- cwd : expandedRepoPath ,
383- encoding : "utf-8" ,
384- stdio : "pipe" ,
385- timeout : 10_000 ,
386- } ) ;
387-
388- let currentWorktree : string | null = null ;
389- for ( const line of output . split ( "\n" ) ) {
390- if ( line . startsWith ( "worktree " ) ) {
391- currentWorktree = line . slice ( "worktree " . length ) ;
392- }
393- if ( line . startsWith ( "branch " ) && line . includes ( "/symphony/loop-" ) ) {
394- return currentWorktree ;
395- }
396- }
397- } catch {
398- // fall through
399- }
400- return null ;
401- }
376+ // findExistingLoopWorktree was removed — it greedy-matched ANY loop worktree
377+ // from ANY prior loop, causing new PLAN loops to reuse stale worktrees.
378+ // PLAN always creates a fresh worktree. EXECUTE/REQUEST_CHANGES reuse via
379+ // findWorktreeForBranch(parentBranchName) which matches the specific parent.
402380
403381// ---------------------------------------------------------------------------
404382// Per-command artifact writing
@@ -918,30 +896,17 @@ async function handleLoopRequest(
918896 } ) ;
919897 return ;
920898 } else if ( body . command === "PLAN" ) {
921- // PLAN: reuse existing symphony loop worktree if available, else create new
922- worktreeDir = findExistingLoopWorktree ( expandedRepoPath ) ;
923- if ( worktreeDir ) {
924- loopLog ( body . loopId , `Reusing existing loop worktree: ${ worktreeDir } ` ) ;
925- try {
926- assertPathAllowed ( worktreeDir , allowedDirs ) ;
927- } catch ( e ) {
928- if ( e instanceof DirectoryNotAllowedError ) {
929- json ( context , 403 , { error : `Worktree path not allowed: ${ worktreeDir } ` } ) ;
930- return ;
931- }
932- throw e ;
933- }
934- } else {
935- const loopBranch = `symphony/loop-${ pickStableId ( body ) } ` ;
936- worktreeDir = resolveLoopWorktreeDir ( expandedRepoPath , pickStableId ( body ) ) ;
937- await ensureWorktree (
938- expandedRepoPath ,
939- worktreeDir ,
940- loopBranch ,
941- body . repo ?. branch ?? "main"
942- ) ;
943- loopLog ( body . loopId , `Created new loop worktree: ${ worktreeDir } ` ) ;
944- }
899+ // PLAN: always create a fresh worktree (matches ECS harness which always clones fresh).
900+ // No reuse — each PLAN loop gets its own worktree keyed by loopId.
901+ const loopBranch = `symphony/loop-${ pickStableId ( body ) } ` ;
902+ worktreeDir = resolveLoopWorktreeDir ( expandedRepoPath , pickStableId ( body ) ) ;
903+ await ensureWorktree (
904+ expandedRepoPath ,
905+ worktreeDir ,
906+ loopBranch ,
907+ body . repo ?. branch ?? "main"
908+ ) ;
909+ loopLog ( body . loopId , `Created loop worktree: ${ worktreeDir } ` ) ;
945910 claudeWorkDir = path . join ( worktreeDir , ".claude" , "work" ) ;
946911 await fs . mkdir ( claudeWorkDir , { recursive : true } ) ;
947912 await writeArtifactsForPlan ( claudeWorkDir , body . artifacts , body . prompt ) ;
0 commit comments