diff --git a/src/renderer/src/store/slices/repos-refresh-identity.test.ts b/src/renderer/src/store/slices/repos-refresh-identity.test.ts index cac63ee0024..ecbb8c893bd 100644 --- a/src/renderer/src/store/slices/repos-refresh-identity.test.ts +++ b/src/renderer/src/store/slices/repos-refresh-identity.test.ts @@ -305,13 +305,18 @@ describe('SSH readoption catalog identity', () => { it('keeps projects and host setups across a no-op recordSshRepoReadoptions([])', async () => { const store = createTestStore() await store.getState().fetchRepos() - const projects = store.getState().projects - const setups = store.getState().projectHostSetups + const before = store.getState() + const projects = before.projects + const setups = before.projectHostSetups expect(projects).toHaveLength(1) expect(setups).toHaveLength(1) store.getState().recordSshRepoReadoptions([]) + // Why: the empty-in/empty-pending call must hand the state object back untouched, or the + // freshly allocated pendingSshRepoReadoptions alone would wake every store subscriber. + expect(store.getState()).toBe(before) + expect(store.getState().pendingSshRepoReadoptions).toBe(before.pendingSshRepoReadoptions) expect(store.getState().projects).toBe(projects) expect(store.getState().projects[0]).toBe(projects[0]) expect(store.getState().projectHostSetups).toBe(setups) diff --git a/src/renderer/src/store/slices/repos.ts b/src/renderer/src/store/slices/repos.ts index fd96ad3e572..df3cef3d7e6 100644 --- a/src/renderer/src/store/slices/repos.ts +++ b/src/renderer/src/store/slices/repos.ts @@ -2025,7 +2025,9 @@ export const createRepoSlice: StateCreator = (set, ) // Why: mergeProjectHostSetupCompatibility always allocates; a no-op readoption // must not churn catalog identity. This write is all-repos, not host-scoped, - // so it cannot go through mergeFetchedProjectCompatibilityForHost. + // so it cannot go through mergeFetchedProjectCompatibilityForHost. Reconcile + // hands the store arrays straight back when nothing moved, so writing them + // unconditionally still leaves identity-keyed selectors untouched. const projects = reconcileCatalogRows( s.projects, compatibility.projects, @@ -2040,10 +2042,8 @@ export const createRepoSlice: StateCreator = (set, repos, pendingSshRepoReadoptions: reconciliation.pendingReadoptions, ...worktreeState, - ...(catalogRowsUnchanged(projects, s.projects) ? {} : { projects }), - ...(catalogRowsUnchanged(projectHostSetups, s.projectHostSetups) - ? {} - : { projectHostSetups }) + projects, + projectHostSetups } }),