Merge branch 'main' into cw/continuous-code-quality-conflict-1772832123778

# Conflicts:
#	apps/server/drizzle/meta/0037_snapshot.json
#	apps/server/drizzle/meta/_journal.json
This commit is contained in:
Lukas May
2026-03-06 22:30:21 +01:00
39 changed files with 5291 additions and 419 deletions

View File

@@ -21,7 +21,7 @@ import type { AgentRepository } from '../db/repositories/agent-repository.js';
import type { AgentManager } from '../agent/types.js';
import type { DispatchManager, PhaseDispatchManager } from '../dispatch/types.js';
import type { ConflictResolutionService } from '../coordination/conflict-resolution-service.js';
import { phaseBranchName, taskBranchName } from '../git/branch-naming.js';
import { phaseBranchName, taskBranchName, isPlanningCategory } from '../git/branch-naming.js';
import { ensureProjectClone } from '../git/project-clones.js';
import { createModuleLogger } from '../logger/index.js';
import { phaseMetaCache, fileDiffCache } from '../review/diff-cache.js';
@@ -708,6 +708,23 @@ export class ExecutionOrchestrator {
}
}
// Clean up stale duplicate planning tasks (e.g. a crashed detail task
// that was reset to pending, then a new detail task was created and completed).
const tasksAfterRecovery = await this.taskRepository.findByPhaseId(phase.id);
const completedPlanningNames = new Set<string>();
for (const t of tasksAfterRecovery) {
if (isPlanningCategory(t.category) && t.status === 'completed') {
completedPlanningNames.add(`${t.category}:${t.phaseId}`);
}
}
for (const t of tasksAfterRecovery) {
if (isPlanningCategory(t.category) && t.status === 'pending' && completedPlanningNames.has(`${t.category}:${t.phaseId}`)) {
await this.taskRepository.update(t.id, { status: 'completed', summary: 'Superseded by retry' });
tasksRecovered++;
log.info({ taskId: t.id, category: t.category }, 'recovered stale duplicate planning task');
}
}
// Re-read tasks after recovery updates and check if phase is now fully done
const updatedTasks = await this.taskRepository.findByPhaseId(phase.id);
const allDone = updatedTasks.every((t) => t.status === 'completed');