| ... | @@ -1002,23 +1002,22 @@ describe("CheckpointReactor", () => { | ... | @@ -1002,23 +1002,22 @@ describe("CheckpointReactor", () => { |
| 1002 | expect(thread?.branch).toBe("t3code/renamed-by-agent"); | 1002 | expect(thread?.branch).toBe("t3code/renamed-by-agent"); |
| 1003 | }); | 1003 | }); |
| 1004 | | 1004 | |
| 1005 | it("does not adopt a drifted checkout when the worktree is shared by another thread", async () => { | 1005 | it("follows a checkout from a saved placeholder branch and refreshes its pull request", async () => { |
| 1006 | const pullRequestRefreshCalls: string[] = []; | 1006 | const pullRequestRefreshCalls: string[] = []; |
| 1007 | const harness = await createHarness({ | 1007 | const harness = await createHarness({ |
| 1008 | seedFilesystemCheckpoints: false, | 1008 | seedFilesystemCheckpoints: false, |
| 1009 | threadBranch: "t3code/original-branch", | 1009 | threadBranch: "t3code/fd9cbe0e", |
| 1010 | localStatusRefName: "t3code/renamed-by-agent", | 1010 | localStatusRefName: "fix/mobile-tool-detail-expansion", |
| 1011 | secondThreadSharingWorktree: true, | | |
| 1012 | pullRequestRefreshCalls, | 1011 | pullRequestRefreshCalls, |
| 1013 | }); | 1012 | }); |
| 1014 | | 1013 | |
| 1015 | harness.provider.emit({ | 1014 | harness.provider.emit({ |
| 1016 | type: "turn.completed", | 1015 | type: "turn.completed", |
| 1017 | eventId: EventId.make("evt-turn-completed-branch-drift-shared"), | 1016 | eventId: EventId.make("evt-turn-completed-placeholder-drift"), |
| 1018 | provider: ProviderDriverKind.make("codex"), | 1017 | provider: ProviderDriverKind.make("codex"), |
| 1019 | createdAt: "2026-01-01T00:00:00.000Z", | 1018 | createdAt: "2026-01-01T00:00:00.000Z", |
| 1020 | threadId: ThreadId.make("thread-1"), | 1019 | threadId: ThreadId.make("thread-1"), |
| 1021 | turnId: asTurnId("turn-branch-drift-shared"), | 1020 | turnId: asTurnId("turn-placeholder-drift"), |
| 1022 | payload: { state: "completed" }, | 1021 | payload: { state: "completed" }, |
| 1023 | }); | 1022 | }); |
| 1024 | | 1023 | |
| ... | @@ -1026,10 +1025,42 @@ describe("CheckpointReactor", () => { | ... | @@ -1026,10 +1025,42 @@ describe("CheckpointReactor", () => { |
| 1026 | | 1025 | |
| 1027 | const snapshot = await harness.readModel(); | 1026 | const snapshot = await harness.readModel(); |
| 1028 | const thread = snapshot.threads.find((entry) => entry.id === ThreadId.make("thread-1")); | 1027 | const thread = snapshot.threads.find((entry) => entry.id === ThreadId.make("thread-1")); |
| 1029 | expect(thread?.branch).toBe("t3code/original-branch"); | 1028 | expect(thread?.branch).toBe("fix/mobile-tool-detail-expansion"); |
| 1030 | expect(pullRequestRefreshCalls).toEqual([]); | 1029 | expect(thread?.worktreePath).toBe(harness.cwd); |
| | 1030 | expect(pullRequestRefreshCalls).toEqual([harness.cwd]); |
| 1031 | }); | 1031 | }); |
| 1032 | | 1032 | |
| | 1033 | it.each(["t3code/original-branch", "t3code/fd9cbe0e"])( |
| | 1034 | "does not adopt a drifted checkout from %s when the worktree is shared by another thread", |
| | 1035 | async (threadBranch) => { |
| | 1036 | const pullRequestRefreshCalls: string[] = []; |
| | 1037 | const harness = await createHarness({ |
| | 1038 | seedFilesystemCheckpoints: false, |
| | 1039 | threadBranch, |
| | 1040 | localStatusRefName: "t3code/renamed-by-agent", |
| | 1041 | secondThreadSharingWorktree: true, |
| | 1042 | pullRequestRefreshCalls, |
| | 1043 | }); |
| | 1044 | |
| | 1045 | harness.provider.emit({ |
| | 1046 | type: "turn.completed", |
| | 1047 | eventId: EventId.make("evt-turn-completed-branch-drift-shared"), |
| | 1048 | provider: ProviderDriverKind.make("codex"), |
| | 1049 | createdAt: "2026-01-01T00:00:00.000Z", |
| | 1050 | threadId: ThreadId.make("thread-1"), |
| | 1051 | turnId: asTurnId("turn-branch-drift-shared"), |
| | 1052 | payload: { state: "completed" }, |
| | 1053 | }); |
| | 1054 | |
| | 1055 | await harness.drain(); |
| | 1056 | |
| | 1057 | const snapshot = await harness.readModel(); |
| | 1058 | const thread = snapshot.threads.find((entry) => entry.id === ThreadId.make("thread-1")); |
| | 1059 | expect(thread?.branch).toBe(threadBranch); |
| | 1060 | expect(pullRequestRefreshCalls).toEqual([]); |
| | 1061 | }, |
| | 1062 | ); |
| | 1063 | |
| 1033 | it("does not adopt a temporary placeholder checkout as the thread branch", async () => { | 1064 | it("does not adopt a temporary placeholder checkout as the thread branch", async () => { |
| 1034 | const harness = await createHarness({ | 1065 | const harness = await createHarness({ |
| 1035 | seedFilesystemCheckpoints: false, | 1066 | seedFilesystemCheckpoints: false, |