From 5dae6e5d87f5549b6eced8053f8c88835a8096a2 Mon Sep 17 00:00:00 2001 From: Mikyferry Date: Thu, 9 Jul 2026 21:58:04 +0200 Subject: [PATCH 1/2] fix(web): prevent duplicate main branch on concurrent version-control init Multiple components initialize version control on mount; share a single in-flight init promise per project and recover gracefully if a concurrent init already created the main branch. Co-Authored-By: Claude Fable 5 --- apps/web/src/core/managers/version-manager.ts | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/apps/web/src/core/managers/version-manager.ts b/apps/web/src/core/managers/version-manager.ts index 7c677c98d8..ada2ca7390 100644 --- a/apps/web/src/core/managers/version-manager.ts +++ b/apps/web/src/core/managers/version-manager.ts @@ -26,6 +26,8 @@ export class VersionManager { private lastCommitId: string | null = null; private dirty = false; private initialized = false; + private initPromise: Promise | null = null; + private initProjectId: string | null = null; private unsubscribeHandlers: Array<() => void> = []; // Auto-commit @@ -47,6 +49,21 @@ export class VersionManager { * Creates the version DB, main branch, and initial commit if needed. */ async initialize(projectId: string): Promise { + // Multiple components initialize version control on mount; share one + // in-flight init per project so concurrent calls can't both create "main" + if (this.initPromise && this.initProjectId === projectId) { + return this.initPromise; + } + this.initProjectId = projectId; + this.initPromise = this.doInitialize(projectId).catch((err) => { + this.initPromise = null; + this.initProjectId = null; + throw err; + }); + return this.initPromise; + } + + private async doInitialize(projectId: string): Promise { this.storage = new VersionStorage(projectId); const mainBranch = await this.storage.getBranchByName("main"); @@ -116,7 +133,17 @@ export class VersionManager { }; await this.storage.saveCommit(commit); - await this.storage.saveBranch(branch); + try { + await this.storage.saveBranch(branch); + } catch (err) { + // A concurrent init already created "main" (unique by-name index) — reuse it + const existing = await this.storage.getBranchByName("main"); + if (!existing) throw err; + this.currentBranchName = "main"; + this.lastCommitId = existing.headCommitId; + await this.storage.setMeta("currentBranch", "main"); + return; + } await this.storage.setMeta("currentBranch", "main"); this.currentBranchName = "main"; From 61a1ccba8769214fbc553bc1373b7853570c4d01 Mon Sep 17 00:00:00 2001 From: Mikyferry Date: Thu, 9 Jul 2026 21:58:04 +0200 Subject: [PATCH 2/2] fix(ai-backend): add missing Field import in engagement routes Co-Authored-By: Claude Fable 5 --- services/ai-backend/app/routes/engagement.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/ai-backend/app/routes/engagement.py b/services/ai-backend/app/routes/engagement.py index 5666bcda9d..22d0e79406 100644 --- a/services/ai-backend/app/routes/engagement.py +++ b/services/ai-backend/app/routes/engagement.py @@ -9,7 +9,7 @@ import uuid from fastapi import APIRouter, File, Form, HTTPException, UploadFile -from pydantic import BaseModel +from pydantic import BaseModel, Field from app.config import settings from app.models.engagement import (