Repository navigation
fix(sync): keep the import history across logout and import in linear time - #324
Merged
Merged
Conversation
mohamede1945
added this pull request to stack #326
October 14, 2026 14:05
Logout cleared the import history with the user's data. A tracked legacy import run after logout then brought back items the user had deleted while signed in, and the next login pushed them as new creates (S14, IMP-10). The history records what this device's legacy data already brought in, which a logout doesn't change, so the reset now keeps it, like the key-value store. Tying it to the account would not help: an import after logout runs with no account and merges into whichever account signs in next. Keeping it also stops a re-import from adding legacy data to another account. The iOS app disables legacy import at logout, so it never relies on the cleared history. - PersistenceResetRepositoryImpl is the engine's wipe alone and no longer takes the app database; clearImportHistory is gone. - IMP-10 passes without its knownIssue; a variant checks that a re-import after logout brings nothing into another account. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two lookups made an import quadratic in its size: - The note creation-time nudge asked the database once per note, and its query reads every note at or after the asked time. Notes imported newest first, or sharing one time, rescanned the whole run each time: 20,000 notes with one creation time took about 15 s. The importer now nudges through NoteStore.batch(), which reads the taken times once and skips each run of taken milliseconds after walking it (CreationTimes), with the same result as a single insert. The app's single inserts keep the query. - The collections a verse is in (collectionAyahsAt) had no index, so each imported membership and highlight scanned every saved verse. collection_ayah now has an index on (sura, ayah). The schema stays at version 2, which is unreleased. 20,000 memberships import in about 0.5 s instead of 3 s, and 20,000 notes in 0.3 s. Tests: a batch matches single inserts on random times, the verse lookup's query plan uses the index, and a JVM test bounds the time of a 20,000-note import (both fail without the change). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The reset clears the outbox and the item failures with the bases, the token and the account, and a sync that started before it can no longer write: its generation is superseded, so neither a downloaded note nor the token lands. - An import writes domain rows only. Logged in, it leaves the token, the account, the epoch and the bases as they were, so a restore's deletes still reach the server; logged out, it writes no sync state, so it can never leave the token without an account that makes the engine wipe. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d restores - LIFE-08 variant: a logout while the GET is held. Nothing the GET carries lands, nothing is pushed, and a re-login converges. - IMP-11: a tracked import made while a POST is held is pushed by the next sync, next to what the held POST carried. - IMP-04 pins what a restore with deleteExisting pushes: a DELETE for every synced item and a CREATE for every backup item, the note in both sets included (S14's restore note). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The logged-out import test now asserts that no sync type has a sync row and that the epoch is unchanged, not just the NOTE rows. - The LIFE-08 variant's comment says what it proves: the logout cancels the held GET, so nothing it carries lands and nothing is pushed. The epoch guard against an answered GET is covered by the persistence reset test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drop the S-issue tags from the reset repository and the import scenarios, and the bare [NoteStore.insert] KDoc on Batch.insert, which batch()'s KDoc already covers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mohamede1945
force-pushed
the
feat/sync-v2-importer
branch
from
October 14, 2026 15:36
a4dcdd2 to
48724c6
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Moves the importer and reset onto the new engine, and fixes S14: logout no longer clears the import history.
S14: keep the import history across logout
deleteAllDataclearedimport_history. A tracked re-import after logout could then bring back legacy items the user had deleted while signed in, and push them as new creates on the next login (IMP-10).LegacyDataImportCoordinatorimports withtrackHistory = trueon the 3.1.0 upgrade, on every launch and on every CloudKit change.logoutFromQuranCom()callsdisable()before logging out, which turns legacy import off permanently.Import performance
NoteStore.batch()/CreationTimes). 20,000 notes sharing one time take about 0.3 s, down from about 15 s, and pick the same times as single inserts.collection_ayah(sura, ayah): 20,000 memberships or highlights import in about 0.5 s, down from about 3 s.Reset and sync state (pinned by tests)
sync_item/sync_meta(token, account, outbox, failures) and an epoch bump. A sync that started before the reset can't commit afterwards.deleteExisting) pushes.Tests
./gradlew allTests --continuepasses on every module and target:Noteranges model, step 5) remains as aknownIssue.API
deleteAllData()no longer clears the import history; the README now says so.PersistenceResetRepositoryImpltakes onlySyncV2Database. It's internal to DI and hidden from ObjC.🤖 Generated with Claude Code
Cleanup (rebased 2026-10-14)