Skip to content
This repository was archived by the owner on Aug 6, 2026. It is now read-only.

Commit e59be41

Browse files
fix(archive): tolerate task pin sync failures (#3980)
1 parent 9ad6664 commit e59be41

2 files changed

Lines changed: 54 additions & 4 deletions

File tree

packages/core/src/archive/archiveOrchestration.test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,39 @@ describe("archiveTask", () => {
113113
expect(harness.deps.togglePin).toHaveBeenCalledWith(TASK_ID);
114114
});
115115

116+
it("archives when reading task pins fails", async () => {
117+
harness.deps.getPinnedTaskIds = vi
118+
.fn()
119+
.mockRejectedValue(new Error("pins unavailable"));
120+
121+
await archiveTask(TASK_ID, harness.deps);
122+
123+
expect(harness.deps.archive).toHaveBeenCalledWith(TASK_ID);
124+
});
125+
126+
it("preserves pin state when reading task pins and archiving fail", async () => {
127+
harness.deps.getPinnedTaskIds = vi
128+
.fn()
129+
.mockRejectedValue(new Error("pins unavailable"));
130+
harness.deps.archive = vi.fn().mockRejectedValue(new Error("boom"));
131+
132+
await expect(archiveTask(TASK_ID, harness.deps)).rejects.toThrow("boom");
133+
134+
expect(harness.deps.unpin).not.toHaveBeenCalled();
135+
expect(harness.deps.togglePin).not.toHaveBeenCalled();
136+
});
137+
138+
it("archives when unpinning fails", async () => {
139+
harness.deps.getPinnedTaskIds = vi.fn().mockResolvedValue([TASK_ID]);
140+
harness.deps.unpin = vi
141+
.fn()
142+
.mockRejectedValue(new Error("pins unavailable"));
143+
144+
await archiveTask(TASK_ID, harness.deps);
145+
146+
expect(harness.deps.archive).toHaveBeenCalledWith(TASK_ID);
147+
});
148+
116149
it("destroys terminals only after the archive succeeds", async () => {
117150
let clearedWhenArchiveCalled = true;
118151
harness.deps.archive = vi.fn().mockImplementation(async () => {

packages/core/src/archive/archiveOrchestration.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,26 @@ export async function archiveTask(
6767
}
6868

6969
const optimistic = options?.optimistic ?? true;
70-
const pinnedTaskIds = await deps.getPinnedTaskIds();
71-
const wasPinned = pinnedTaskIds.includes(taskId);
70+
let wasPinned: boolean | undefined;
71+
try {
72+
wasPinned = (await deps.getPinnedTaskIds()).includes(taskId);
73+
} catch (error) {
74+
deps.logError("Failed to read task pin state while archiving", error);
75+
}
7276

7377
if (!options?.skipNavigate) {
7478
deps.navigateAwayFromTaskIfActive(taskId);
7579
}
7680

7781
const commandCenterSnapshot = deps.snapshotCommandCenter(taskId);
7882

79-
await deps.unpin(taskId);
83+
if (wasPinned) {
84+
try {
85+
await deps.unpin(taskId);
86+
} catch (error) {
87+
deps.logError("Failed to unpin task while archiving", error);
88+
}
89+
}
8090
deps.removeFromCommandCenter(taskId);
8191

8292
await deps.cache.cancelPathFilter();
@@ -118,7 +128,14 @@ export async function archiveTask(
118128
deps.cache.setArchivedTaskIds((old) => removeArchivedTaskId(old, taskId));
119129
deps.cache.setArchiveList((old) => removeArchivedTask(old, taskId));
120130
if (wasPinned) {
121-
await deps.togglePin(taskId);
131+
try {
132+
await deps.togglePin(taskId);
133+
} catch (pinError) {
134+
deps.logError(
135+
"Failed to restore task pin after archive failure",
136+
pinError,
137+
);
138+
}
122139
}
123140
if (commandCenterSnapshot.index !== -1) {
124141
deps.restoreCommandCenter(taskId, commandCenterSnapshot);

0 commit comments

Comments
 (0)