perf(renderer): drop redundant catalogRowsUnchanged after reconcile

reconcileCatalogRows already hands back the previous array when nothing
moved, so the extra element-wise compare could never disagree. Pin the
empty-readoption early return with a whole-state identity assertion,
which is the only guard the previous test could not distinguish.

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Neil
2026-08-13 00:07:17 -07:00
co-authored by Orca
parent 685ac9476e
commit f517f1afd0
2 changed files with 12 additions and 7 deletions
@@ -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)
+5 -5
View File
@@ -2025,7 +2025,9 @@ export const createRepoSlice: StateCreator<AppState, [], [], RepoSlice> = (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<AppState, [], [], RepoSlice> = (set,
repos,
pendingSshRepoReadoptions: reconciliation.pendingReadoptions,
...worktreeState,
...(catalogRowsUnchanged(projects, s.projects) ? {} : { projects }),
...(catalogRowsUnchanged(projectHostSetups, s.projectHostSetups)
? {}
: { projectHostSetups })
projects,
projectHostSetups
}
}),