Skip to content

fix(desktop): Path mismatches cause sessions missing + strong ID + existing data fix#25013

Merged
Hona merged 5 commits intoanomalyco:devfrom
Hona:fix/defensive-path-sessions
Apr 29, 2026
Merged

fix(desktop): Path mismatches cause sessions missing + strong ID + existing data fix#25013
Hona merged 5 commits intoanomalyco:devfrom
Hona:fix/defensive-path-sessions

Conversation

@Hona
Copy link
Copy Markdown
Member

@Hona Hona commented Apr 29, 2026

No description provided.

@Hona Hona requested a review from adamdotdevin as a code owner April 29, 2026 21:51
Copilot AI review requested due to automatic review settings April 29, 2026 21:51
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to eliminate directory/path normalization mismatches (especially Windows \ vs / and root/trailing-slash cases) that can cause persisted workspace/session state and global-sync child stores to “miss” existing data, by introducing a canonical directory key and adding migration fallbacks for legacy storage locations.

Changes:

  • Added pathKey() (and directoryKey re-export) as the canonical directory normalization function and replaced workspaceKey() usages across layout/global-sync codepaths.
  • Enhanced persistence to support migrating values across legacy storage names (e.g., old workspace storage filenames derived from raw paths).
  • Added/updated tests to cover the new normalization rules and legacy workspace storage fallback behavior.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/app/src/utils/persist.ts Adds legacyStorage support and refactors legacy/current read/migrate logic.
packages/app/src/utils/persist.test.ts Adds test asserting workspace persistence target includes legacy raw-path storage fallback.
packages/app/src/utils/path-key.ts Introduces normalized path key function used as canonical directory identifier.
packages/app/src/pages/layout/sidebar-workspace.tsx Switches active-workspace comparison from workspaceKey to pathKey.
packages/app/src/pages/layout/helpers.ts Removes workspaceKey and replaces comparisons/order logic with pathKey.
packages/app/src/pages/layout/helpers.test.ts Updates tests for normalization/root handling using pathKey.
packages/app/src/pages/layout.tsx Replaces many workspace comparisons and map keys with pathKey.
packages/app/src/context/global-sync/utils.ts Re-exports pathKey as directoryKey + branded type alias.
packages/app/src/context/global-sync/utils.test.ts Adds tests for directoryKey normalization and root/trailing-slash behavior.
packages/app/src/context/global-sync/child-store.ts Keys child stores/caches by normalized DirectoryKey and uses it through bootstrap/query paths.
packages/app/src/context/global-sync.tsx Shifts boot/load/dispose bookkeeping and SDK client creation toward normalized DirectoryKey usage.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


return null
const value = readCurrent({ storage: current, key, defaults, migrate: config.migrate })
if (value !== undefined) return value
Comment on lines 137 to 163
function ensureChild(key: DirectoryKey) {
if (!key) console.error("No directory provided")
if (!children[key]) {
const vcs = runWithOwner(input.owner, () =>
persisted(
Persist.workspace(directory, "vcs", ["vcs.v1"]),
Persist.workspace(key, "vcs", ["vcs.v1"]),
createStore({ value: undefined as VcsInfo | undefined }),
),
)
if (!vcs) throw new Error(input.translate("error.childStore.persistedCacheCreateFailed"))
const vcsStore = vcs[0]
vcsCache.set(directory, { store: vcsStore, setStore: vcs[1], ready: vcs[3] })
vcsCache.set(key, { store: vcsStore, setStore: vcs[1], ready: vcs[3] })

const meta = runWithOwner(input.owner, () =>
persisted(
Persist.workspace(directory, "project", ["project.v1"]),
Persist.workspace(key, "project", ["project.v1"]),
createStore({ value: undefined as ProjectMeta | undefined }),
),
)
if (!meta) throw new Error(input.translate("error.childStore.persistedProjectMetadataCreateFailed"))
metaCache.set(directory, { store: meta[0], setStore: meta[1], ready: meta[3] })
metaCache.set(key, { store: meta[0], setStore: meta[1], ready: meta[3] })

const icon = runWithOwner(input.owner, () =>
persisted(
Persist.workspace(directory, "icon", ["icon.v1"]),
Persist.workspace(key, "icon", ["icon.v1"]),
createStore({ value: undefined as string | undefined }),
),
Comment on lines 502 to 505
const current = currentStorage as SyncStorage
const legacyStore = legacyStorage as SyncStorage
const legacyStores = legacyStorageNames.map(localStorageWithPrefix)

@Hona Hona enabled auto-merge (squash) April 29, 2026 22:32
@Hona Hona merged commit d7b7be1 into anomalyco:dev Apr 29, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants