diff --git a/extensions/memory-core/src/memory/qmd-manager.test.ts b/extensions/memory-core/src/memory/qmd-manager.test.ts index bd0aed2e7d7..71e098ecc4d 100644 --- a/extensions/memory-core/src/memory/qmd-manager.test.ts +++ b/extensions/memory-core/src/memory/qmd-manager.test.ts @@ -1049,7 +1049,7 @@ describe("QmdMemoryManager", () => { ); }); - it("rebinds a path-pattern conflict when qmd add reports the stale collection name", async () => { + it("refuses to rebind a stderr-only path-pattern conflict without collection metadata", async () => { cfg = { ...cfg, memory: { @@ -1111,10 +1111,10 @@ describe("QmdMemoryManager", () => { const { manager } = await createManager({ mode: "full" }); await manager.close(); - expect(removeCalls).toEqual(["workspace-legacy"]); - expect(addCalls).toEqual(["workspace-main", "workspace-main"]); - expect(logWarnMock).toHaveBeenCalledWith(expect.stringContaining("rebinding")); - expect(logWarnMock).not.toHaveBeenCalledWith( + expect(removeCalls).toEqual([]); + expect(addCalls).toEqual(["workspace-main"]); + expect(logWarnMock).not.toHaveBeenCalledWith(expect.stringContaining("rebinding")); + expect(logWarnMock).toHaveBeenCalledWith( expect.stringContaining("qmd collection add skipped for workspace-main"), ); }); diff --git a/extensions/memory-core/src/memory/qmd-manager.ts b/extensions/memory-core/src/memory/qmd-manager.ts index accfac525df..810e21b0a68 100644 --- a/extensions/memory-core/src/memory/qmd-manager.ts +++ b/extensions/memory-core/src/memory/qmd-manager.ts @@ -671,7 +671,23 @@ export class QmdMemoryManager implements MemorySearchManager { conflictName = this.findCollectionByPathPattern(collection, existing); } - conflictName ??= this.parseConflictingCollectionNameFromAddError(addErrorMessage); + if (!conflictName) { + const parsedConflictName = this.parseConflictingCollectionNameFromAddError(addErrorMessage); + const parsedDetails = parsedConflictName ? existing.get(parsedConflictName) : undefined; + if ( + parsedConflictName && + parsedDetails?.path && + typeof parsedDetails.pattern === "string" && + this.pathsMatch(parsedDetails.path, collection.path) && + this.patternsMatchForManagedCollection( + collection.path, + parsedDetails.pattern, + collection.pattern, + ) + ) { + conflictName = parsedConflictName; + } + } if (!conflictName) { return false;