Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions connectors/gmail/src/gmail.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,28 @@ describe("processEmailThreads — no status set", () => {
expect(saved.unread).toBeUndefined();
});
});

describe("star -> to-do write-back (no skip_todo_writeback echo guard)", () => {
it("calls setThreadToDo and never writes a skip_todo_writeback key", async () => {
const { gmail } = makeGmail();
const store = (gmail as any).tools.store;
const integrations = (gmail as any).tools.integrations;
await store.set("auth_actor_id", "actor-1");
const thread = makeGmailThread(["INBOX", "STARRED"]);

await (gmail as any).processEmailThreads([thread], false, "INBOX");

expect(integrations.setThreadToDo).toHaveBeenCalledWith(
"https://mail.google.com/mail/u/0/#inbox/thread-archived",
"actor-1",
true
);
expect(store.set).not.toHaveBeenCalledWith(
expect.stringContaining("skip_todo_writeback"),
expect.anything()
);
});
});
});

describe("recoverMailboxDelivery — durable recovery on upgrade", () => {
Expand Down Expand Up @@ -656,4 +678,18 @@ describe("thread-state write-back when the connection has no auth token", () =>
});
fetchSpy.mockRestore();
});

it("onThreadToDo writes back even if a stale skip_todo_writeback key is present", async () => {
const { gmail } = makeGmail({ token: "tok", scopes: [] });
const store = (gmail as any).tools.store;
await store.set(`skip_todo_writeback:gmail-thread-1`, true);
const fetchSpy = vi
.spyOn(globalThis, "fetch")
.mockResolvedValue(new Response("{}"));

await gmail.onThreadToDo(thread, actor, true, {});

expect(fetchSpy).toHaveBeenCalledTimes(1);
fetchSpy.mockRestore();
});
});
8 changes: 0 additions & 8 deletions connectors/gmail/src/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1430,8 +1430,6 @@ export async function processEmailThreadsFn(
actorId,
isStarred
);
// Prevent the onThreadToDo callback from echoing back
await host.set(`skip_todo_writeback:${thread.id}`, true);
}
await host.set(`starred:${thread.id}`, isStarred);
}
Expand Down Expand Up @@ -1695,12 +1693,6 @@ export async function onThreadToDoFn(
const channelId = (meta.channelId ?? meta.syncableId) as string;
if (!threadId || !channelId) return;

// Loop prevention: skip if this change originated from Gmail star sync
if (await host.get(`skip_todo_writeback:${threadId}`)) {
await host.clear(`skip_todo_writeback:${threadId}`);
return;
}

// Best-effort: if the connection lost its Google auth, skip the star
// write-back instead of throwing (the to-do change already lives in Plot).
// Resolved before the local-state mutation below so a no-token call is a
Expand Down
Loading