fix(memory): verify qmd conflict before rebind

This commit is contained in:
Ted Li
2026-04-26 19:46:26 -07:00
committed by Peter Steinberger
parent e422bcfc2a
commit 49db1908f3
2 changed files with 22 additions and 6 deletions

View File

@@ -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"),
);
});

View File

@@ -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;