Skip to content

fix(sync): push local-only legacy pages after noteId migration (#1020) - #1024

Closed
cursor[bot] wants to merge 2 commits into
developfrom
cursor/critical-bug-investigation-a486
Closed

fix(sync): push local-only legacy pages after noteId migration (#1020)#1024
cursor[bot] wants to merge 2 commits into
developfrom
cursor/critical-bug-investigation-a486

Conversation

@cursor

@cursor cursor Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Bug and impact

On first sync after the Issue #1020 migration, syncWithApi could skip pushing local-only pages to the server.

Trigger scenario: A user upgrades to the #1020 client with legacy IndexedDB rows still stored as noteId: null (old personal pages). On initial sync:

  1. getAllPages() returns [] because null noteId rows are filtered out pre-migration.
  2. localPageCount === 0 causes finishSyncIfNoPushNeeded to skip the push phase entirely.
  3. reassignNullNotePages runs during pull and assigns a default note, making pages visible locally.
  4. Those pages were never on the server and are never pushed — silent data loss if the user clears browser storage or switches devices.

Root cause

finishSyncIfNoPushNeeded used the pre-pull localPageCount, which no longer reflects reality once #1020 hides legacy noteId: null rows from getAllPages() until reassignNullNotePages runs inside applyPull.

Fix

Only skip push on initial sync when every page in pagesForPush was just received from the server (redundant echo). If local-only pages exist after migration, push proceeds normally.

Validation

  • Added regression test: pushes local-only legacy pages after migration when pre-pull count was zero (issue #1020)
  • Updated existing initial-sync skip test to model post-pull state correctly
  • bunx vitest run src/lib/sync/syncWithApi.test.ts — 22/22 passed

Related: #1023 / #1020

Open in Web View Automation 

claude and others added 2 commits June 10, 2026 06:46
…n-null 化 (#1020)

- server: GET /api/sync/pages の各ページ行に note_id を追加し、トップレベルに
  default_note_id を返す(クライアントのレガシー null 行移行用)
- front(sync): pull 適用前に reassignNullNotePages で既存の noteId:null 行を
  デフォルトノートへ付け替え。push はデフォルトノート配下のみに限定
- front(IndexedDB): PageMetadata.noteId を string に tighten。未移行の
  レガシー null 行は読み出しから除外し、同期時に自動移行
- front(types): Page.noteId / PageSummary.noteId を string(non-null)へ再 tighten
  し、#1011 で追加した消費側 null ガード・null 分岐を撤去
- ゲストのローカルページ作成を廃止(#889 以降 /notes/null/:pageId に遷移して
  実質機能していなかった)。createPageLocal / pageStore を削除し、FAB は
  未サインイン時に非表示
- WikiLink ホバープレビューを pageStore からリポジトリ(IndexedDB)ベースの
  usePageByTitle / useGhostLinkReferenced に置き換え
- 検索結果の「共有」バッジは noteId の有無ではなく結果ソースで判定
- 呼び出し元のない importPersonalPageFromApi(note_id != null を拒否する
  ガード)を削除

[skip drizzle-check] サーバはルート実装のみの変更で、スキーマ変更なし

Closes #1020

https://claude.ai/code/session_01FH8KekbbgxZxsw5LLknKCQ
Initial sync skipped push when pre-pull localPageCount was zero, but
legacy noteId:null rows are hidden from getAllPages until reassignNullNotePages
runs in applyPull. That could leave offline-only pages never uploaded.

Only skip push on initial sync when every page slated for push was just
pulled from the server (redundant echo), not when local-only rows exist.
@otomatty

Copy link
Copy Markdown
Owner

sync 修正のみ develop 最新ベースで cherry-pick した focused PR #1061 に移行します。本 PR(Draft + コンフリクト + 無関係な大規模 refactor 含む)はクローズします。

@otomatty otomatty closed this Jun 13, 2026
@otomatty
otomatty deleted the cursor/critical-bug-investigation-a486 branch June 13, 2026 14:26
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.

3 participants